U-Boot的启动过程源码分析
u-boot属于两阶段的bootloader,第一阶段的文件为cpu/arm920t/start.S和board/smdk2410/lowlevel_init.S,前者是平台相关的,后者是开发板相关的。
1.u-boot第一阶段代码分析
(1)硬件设备初始化
依次完成如下设置:将CPU的工作模式设为管理模式(svc),关闭看门狗,设置FCLK、HCLK、PCLK的比例(即设置CLKDIVN寄存器),关闭MMU、CACHE。
代码在cpu/arm920t/start.S中。
(2)为加载bootloader的第二阶段代码准备RAM空间
初始化内存芯片,使能。对于S3C2410/S3C2440,通过在start.S中调用lowlevel_init函数来设置存储控制器,使得外接的SDRAM可用。代码在board/smdk2410/lowlevel_init.S中。(该文件是开发板相关的,如果外接设备不一样,可以修改相关宏定义)
129 _TEXT_BASE: 130 .word TEXT_BASE 131 132 .globl lowlevel_init 133 lowlevel_init: 134 /* memory control configuration */ 135 /* make r0 relative the current location so that it */ 136 /* reads SMRDATA out of FLASH rather than memory ! */ 137 ldr r0, =SMRDATA 138 ldr r1, _TEXT_BASE 139 sub r0, r0, r1 140 ldr r1, =BWSCON /* Bus Width Status Controller */ 141 add r2, r0, #13*4 142 0: 143 ldr r3, [r0], #4 144 str r3, [r1], #4 145 cmp r2, r0 146 bne 0b 147 148 /* everything is fine now */ 149 mov pc, lr 150 151 .ltorg 152 /* the literal pools origin */ 153 154 SMRDATA: 155 .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) 156 .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
- 第137~139行进行地址变换,因为这时候内存还没有数据,不能使用连接程序时确定的地址来读取数据;
- 第137行中的SMRDATA表示这13个寄存器的值存放的开始地址(连接地址),值为0x33F8xxxx,处于内存中;
- 第138行获得代码的起始地址,他就是第130行中的“TEXT_BASE”,其值在board/smdk2410/config.mk中定义为“TEXT_BASE=0x33F80000”。
- 第139行将0x33F8xxxx与0x33F80000相减,这就是13个寄存器值在NOR Flash上存放的开始地址
(3)复制bootloader的第二段代码到RAM空间
这里将整个u-boot的代码(包括第一、第二阶段)都复制到SDRAM中,这在cpu/arm920t/start.S中实现,如下所示:
164 relocate: /* relocate U-Boot to RAM ,将u-boot复制到ram中 */ 165 adr r0, _start /* r0 <- current position of code ,r0:当前代码的开始地址 */ 166 ldr r1, _TEXT_BASE /* test if we run from flash or RAM ,r1:代码段的连接地址*/ 167 cmp r0, r1 /* don‘t reloc during debug ,测试现在是在flash中还是在ram中 */ 168 beq stack_setup 169 170 ldr r2, _armboot_start 第一条指令的运行地址 171 ldr r3, _bss_start 在连接脚本u-boot.lds中定义,是代码的结束地址 172 sub r2, r3, r2 /* r2 <- size of armboot ,r2=代码段长度 */ 173 add r2, r0, r2 /* r2 <- source end address ,r2=nor flash上代码段的结束地址 */ 174 175 copy_loop: 176 ldmia r0!, {r3-r10} /* copy from source address [r0] ,从地址[r0]处获得数据 */ 177 stmia r1!, {r3-r10} /* copy to target address [r1] ,复制到地址[r1]处 */ 178 cmp r0, r2 /* until source end addreee [r2] ,判断是否幅值完毕 */ 179 ble copy_loop 没复制完,则继续
(4)设置好栈
栈的设置灵活性很大,只要让sp寄存器指向一段没有使用的内存即可。
(5)跳转到第二段代码的c入口点
在跳转前,要清除BSS段(初始值为0、无初始值的全局变量、静态变量放在BSS段)
此时,C函数的运行环境已经完全准备好,通过如下命令直接跳转(之后,程序开始在内存中运行),将调用lib_arm/board.c中的start_armboot函数,这是第二阶段的入口点。
223 ldr pc, _start_armboot 224 225 _start_armboot: .word start_armboot
2.u-boot移植第二阶段代码分析
第二阶段从lib_arm/board.c中的start_armboot函数开始,完成对硬件的初始化、驱动
(1)初始化本阶段