当前位置: 首页 > news >正文

4.1 uboot启动第一阶段

1、初始Bootloader

Bootloader是启动计算机或嵌入式系统时执行的第一个程序,它主要负责初始化系统硬件,加载操作系统。U-Boot也是Bootloader的一种。它的作用如下:

(1)初始化硬件

(2)部署操作系统

(3)启动操作系统

(4)提供启动选项

(5)提供固件升级机制

2、U-Boot源码目录

目录名作用
api
board开发板的相关定义和结构
common包含U-Boot用到的各种处理函数
cpu各种不同类型的处理器相关的代码
docU-Boot相关文档
drivers常用外部设备的驱动
fs文件系统(cramfs、ext2、fat、fdos、jffs2、reserfs)
includeU-Boot用到的头文件
lib_armARM体系结构有关的数据定义和操作
lib_genericU-Boot通用的操作函数
libfdt设备树相关的
net常用的网络协议,包括:bootp、rarp、arp、tftp
post上电自检相关
tools工具类相关的

3、U-Boot启动的第一阶段

U-Boot的工作流程分成stage1和stage2两个阶段。

3.1 头部16字节

SD卡/Nand等方式启动需要16字节的校验头,USB启动就不需要16字节的校验头,这里是先留出16字节的大小,用于后面计算校验时填充。

#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
	.word 0x2000
	.word 0x0
	.word 0x0
	.word 0x0
#endif

3.2 设置异常向量表

.globl _start
_start: b	reset
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq

_undefined_instruction:
	.word undefined_instruction
_software_interrupt:
	.word software_interrupt
_prefetch_abort:
	.word prefetch_abort
_data_abort:
	.word data_abort
_not_used:
	.word not_used
_irq:
	.word irq
_fiq:
	.word fiq
_pad:
	.word 0x12345678 /* now 16*4=64 */

异常复位时跳转到reset

3.3 地址对齐

以当前地址开始,以16字节对齐

.global _end_vect
_end_vect:

	.balignl 16,0xdeadbeef
.balignl {alignment} {,fill} {,max}。

;alignment为正整数,以alignment整数倍地址进行对齐,以当前地址为起始地址,进行字节填充,用fill进行填充

3.4 两个地址

/* 定义在Makefile,是uboot链接时的链接地址 */
_TEXT_BASE:
	.word	TEXT_BASE

/* uboot在DDR的物理地址 */
_TEXT_PHY_BASE:
	.word	CFG_PHY_UBOOT_BASE

3.5 cpu设置为SVC模式

reset:
	/*
	 * set the cpu to SVC32 mode and IRQ & FIQ disable
	 */
	@;mrs	r0,cpsr
	@;bic	r0,r0,#0x1f
	@;orr	r0,r0,#0xd3
	@;msr	cpsr,r0
	msr	cpsr_c, #0xd3		@ I & F disable, Mode: 0x13 - SVC

3.6 cpu_init_crit

(1)设置L1Cache、L2Cache、MMU

#ifndef CONFIG_EVT1
#if 0	
	bl	v7_flush_dcache_all
#else
	bl	disable_l2cache

	mov	r0, #0x0	@ 
	mov	r1, #0x0	@ i	
	mov	r3, #0x0
	mov	r4, #0x0
lp1:
	mov	r2, #0x0	@ j
lp2:	
	mov	r3, r1, LSL #29		@ r3 = r1(i) <<29
	mov	r4, r2, LSL #6		@ r4 = r2(j) <<6
	orr	r4, r4, #0x2		@ r3 = (i<<29)|(j<<6)|(1<<1)
	orr	r3, r3, r4
	mov	r0, r3			@ r0 = r3
	bl	CoInvalidateDCacheIndex
	add	r2, #0x1		@ r2(j)++
	cmp	r2, #1024		@ r2 < 1024
	bne	lp2			@ jump to lp2
	add	r1, #0x1		@ r1(i)++
	cmp	r1, #8			@ r1(i) < 8
	bne	lp1			@ jump to lp1

	bl	set_l2cache_auxctrl
	
	bl	enable_l2cache
