u-boot属于两阶段的bootloader,第一阶段的文件为 arch/arm/cpu/armv7/start.S 和 arch/arm/cpu/armv7/lowlevel_init.S,前者是平台相关的,后者是开发板相关的。
1. u-boot第一阶段代码分析
(1)硬件设备初始化
将CPU的工作模式设为管理模式(SVC);
关闭中断;
禁用MMU,TLB ;
板级初始化;
(2)为加载Bootloader的第二阶段代码准备RAM空间
加载u-boot.img,跳转到u-boot.img;
上述工作,也就是uboot-spl代码流程的核心。
代码如下:
arch/arm/cpu/armv7/start.S
1 /* 2 * the actual reset code 3 */ 4 reset: 5 bl save_boot_params 6 /* 7 * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode, 8 * except if in HYP mode already 9 */ 10 mrs r0, cpsr 11 and r1, r0, #0x1f @ mask mode bits 12 teq r1, #0x1a @ test for HYP mode 13 bicne r0, r0, #0x1f @ clear all mode bits 14 orrne r0, r0, #0x13 @ set SVC mode 15 orr r0, r0, #0xc0 @ disable FIQ and IRQ 16 msr cpsr,r0 17 @@ 以上通过设置CPSR寄存器里设置CPU为SVC模式,禁止中断 18 @@ 具体操作可以参考《[kernel 启动流程] (第二章)第一阶段之——设置SVC、关闭中断》的分析 19 20 /* the mask ROM code should have PLL and others stable */ 21 #ifndef CONFIG_SKIP_LOWLEVEL_INIT 22 bl cpu_init_cp15 23 @@ 调用cpu_init_cp15,初始化协处理器CP15,从而禁用MMU和TLB。 24 @@ 具体操作可以参考[kernel 启动流程] (第六章)第一阶段之——打开MMU两篇文章的分析 25 bl cpu_init_crit 26 @@ 调用cpu_init_crit,进行一些关键的初始化动作,也就是板级的初始化 27 @@ 后面会有一小节进行分析 28 #endif 29 30 bl _main 31 @@ 跳转到主函数,也就是要加载BL2以及跳转到BL2的主体部分 32 /*------------------------------------------------------------------------------*/
cpu_init_crit
cpu_init_crit,进行一些关键的初始化动作,也就是平台级和板级的初始化。其代码核心就是lowlevel_init,如下
arch/arm/cpu/armv7/start.S
1 ENTRY(cpu_init_crit) 2 /* 3 * Jump to board specific initialization... 4 * The Mask ROM will have already initialized 5 * basic memory. Go here to bump up clock rate and handle 6 * wake up conditions. 7 */ 8 b lowlevel_init @ go setup pll,mux,memory 9 ENDPROC(cpu_init_crit)
所以说lowlevel_init就是这个函数的核心。
arch/arm/cpu/armv7/lowlevel_init.S
1 ENTRY(lowlevel_init) 2 /* 3 * Setup a temporary stack 4 */ 5 ldr sp, =CONFIG_SYS_INIT_SP_ADDR 6 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ 7 #ifdef CONFIG_SPL_BUILD 8 ldr r9, =gdata 9 #else 10 sub sp, sp, #GD_SIZE 11 bic sp, sp, #7 12 mov r9, sp 13 #endif 14 /* 15 * Save the old lr(passed in ip) and the current lr to stack 16 */ 17 push {ip, lr} 18 @@设置好栈,为接下来的C环境做好准备 19 /* 20 * go setup pll, mux, memory 21 */ 22 bl s_init 23 pop {ip, pc} 24 ENDPROC(lowlevel_init)
以Am335x为例,在移植过程中,就需要在lowlevel_init.S里加入一些简单的板级初始化,例如在lowlevle_init.s------->s_init中:
arch/arm/cpu/armv7/am33xx/board.c
void s_init(void) { .... /* * Save the boot parameters passed from romcode. * We cannot delay the saving further than this, * to prevent overwrites. */ #ifdef CONFIG_SPL_BUILD save_omap_boot_params(); @@ #endif #if defined(CONFIG_SPL_BUILD) || defined(CONFIG_NOR_BOOT) watchdog_disable(); //arch/arm/cpu/armv7/am33xx/board.c timer_init(); set_uart_mux_conf(); // board/ti/am335x/board.c setup_clocks_for_console(); // arch/arm/cpu/armv7/am335x/Clock_am33xx.c uart_soft_reset(); // arch/arm/cpu/armv7/am33xx/board.c #endif .... gd = &gdata; preloader_console_init(); @@ .... #if defined(CONFIG_SPL_BUILD) || defined(CONFIG_NOR_BOOT) prcm_init(); set_mux_conf_regs(); #if defined(CONFIG_SPL_AM33XX_ENABLE_RTC32K_OSC) /* Enable RTC32K clock */ rtc32k_enable(); #endif sdram_init(); #endif }
(待续...)