上接博文《TI-Davinci开发系列之八x-loader工作流程分析》
原创作品,转载时请务必以超链接形式标明文章原始出处:http://blog.csdn.net/gqb666/article/details/8931775,作者:gqb666
注:本文使用的u-boot源码版本为u-boot-2009.11
u-boot同其他bootloader一样,其启动过程分为stage1和stage2两个阶段, stage1主要完成基本硬件设备初始化和为加载stage2部分的代码准备RAM空间,stage2则是为引导内核准备环境。下面分两部分来分析u-boot启动的两个阶段。
u-boot的第一阶段主要由u-boot源文件目录cpu\arm_cortexa8目录下的start.S和cpu\arm_cortexa8\omap3目录下lowlevel_init.S来完成,前者是SOC平台相关,后者是开发板相关的。
基本硬件设备的初始化主要在start.S内完成,依次完成如下设置:将CPU的工作模式设为管理模式(svc),将中断向量表拷贝到SRAM,关闭WATCHDOG,后来就是关闭MMU,CACHE等。
reset: /* * set the cpu to SVC32 mode 设置ARM处理器的工作模式为SVC模式 */ mrs r0, cpsr bic r0, r0, #0x1f orr r0, r0, #0xd3 msr cpsr,r0 /*将中断向量表拷贝到SRAM*/ #if (CONFIG_OMAP34XX) /* Copy vectors to mask ROM indirect addr */ adr r0, _start @ r0<- current position of code add r0, r0, #4 @ skip reset vector mov r2, #64 @ r2 <- size to copy add r2, r0, r2 @ r2 <- sourceend address mov r1, #SRAM_OFFSET0 @ build vect addr mov r3, #SRAM_OFFSET1 add r1, r1, r3 mov r3, #SRAM_OFFSET2 add r1, r1, r3 next: ldmia r0!, {r3 - r10} @ copy from source address [r0] stmia r1!, {r3 - r10} @ copyto target address [r1] cmp r0, r2 @until source end address [r2] bne next @loop until equal */ ldr pc, _start_armboot @ jump to C code _start_armboot: .wordstart_armboot cpu_init_crit: /*关闭MMU与CACHE */ mov r0, #0 @ set up for MCR mcr p15, 0, r0, c8, c7, 0 @ invalidateTLBs mcr p15, 0, r0, c7, c5, 0 @ invalidateicache 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 /*调用lowlevel_init用来初始化RAM*/ mov ip, lr @persevere link reg across call bl lowlevel_init @go setup pll,mux,memory mov lr, ip @restore link mov pc, lr @back to my caller
所谓准备RAM空间,就是初始化内存控制器,使它可用。对于OMAP3这种SOC,通过在start.S中调用lowlevel_init函数来设置存储控制器,使得外接的SDRAM可用。代码在cpu\arm_cortexa8\omap3目录下lowlevel_init.S中。
.globl lowlevel_init lowlevel_init: ldr sp, SRAM_STACK str ip, [sp] /* stashold link register */ mov ip, lr /*save link reg across call */ bl s_init /* gosetup pll,mux,memory */ ldr ip, [sp] /* restore saveip */ mov lr, ip /*restore link reg */ /* back toarch calling code */ mov pc, lr /* the literalpools origin */ .ltorg
这里将u-boot的代码(实际包括第一、二阶段)都复制到SDRAM中,这在cpu\arm_cortexa8中start.S中完成,这一步是u-boot第一阶段的核心所在,因为它实际上完成将代码拷贝到u-boot执行的链接地址处,在此之后的变量就可以进行正常读写,前面的代码必须是位置无关代码(只能读操作不能写操作)。
relocate: /*将x-loader复制到RAM中 */ adr r0, _start /* r0:当前代码的开始地址 */ ldr r1, _TEXT_BASE /* r1:代码段的链接地址 */ cmp r0, r1 /* 测试是否需要复制(SRAM,SDRAM,NOR FLAHS不需要复制) beq stack_setup /*直接跳到栈初始化部分) */ ldr r2, _armboot_start /*_armboot_start在前面定义,第一条指令地址*/ ldr r3, _bss_start /*链接脚本x-loader.lds中定义,是代码段的结束地址*/ sub r2, r3, r2 /* r2 :代码段长度 */ add r2, r0, r2 /* r2:SRAM上代码段的结束地址 */ copy_loop: ldmia r0!, {r3-r10} /*从地址[r0]处获得数据 */ stmia r1!, {r3-r10} /*复制到地址[r1]处 */ cmp r0, r2 /*判断是否复制完毕 */ ble copy_loop
栈的设置灵活性很大,只要让sp寄存器指向一段没有使用的内存即可。
/* Set up the stack */ stack_setup: ldr r0, _TEXT_BASE /*_TEXT_BASE代码段的开始地址 */ sub sp, r0, #128 /*为 abort-栈保留32字节 */ and sp, sp, #~7 /* 8字节对齐 */
在跳转之前,还要清除BSS段(初始值为0、无初始值的全局变量、静态变量放在BSS段),代码如下:
clear_bss: ldr r0, _bss_start /* bss段的开始地址 */ ldr r1, _bss_end /* bss段的结束地址,它的值在链接脚本中定义*/ mov r2, #0x00000000 /* clear value */ clbss_l: str r2, [r0] /*往bss段内写入0值 */ cmp r0, r1 /*are we at the end yet */ add r0, r0, #4 /* increment clearindex pointer */ bne clbss_l /* keep clearing till atend */ ldr pc, _start_armboot /*向C函数入口跳转 */ _start_armboot: .word start_armboot