#endif
#endif
	
	bl	disable_l2cache

	bl	set_l2cache_auxctrl_cycle

	bl	enable_l2cache
	
       /*
        * Invalidate L1 I/D
        */
        mov	r0, #0                  @ set up for MCR
        mcr	p15, 0, r0, c8, c7, 0   @ invalidate TLBs
        mcr	p15, 0, r0, c7, c5, 0   @ invalidate icache

       /*
        * disable MMU stuff and caches
        */
        mrc	p15, 0, r0, c1, c0, 0
        bic	r0, r0, #0x00002000     @ clear bits 13 (--V-)
        bic	r0, r0, #0x00000007     @ clear bits 2:0 (-CAM)
        orr	r0, r0, #0x00000002     @ set bit 1 (--A-) Align
        orr	r0, r0, #0x00000800     @ set bit 12 (Z---) BTB
        mcr 	p15, 0, r0, c1, c0, 0

(2)识别启动介质

/* Read booting information */
ldr	r0, =PRO_ID_BASE
ldr	r1, [r0,#OMR_OFFSET]
bic	r2, r1, #0xffffffc1

(3)在sram中设置栈

ldr	sp, =0xd0036000 /* end of sram dedicated to u-boot */
sub	sp, sp, #12	/* set stack */
mov	fp, #0

/* 设置栈之后跳转到lowlevel_init */
bl	lowlevel_init	/* go setup pll,mux,memory */

3.7 lowlevel_init

(1)检查复位状态,cpu有多种复位状态,如冷上电、热启动、睡眠,冷上电时需要重新初始化DDR

(2)IO状态恢复:恢复睡眠前IO的值

(3)关看门狗

(4)SRAM和SROM初始化

(5)供电锁存

(6)判断代码运行位置,如果运行在RAM中,就不需要进行重定位

(7)初始化系统时钟

(8)初始化DDR

(9)初始化串口

(10)pop {pc}:函数调用返回

	.globl lowlevel_init
lowlevel_init:
	push	{lr}

	/* check reset status  */
	
	ldr	r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
	ldr	r1, [r0]
	bic	r1, r1, #0xfff6ffff
	cmp	r1, #0x10000
	beq	wakeup_reset_pre
	cmp	r1, #0x80000
	beq	wakeup_reset_from_didle

	/* IO Retention release */
	ldr	r0, =(ELFIN_CLOCK_POWER_BASE + OTHERS_OFFSET)
	ldr	r1, [r0]
	ldr	r2, =IO_RET_REL
	orr	r1, r1, r2
	str	r1, [r0]

	/* Disable Watchdog */
	ldr	r0, =ELFIN_WATCHDOG_BASE	/* 0xE2700000 */
	mov	r1, #0
	str	r1, [r0]

	/* SRAM(2MB) init for SMDKC110 */
	/* GPJ1 SROM_ADDR_16to21 */
	ldr	r0, =ELFIN_GPIO_BASE
	
	ldr	r1, [r0, #GPJ1CON_OFFSET]
	bic	r1, r1, #0xFFFFFF
	ldr	r2, =0x444444
	orr	r1, r1, r2
	str	r1, [r0, #GPJ1CON_OFFSET]

	ldr	r1, [r0, #GPJ1PUD_OFFSET]
	ldr	r2, =0x3ff
	bic	r1, r1, r2
	str	r1, [r0, #GPJ1PUD_OFFSET]

	/* GPJ4 SROM_ADDR_16to21 */
	ldr	r1, [r0, #GPJ4CON_OFFSET]
	bic	r1, r1, #(0xf<<16)
	ldr	r2, =(0x4<<16)
	orr	r1, r1, r2
	str	r1, [r0, #GPJ4CON_OFFSET]

	ldr	r1, [r0, #GPJ4PUD_OFFSET]
	ldr	r2, =(0x3<<8)
	bic	r1, r1, r2
	str	r1, [r0, #GPJ4PUD_OFFSET]


	/* CS0 - 16bit sram, enable nBE, Byte base address */
	ldr	r0, =ELFIN_SROM_BASE	/* 0xE8000000 */
	mov	r1, #0x1
	str	r1, [r0]

	/* PS_HOLD pin(GPH0_0) set to high */
	ldr	r0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)
	ldr	r1, [r0]
	orr	r1, r1, #0x300	
	orr	r1, r1, #0x1	
	str	r1, [r0]

	/* when we already run in ram, we don't need to relocate U-Boot.
	 * and actually, memory controller must be configured before U-Boot
	 * is running in ram.
	 */
	ldr	r0, =0xff000fff
	bic	r1, pc, r0		/* r0 <- current base addr of code */
	ldr	r2, _TEXT_BASE		/* r1 <- original base addr in ram */
	bic	r2, r2, r0		/* r0 <- current base addr of code */
	cmp     r1, r2                  /* compare r0, r1                  */
	beq     1f			/* r0 == r1 then skip sdram init   */

	/* init system clock */
	bl system_clock_init

	/* Memory initialize */
	bl mem_ctrl_asm_init
	
1:
	/* for UART */
	bl uart_asm_init

	bl tzpc_init

#if defined(CONFIG_ONENAND)
	bl onenandcon_init
#endif

#if defined(CONFIG_NAND)
	/* simple init for NAND */
	bl nand_asm_init
#endif

	/* check reset status  */
	
	ldr	r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
	ldr	r1, [r0]
	bic	r1, r1, #0xfffeffff
	cmp	r1, #0x10000
	beq	wakeup_reset_pre

	/* ABB disable */
	ldr	r0, =0xE010C300
	orr	r1, r1, #(0x1<<23)
	str	r1, [r0]

	/* Print 'K' */
	ldr	r0, =ELFIN_UART_CONSOLE_BASE
	ldr	r1, =0x4b4b4b4b
	str	r1, [r0, #UTXH_OFFSET]

	pop	{pc}

3.8 在DDR中设置栈

ldr	r0, =0xE010E81C  /* PS_HOLD_CONTROL register */
ldr	r1, =0x00005301	 /* PS_HOLD output high	*/
str	r1, [r0]

/* get ready to call C functions */
ldr	sp, _TEXT_PHY_BASE	/* setup temp stack pointer */
sub	sp, sp, #12
mov	fp, #0			/* no previous frame, so fp=0 */

3.9 再次判断是否需要进行重定位

/* when we already run in ram, we don't need to relocate U-Boot.
 * and actually, memory controller must be configured before U-Boot
 * is running in ram.
*/
ldr	r0, =0xff000fff
bic	r1, pc, r0		/* r0 <- current base addr of code */
ldr	r2, _TEXT_BASE		/* r1 <- original base addr in ram */
bic	r2, r2, r0		/* r0 <- current base addr of code */
cmp     r1, r2                  /* compare r0, r1                  */
beq     after_copy		/* r0 == r1 then skip flash copy   */

重定位代码

#if defined(CONFIG_EVT1)
	/* If BL1 was copied from SD/MMC CH2 */
	ldr	r0, =0xD0037488
	ldr	r1, [r0]
	ldr	r2, =0xEB200000
	cmp	r1, r2
	beq     mmcsd_boot
#endif

	ldr	r0, =INF_REG_BASE
	ldr	r1, [r0, #INF_REG3_OFFSET]
	cmp	r1, #BOOT_NAND		/* 0x0 => boot device is nand */
	beq	nand_boot
	cmp	r1, #BOOT_ONENAND	/* 0x1 => boot device is onenand */
	beq	onenand_boot
	cmp     r1, #BOOT_MMCSD
	beq     mmcsd_boot
	cmp     r1, #BOOT_NOR
	beq     nor_boot
	cmp     r1, #BOOT_SEC_DEV
	beq     mmcsd_boot

nand_boot:
	mov	r0, #0x1000
	bl	copy_from_nand
	b	after_copy

onenand_boot:
	bl	onenand_bl2_copy
	b	after_copy

mmcsd_boot:
#if DELETE
	ldr     sp, _TEXT_PHY_BASE      
	sub     sp, sp, #12
	mov     fp, #0
#endif
	bl      movi_bl2_copy
	b       after_copy

nor_boot:
	bl      read_hword
	b       after_copy
after_copy:

#if defined(CONFIG_ENABLE_MMU)
enable_mmu:
	/* enable domain access */
	ldr	r5, =0x0000ffff
	mcr	p15, 0, r5, c3, c0, 0		@load domain access register

	/* Set the TTB register */
	ldr	r0, _mmu_table_base
	ldr	r1, =CFG_PHY_UBOOT_BASE
	ldr	r2, =0xfff00000
	bic	r0, r0, r2
	orr	r1, r0, r1
	mcr	p15, 0, r1, c2, c0, 0

	/* Enable the MMU */
mmu_on:
	mrc	p15, 0, r0, c1, c0, 0
	orr	r0, r0, #1
	mcr	p15, 0, r0, c1, c0, 0
	nop
	nop
	nop
	nop
#endif

3.10 再次在DDR中设置栈

skip_hw_init:
	/* Set up the stack						    */
stack_setup:
#if defined(CONFIG_MEMORY_UPPER_CODE)
	ldr	sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)
#else
	ldr	r0, _TEXT_BASE		/* upper 128 KiB: relocated uboot   */
	sub	r0, r0, #CFG_MALLOC_LEN	/* malloc area                      */
	sub	r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
#if defined(CONFIG_USE_IRQ)
	sub	r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
	sub	sp, r0, #12		/* leave 3 words for abort-stack    */

#endif

3.11 清理bss段,并跳转到uboot启动第二阶段_start_armboot

clear_bss:
	ldr	r0, _bss_start		/* find start of bss segment        */
	ldr	r1, _bss_end		/* stop here                        */
	mov 	r2, #0x00000000		/* clear                            */

clbss_l:
	str	r2, [r0]		/* clear loop...                    */
	add	r0, r0, #4
	cmp	r0, r1
	ble	clbss_l
	
	ldr	pc, _start_armboot

相关文章:

  • 基于SpringBoot+Vue的瑜伽课体验课预约系统【附源码】
  • CI/CD—Jenkins实现自动构建Docker镜像运行Java程序
  • 10.OSPF专题
  • 【机器学习】强化学习(3)——深度强化学习的数学知识
  • 设计模式Python版 策略模式
  • C++:vector容器(下篇)
  • CI/CD—Jenkins配置一次完整的jar自动化发布流程
  • Hadoop安装文件解压报错:无法创建符号链接。。。
  • C++11 `enum class`
  • CSGO开箱网盲盒源码搭建与成品演示解析
  • 多视图几何--相机标定--DTL进行相机标定
  • 每日学Java之一万个为什么
  • C++函数高阶
  • 19天 - HTTP 1.0 和 2.0 有什么区别?HTTP 2.0 和 3.0 有什么区别?HTTP 和 HTTPS 有什么区别?
  • 单元测试、系统测试和集成测试知识总结
  • 物联网在电力行业的应用
  • 网络DNS怎么更改?
  • 【前端】BOM DOM
  • Fuel 爬虫:Scala 中的图片数据采集与分析
  • DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14基础固定表头示例
  • 正荣地产:前4个月销售14.96亿元,控股股东已获委任联合清盘人
  • 5月12日至13日北京禁飞“低慢小”航空器
  • 潘功胜发布会答问五大要点:除了降准降息,这些政策“含金量”也很高
  • 最新研究:基因编辑治疗晚期胃肠道癌显成效
  • 吴清:全力支持中央汇金公司发挥好类“平准基金”作用
  • 线下无理由退货怎样操作?线上线下监管有何不同?市场监管总局回应