[A133]uboot启动流程
hongxi.zhu 2024-6-21
1. 第一阶段
lds描述
从u-boot.lds
中能找到程序的汇编入口ENTRY(_start)
brandy/brandy-2.0/u-boot-2018/u-boot.lds
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
...
ENTRY(_start)
的实现在start.S
中,根据平台架构, 有对应的实现,当前平台是armv8
_start
brandy/brandy-2.0/u-boot-2018/arch/arm/cpu/armv8/start.S
.globl _start
_start:
#if defined(LINUX_KERNEL_IMAGE_HEADER)
#include <asm/boot0-linux-kernel-header.h>
#elif defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK)
/*
* Various SoCs need something special and SoC-specific up front in
* order to boot, allow them to set that in their boot0.h file and then
* use it here.
*/
#include <asm/arch/boot0.h>
#else
b reset /* 跳转到reset块 */
#endif
reset
brandy/brandy-2.0/u-boot-2018/arch/arm/cpu/armv8/start.S
reset:
/* Allow the board to save important registers */
b save_boot_params /*空实现,并跳转回save_boot_params_ret*/
.globl save_boot_params_ret
save_boot_params_ret:
/*
* Could be EL3/EL2/EL1, Initial State:
* Little Endian, MMU Disabled, i/dCache Disabled
*/
adr x0, vectors /*将异常向量表基地址写到x0*/
switch_el x1, 3f, 2f, 1f /*根据异常等级选择el3/el2/el1情况处理*/
3: msr vbar_el3, x0 /*el3*/
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 */
b 0f /*设置完上述相关寄存器,跳出*/
2: msr vbar_el2, x0 /*el2*/
mov x0, #0x33ff
msr cptr_el2, x0 /* Enable FP/SIMD */
b 0f
1: msr vbar_el1, x0 /*el1*/
mov x0, #3 << 20
msr cpacr_el1, x0 /* Enable FP/SIMD */
0: /* 空执行,相当于跳出 */
/* Apply ARM core specific erratas */
bl apply_core_errata /*arm核的特殊配置*/
/*
* Cache/BPB/TLB Invalidate
* i-cache is invalidated before enabled in icache_enable()
* tlb is invalidated before mmu is enabled in dcache_enable()
* d-cache is invalidated before enabled in dcache_enable()
*/
/* Processor specific initialization */
bl lowlevel_init /* A133看起来没做啥事情 */
master_cpu:
bl _main /*跳转到_main*/
_main
brandy/brandy-2.0/u-boot-2018/arch/arm/lib/crt0_64.S
ENTRY(_main)
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
/*清除x0寄存器的最低四位(#0xf即二进制1111)并赋值给sp栈指针, x0寄存器的值是调用方传递*/
bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */
mov x0, sp /*将栈指针sp的值写入x0寄存器作为下一条bl命令的参数,这个参数就是global区域的顶部地址top*/
bl board_init_f_alloc_reserve /*跳转到C中的board_init_f_alloc_reserve,给全局gd变量分配内存*/
mov sp, x0 /*上面的bl命令执行后,它的返回值存放在x0中,将这个新的栈指针值赋值给sp指针*/
/* set up gd here, outside any C code */
mov x18, x0 /*x18寄存器用作全局数据(Global Data, gd)的指针,上面board_init_f_alloc_reserve的返回值就是需要设置的gd的指针地址*/
bl board_init_f_init_reserve /*跳转到C中的board_init_f_init_reserve, 初始化gd变量的内容为0,并确定后续分配的gd变量内容偏移基地址*/
mov x0, #0 /*x0清零,下一个bl命令传入参数值为0*/
bl board_init_f /*跳转到C中的board_init_f初始化一些早期硬件,并为重定位准备*/
#if !defined(CONFIG_SPL_BUILD)
/*
* Set up intermediate environment (new sp and gd) and call
* relocate_code(addr_moni). Trick here is that we'll return
* 'here' but relocated.
*/
ldr x0, [x18, #GD_START_ADDR_SP] /* x0 <- gd->start_addr_sp */
bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */
ldr x18, [x18, #GD_NEW_GD] /* x18 <- gd->new_gd */
adr lr, relocation_return
/* Add in link-vs-relocation offset */
ldr x9, [x18, #GD_RELOC_OFF] /* x9 <- gd->reloc_off */
add lr, lr, x9 /* new return address after relocation */
ldr x0, [x18, #GD_RELOCADDR] /* x0 <- gd->relocaddr */
b relocate_code
relocation_return:
/*
* Set up final (full) environment
*/
bl c_runtime_cpu_setup /* still call old routine */
#endif /* !CONFIG_SPL_BUILD */
/*
* Clear BSS section
*/
ldr x0, =__bss_start /* this is auto-relocated! */
ldr x1, =__bss_end /* this is auto-relocated! */
clear_loop:
str xzr, [x0], #8
cmp x0, x1
b.lo clear_loop
/* call board_init_r(gd_t *id, ulong dest_addr) */
mov x0, x18 /* gd_t */
ldr x1, [x18, #GD_RELOCADDR] /* dest_addr */
b board_init_r /* PC relative jump */
/* NOTREACHED - board_init_r() does not return */
ENDPROC(_main)
board_init_f_alloc_reserve
brandy/brandy-2.0/u-boot-2018/common/init/board_init.c
ulong board_init_f_alloc_reserve(ulong top)
{
...
/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
// 从global区域分配一块大小为struct global_data大小的16字节对齐的内存存放全局的global_data变量
// top就是x0寄存器传入的值(具体值需要调试才知道)
top = rounddown(top-sizeof(struct global_data), 16);
return top;
}
board_init_f_init_reserve
brandy/brandy-2.0/u-boot-2018/common/init/board_init.c
void board_init_f_init_reserve(ulong base)
{
struct global_data *gd_ptr;
/*
* clear GD entirely and set it up.
* Use gd_ptr, as gd may not be properly set yet.
*/
gd_ptr = (struct global_data *)base; // 拿到寄存器x18里存的gd变量内存地址
/* zero the area */
memset(gd_ptr, '\0', sizeof(*gd)); //将这块内存数据,初始化为0
/* set GD unless architecture did it already */
...
/* next alloc will be higher by one GD plus 16-byte alignment */
base += roundup(sizeof(struct global_data), 16); //内存向上对齐16字节,这个地址就是gd变量后续分配内容的偏移基地址
/*
* record early malloc arena start.
* Use gd as it is now properly set for all architectures.
*/
...
}
board_init_f
brandy/brandy-2.0/u-boot-2018/common/board_f.c
void board_init_f(ulong boot_flags)
{
gd->flags = boot_flags; // 这里汇编传入的x0是0,所以boot_flags = 0
gd->have_console = 0;
//执行init_sequence_f数组中的每一个函数指针,会依次初始化cpu/dm/外设总线/串口/optee/等
if (initcall_run_list(init_sequence_f))
hang();
}
init_sequence_f数组中特别注意的是下面的函数,将接下来的链接重定位息息相关:
static const init_fnc_t init_sequence_f[] = {
setup_mon_len, /*设置内存区域长度 gd->mon_len = __bss_end - __image_copy_start;*/
#ifdef CONFIG_OF_CONTROL
fdtdec_setup, /*设置dtb的地址gd->fdt_blob*/