上QQ阅读APP看书,第一时间看更新
1.2.3 函数_main
函数_main的代码如下:
arch/arm/lib/crt0_64.S 1 ENTRY(_main) 2 3 /* 4 * 设置初始的C语言运行环境,并且调用board_init_f(0)。 5 */ 6 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK 7 ldr x0, =(CONFIG_SPL_STACK) 8 #else 9 ldr x0, =(CONFIG_SYS_INIT_SP_ADDR) 10 #endif 11 bic sp, x0, #0xf /* 为了符合应用二进制接口规范,对齐到16字节*/ 12 mov x0, sp 13 bl board_init_f_alloc_reserve 14 mov sp, x0 15 /* 设置gd */ 16 mov x18, x0 17 bl board_init_f_init_reserve 18 19 mov x0, #0 20 bl board_init_f 21 22 #if ! defined(CONFIG_SPL_BUILD) 23 /* 24 * 设置中间环境(新的栈指针和gd),然后调用函数 25 * relocate_code(addr_moni)。 26 * 27 */ 28 ldr x0, [x18, #GD_START_ADDR_SP] /* 把寄存器x0设置为gd->start_addr_sp */ 29 bic sp, x0, #0xf /* 为了符合应用二进制接口规范,对齐到16字节 */ 30 ldr x18, [x18, #GD_BD] /* 把寄存器x18设置为gd->bd */ 31 sub x18, x18, #GD_SIZE /* 新的gd在bd的下面 */ 32 33 adr lr, relocation_return 34 ldr x9, [x18, #GD_RELOC_OFF] /* 把寄存器x9设置为gd->reloc_off */ 35 add lr, lr, x9 /* 在重定位后新的返回地址 */ 36 ldr x0, [x18, #GD_RELOCADDR] /* 把寄存器x0设置为gd->relocaddr */ 37 b relocate_code 38 39 relocation_return: 40 41 /* 42 * 设置最终的完整环境 43 */ 44 bl c_runtime_cpu_setup /* 仍然调用旧的例程 */ 45 #endif /* ! CONFIG_SPL_BUILD */ 46 #if defined(CONFIG_SPL_BUILD) 47 bl spl_relocate_stack_gd /* 可能返回空指针 */ 48 /* 49 * 执行“sp = (x0 ! = NULL) ? x0 : sp”, 50 * 规避这个约束: 51 * 带条件的mov指令不能把栈指针寄存器作为操作数 52 */ 53 mov x1, sp 54 cmp x0, #0 55 csel x0, x0, x1, ne 56 mov sp, x0 57 #endif 58 59 /* 60 * 用0初始化未初始化数据段 61 */ 62 ldr x0, =__bss_start /* 这是自动重定位*/ 63 ldr x1, =__bss_end /* 这是自动重定位*/ 64 clear_loop: 65 str xzr, [x0], #8 66 cmp x0, x1 67 b.lo clear_loop 68 69 /* 调用函数board_init_r(gd_t *id, ulong dest_addr) */ 70 mov x0, x18 /* gd_t */ 71 ldr x1, [x18, #GD_RELOCADDR] /* dest_addr */ 72 b board_init_r /* 相对程序计数器的跳转 */ 73 74 /* 不会运行到这里,因为函数board_init_r()不会返回*/ 75 76 ENDPROC(_main)
第6~17行代码,设置C代码的运行环境,为调用函数board_init_f做准备。
❑ 第11行代码,设置临时的栈。
❑ 第13行代码,调用函数board_init_f_alloc_reserve,在栈的顶部为结构体global_data分配空间。
❑ 第17行代码,调用函数board_init_f_init_reserve,初始化结构体global_data。
第20行代码,调用函数board_init_f(f是front,表示前期),执行前期初始化。为了把U-Boot程序复制到内存中来执行,初始化硬件,做准备工作。文件“common/board_f.c”定义了公共的函数board_init_f,函数board_init_f依次执行数组init_sequence_f中的每个函数。
第22~45行代码,如果编译为正常的引导程序,那么调用函数relocate_code,把U-Boot程序复制到内存中,重新定位,然后调用函数c_runtime_cpu_setup,把向量基准地址寄存器设置为异常向量表的起始地址。这里是分界线,以前处理器从NOR闪存取指令,这一步执行完以后处理器从内存取指令。
第46~57行代码,如果编译为第二阶段程序加载器,那么调用函数spl_relocate_stack_gd重新定位栈。
第62~67行代码,用0初始化未初始化数据段。
第72行代码,调用函数board_init_r(r是rear,表示后期),执行后期初始化。文件“common/board_r.c”定义了函数board_init_r,依次执行数组init_sequence_r中的每个函数,最后一个函数是run_main_loop。