4418上电后会先加载运行片内启动代码(BL0),大致工作是判断CPU的启动方式,初始化启动设备。拷贝uboot前16k(BL1)到内部RAM,对代码做校验,然后开始运行BL1。4418的BL1也是厂商直接提供的,属于闭源代码。4418的BL1大致由2nboot和2nboot配置组成,2nboot的配置可以在友善之臂的uboot源码中找到(tools/nexell/nish/nanop2.txt)。2nboot大致工作是初始化中断向量,关闭看门口,初始化ddr内存,拷贝整个uboot到ddr,然后跳转到ddr中运行uboot的后半部分(BL2)。
友善支之臂不同版本的2nboot代码量大小不一样,具体见我前两篇博客中的介绍
uboot 2010:https://blog.csdn.net/qq_16054639/article/details/105770048
uboot 2016:https://blog.csdn.net/qq_16054639/article/details/105829051
uboot中的CONFIG_SPL是没有启用的,整个uboot的前半部分启动代码是闭源的,所以手里的源码都是从后半部分开始的。
查看源码文件/arch/arm/armv7/s5p4418/u-boot.lds
.text :
{
*(.__image_copy_start) //拷贝开始的位置
*(.vectors) //存放中断向量表
CPUDIR/start.o (.text*)//代码开始
*(.text*)
}
发现开始代码段为vectors,这个vectors的来源是在配置文件tools/nexell/nish/nanop2.txt中
E59FF018 // 0x000 : MOV PC, ResetV
E59FF018 // 0x004 : MOV PC, UndefV
E59FF018 // 0x008 : MOV PC, SWIV
E59FF018 // 0x00C : MOV PC, PAbortV
E59FF018 // 0x010 : MOV PC, DAbortV
E59FF018 // 0x014 : MOV PC, NotUsed
E59FF018 // 0x018 : MOV PC, IRQV
E59FF018 // 0x01C : MOV PC, FIQV
FFFF0200 // 0x020 : SRAMBASE + Header
FFFF0204 // 0x024 : SRAMBASE + Header
FFFF0208 // 0x028 : SRAMBASE + Header
FFFF020C // 0x02C : SRAMBASE + Header
FFFF0210 // 0x030 : SRAMBASE + Header
FFFF0214 // 0x034 : SRAMBASE + Header
FFFF0218 // 0x038 : SRAMBASE + Header
FFFF021C // 0x03C : SRAMBASE + Header
之后接着开始代码/arch/arm/armv7/start.S
.globl reset
.globl save_boot_params_ret
reset:
/* Allow the board to save important registers */
b save_boot_params
save_boot_params_ret:
/*
* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
* except if in HYP mode already
*/
mrs r0, cpsr
and r1, r0, #0x1f @ mask mode bits
teq r1, #0x1a @ test for HYP mode
bicne r0, r0, #0x1f @ clear all mode bits
orrne r0, r0, #0x13 @ set SVC mode
orr r0, r0, #0xc0 @ disable FIQ and IRQ
msr cpsr,r0
/*
* Setup vector:
* (OMAP4 spl TEXT_BASE is not 32 byte aligned.
* Continue to use ROM code vector only in OMAP4 spl)
*/
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD)) //没配置这里不会执行
/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTLR Register
bic r0, #CR_V @ V = 0
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTLR Register
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
#endif
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_cp15
bl cpu_init_crit
#endif
bl _main
执行流程:
/arch/arm/armv7/lowlevel_init.S
执行流程:
/arch/arm/lib/crt0.S
执行流程:
/common/board_f.c
board_init_f这个函数主要遍历执行了init_sequence_f这个数组中的函数
挑出几个主要关键函数解释:
/common/board_c.c
board_init_r函数跟board_init_f函数类似,也是遍历执行一个数组中的所有函数
挑出几个主要关键函数解释:
run_preboot_environment_command(执行默认环境变量命令,也就是启动命令preboot)
preboot定义在include/env_default.h
#ifdef CONFIG_PREBOOT
"preboot=" CONFIG_PREBOOT "\0" //CONFIG_PREBOOT这个宏没有定义,所以这里等于什么也没做
#endif
至此整个uboot的主要启动流程就梳理结束了