<span style="font-size:18px;">一、首先分析u-boot代码,u-boot启动过程分为两个阶段。在u-boot下,对于arm处理器来说,一上电执行的程序会在/cpu/920t/Start.S汇编文件。</span>
1分析start.S汇编文件
start.S最开始是异常向量表,如下所示:
.globl _start _start: b start_code 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
正常情况下会执行异常向量表的第一个段跳转指令,跳转到start_code 执行,start_code处会设置cpu为SVC模式,代码如下:
start_code: /* * set the cpu to SVC32 mode */ mrs r0,cpsr bic r0,r0,#0x1f orr r0,r0,#0xd3 msr cpsr,r0
之后进行关闭中断、关闭看门狗、代码如下:
/* turn off the watchdog */ # if defined(CONFIG_S3C2400) # define pWTCON 0x15300000 # define INTMSK 0x14400008 /* Interupt-Controller base addresses */ # define CLKDIVN 0x14800014 /* clock divisor register */ #else # define pWTCON 0x53000000 # define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ # define INTSUBMSK 0x4A00001C # define CLKDIVN 0x4C000014 /* clock divisor register */ # endif ldr r0, =pWTCON mov r1, #0x0 str r1, [r0] /* * mask all IRQs by setting all bits in the INTMR - default */ mov r1, #0xffffffff ldr r0, =INTMSK str r1, [r0] # if defined(CONFIG_S3C2410) ldr r1, =0x3ff ldr r0, =INTSUBMSK str r1, [r0] # endif
设置cpu时钟初始化CPU(关闭I/D cache 关闭MMU操作):
/* FCLK:HCLK:PCLK = 1:2:4 */ /* default FCLK is 120 MHz ! */ ldr r0, =CLKDIVN mov r1, #3 str r1, [r0]
<span style="white-space:pre"> </span>bl<span style="white-space:pre"> </span>cpu_init_crit
cpu_init_crit: <span style="white-space:pre"> </span>/* <span style="white-space:pre"> </span> * flush v4 I/D caches <span style="white-space:pre"> </span> */ <span style="white-space:pre"> </span>mov<span style="white-space:pre"> </span>r0, #0 <span style="white-space:pre"> </span>mcr<span style="white-space:pre"> </span>p15, 0, r0, c7, c7, 0<span style="white-space:pre"> </span>/* flush v3/v4 cache */ <span style="white-space:pre"> </span>mcr<span style="white-space:pre"> </span>p15, 0, r0, c8, c7, 0<span style="white-space:pre"> </span>/* flush v4 TLB */ <span style="white-space:pre"> </span>/* <span style="white-space:pre"> </span> * disable MMU stuff and caches <span style="white-space:pre"> </span> */ <span style="white-space:pre"> </span>mrc<span style="white-space:pre"> </span>p15, 0, r0, c1, c0, 0 <span style="white-space:pre"> </span>bic<span style="white-space:pre"> </span>r0, r0, #0x00002300<span style="white-space:pre"> </span>@ clear bits 13, 9:8 (--V- --RS) <span style="white-space:pre"> </span>bic<span style="white-space:pre"> </span>r0, r0, #0x00000087<span style="white-space:pre"> </span>@ clear bits 7, 2:0 (B--- -CAM) <span style="white-space:pre"> </span>orr<span style="white-space:pre"> </span>r0, r0, #0x00000002<span style="white-space:pre"> </span>@ set bit 2 (A) Align <span style="white-space:pre"> </span>orr<span style="white-space:pre"> </span>r0, r0, #0x00001000<span style="white-space:pre"> </span>@ set bit 12 (I) I-Cache <span style="white-space:pre"> </span>mcr<span style="white-space:pre"> </span>p15, 0, r0, c1, c0, 0 <span style="white-space:pre"> bl<span style="white-space:pre"> </span>lowlevel_init</span>
<span style="white-space:pre"> </span>mov<span style="white-space:pre"> </span>ip, lr
</pre><p></p><p><span style="font-size:18px"><span style="font-size:18px">在cpu_init_crit中会初始化内存SDRAM,主要在lowlevel_init.S中实现。</span></span></p><p></p><p><span style="font-size:18px"><span style="font-size:18px">设置栈指针:</span></span></p><p><span style="font-size:18px"></span></p><pre name="code" class="plain">relocate: /* relocate U-Boot to RAM */ adr r0, _start /* r0 <- current position of code */ ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ cmp r0, r1 /* don't reloc during debug */ beq stack_setup
stack_setup: <span style="white-space:pre"> </span>ldr<span style="white-space:pre"> </span>r0, _TEXT_BASE<span style="white-space:pre"> </span>/* upper 128 KiB: relocated uboot */ <span style="white-space:pre"> </span>sub<span style="white-space:pre"> </span>r0, r0, #CFG_MALLOC_LEN<span style="white-space:pre"> </span>/* malloc area */ <span style="white-space:pre"> </span>sub<span style="white-space:pre"> </span>r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */实现自拷贝
copy_loop: ldmia r0!, {r3-r10} /* copy from source address [r0] */ stmia r1!, {r3-r10} /* copy to target address [r1] */ cmp r0, r2 /* until source end addreee [r2] */ ble copy_loop之后跳转到下个阶段的start_armboot执行。
ldr pc, _start_armboot
2.第二段代码在/lib_arm/board.c中
入口函数:
void start_armboot (void) { init_fnc_t **init_fnc_ptr;
<span style="white-space:pre"> </span>gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
<span style="white-space:pre"> </span>memset ((void*)gd, 0, sizeof (gd_t)); <span style="white-space:pre"> </span>gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); <span style="white-space:pre"> </span>memset (gd->bd, 0, sizeof (bd_t));
<span style="white-space:pre"> </span>for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { <span style="white-space:pre"> </span>if ((*init_fnc_ptr)() != 0) { <span style="white-space:pre"> </span>hang (); <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>...
}
board.c所做工作主要是初始化板参数的全局变量golbal_data,在第二阶段入口函数start_armboot中,初始化这个全局变量gd (golbal_data),这是一个全局指针,存放所需初始化的函数指针,通过一个for循环来调用这些函数。这些函数的主要操作是开发板的基本设置,如串口波特率、设备序列号、mac地址、启动参数存储地址等。在初始化结束后跳到/common/main.c代码中循环的通过串口与u-boot进行交互,在此进行内核的引导或者其他参数的修改或者配置。至此u-boot结束工作,把管理权交给被引导的内核。
以上即是u-boot的启动流程。
二、s5pv210硬件上的操作
对于硬件来说,arm启动时,会先运行内部IROM中的固化代码进行一些必要的初始化,执行完后硬件上会自动读取NAND Flash或sd卡等启动设备的前16K的数据到IRAM中,这16K数据中的前16byte中保存了一个叫校验和的值,校验通过后,程序会继续运行,并且将第一阶段的代码拷贝到SDRAM中进而运行第二阶段。因此跳转后CPU就是从SDRAM中取址执行了。
以上为本人学习总结,仅供参考,如有不足还望指出,谢谢!