lds文件可以看出,程序入口函数为_start,下面从_start 开始分析start.s文件中有用的部分。
_start:
b reset @do nothing, jump to save_boot_params
b save_boot_params @do nothing,jump to save_boot_params_ret
b save_boot_params_ret
接下来在运行save_boot_params_ret标号段的代码。
CONFIG_POSITION_INDEPENDENT 宏定义在配置选项中被设置,所以以下代码会被运行。
#if CONFIG_POSITION_INDEPENDENT
/* Verify that we're 4K aligned. */
adr x0, _start
ands x0, x0, #0xfff
b.eq 1f
0:
/*
* FATAL, can't continue.
* U-Boot needs to be loaded at a 4K aligned address.
*
* We use ADRP and ADD to load some symbol addresses during startup.
* The ADD uses an absolute (non pc-relative) lo12 relocation
* thus requiring 4K alignment.
*/
wfi
b 0b
1:
/*
* Fix .rela.dyn relocations. This allows U-Boot to be loaded to and
* executed at a different address than it was linked at.
*/
pie_fixup:
adr x0, _start /* x0 <- Runtime value of _start */
ldr x1, _TEXT_BASE /* x1 <- Linked value of _start */
subs x9, x0, x1 /* x9 <- Run-vs-link offset */
beq pie_fixup_done
adrp x2, __rel_dyn_start /* x2 <- Runtime &__rel_dyn_start */
add x2, x2, #:lo12:__rel_dyn_start
adrp x3, __rel_dyn_end /* x3 <- Runtime &__rel_dyn_end */
add x3, x3, #:lo12:__rel_dyn_end
pie_fix_loop:
/* 对于AArch64架构,一组rela.dyn数据有3个64位数据组成,
* 从上到下分别是需要重定向的原始地址,重定向类型,重定向的原始数据。
* x0=原始地址,x1=重定向类型,这里类型为1027,x2=原始数据。
* 重定向的目标则是将原始地址和数据修改为运行时对应的地址和数据*/
/* x0 = [x2], x1 = [x2+8], x2 = x2+16*/
ldp x0, x1, [x2], #16 /* (x0, x1) <- (Link location, fixup) */
/* x4=[x2], x2=x2+8*/
ldr x4, [x2], #8 /* x4 <- addend */
/* */
cmp w1, #1027 /* relative fixup? */
/*如果不为1027,则不属于此次应该重定向的数据,则跳过 */
bne pie_skip_reloc
/* relative fix: store addend plus offset at dest location */
/* x0=x0+x9,x9是运行地址相对于链接地址的偏移量*/
add x0, x0, x9
/* x4=x4+x9,x9是运行地址相对于链接地址的偏移量*/
add x4, x4, x9
/* 将新数据放到新的地址上*/
str x4, [x0]
pie_skip_reloc:
/* start=end,跳转到pie_fixup_done运行,如果不等,则跳转到pie_fix_loop继续*/
cmp x2, x3
b.lo pie_fix_loop
pie_fixup_done:
#endif
这段代码用于位置无关代码段的rel.dyn段,判断代码实际运行地址与链接地址是否相等,如果不相等,则需要吧rel_dyn段搬运到运行处对应的位置。 对于AArch64架构,一组rela.dyn数据有3个64位数据组成,从上到下分别是需要重定向的原始地址,重定向类型,重定向的原始数据(这里的原始数据也是地址:全局变量的地址等)。
接下来根据实际运行的el等级,初始化异常向量表。
#if defined(CONFIG_ARMV8_SPL_EXCEPTION_VECTORS) || !defined(CONFIG_SPL_BUILD)
.macro set_vbar, regname, reg
msr \regname, \reg
.endm
adr x0, vectors
#else
.macro set_vbar, regname, reg
.endm
#endif
/*
* Could be EL3/EL2/EL1, Initial State:
* Little Endian, MMU Disabled, i/dCache Disabled
*/
switch_el x1, 3f, 2f, 1f
3: set_vbar vbar_el3, x0
mrs x0, scr_el3
orr x0, x0, #0xf /* SCR_EL3.NS|IRQ|FIQ|EA */
msr scr_el3, x0
msr cptr_el3, xzr /* Enable FP/SIMD */
#ifdef COUNTER_FREQUENCY
ldr x0, =COUNTER_FREQUENCY
msr cntfrq_el0, x0 /* Initialize CNTFRQ */
#endif
b 0f
2: set_vbar vbar_el2, x0
mov x0, #0x33ff
msr cptr_el2, x0 /* Enable FP/SIMD */
b 0f
1: set_vbar vbar_el1, x0
mov x0, #3 << 20
msr cpacr_el1, x0 /* Enable FP/SIMD */
0:
isb
vectors是excecption.S文件中的代码,定义了异常向量表和中断函数。 至此,cpu进入了关闭mmu,cache,tlb的状态。
最后主cpu跳转到_main:
/* cpu 勘误修正,一般都不用 */
bl apply_core_errata
bl lowlevel_init
bl _main
而_main 是再crt0_64.S文件中。
综上,start.S里面做了以下事情:
(1)如果定义了CONFIG_POSITION_INDEPENDENT,则根据实际运行地址和链接地址来修正rel_dyn 段,参照arm位置无关代码。
(2)根据当前el等级,把中断向量表放到对应的el的寄存器中
(3)lowlevel_init中根据中断控制器的类型初始化中断控制器
(4)跳转到_main