下面的代码基于amlogic的SDK的code示例。
start.S为整个u-boot的入口
start.S(arch\arm\cpu\armv8\start.S)
- #include <asm-offsets.h>
- #include <config.h>
- #include <version.h>
- #include <linux/linkage.h>
- #include <asm/macro.h>
- #include <asm/armv8/mmu.h>
-
- /*************************************************************************
- *
- * Startup Code (reset vector)
- *
- *************************************************************************/
-
- .globl _start
- _start:
- b reset
-
- .align 3
-
- .globl _TEXT_BASE
- _TEXT_BASE:
- .quad CONFIG_SYS_TEXT_BASE
-
- /*
- * These are defined in the linker script.
- */
- .globl _end_ofs
- _end_ofs:
- .quad _end - _start
-
- .globl _bss_start_ofs
- _bss_start_ofs:
- .quad __bss_start - _start
-
- .globl _bss_end_ofs
- _bss_end_ofs:
- .quad __bss_end - _start
-
- reset:
- /*
- * Could be EL3/EL2/EL1, Initial State:
- * Little Endian, MMU Disabled, i/dCache Disabled
- */
- adr x0, vectors
- switch_el x1, 3f, 2f, 1f
- 3: msr 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 */
- ldr x0, =COUNTER_FREQUENCY
- msr cntfrq_el0, x0 /* Initialize CNTFRQ */
- b 0f
- 2: msr vbar_el2, x0
- mov x0, #0x33ff
- msr cptr_el2, x0 /* Enable FP/SIMD */
- b 0f
- 1: msr vbar_el1, x0
- mov x0, #3 << 20
- msr cpacr_el1, x0 /* Enable FP/SIMD */
- 0:
-
- /*
- * 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
-
- branch_if_master x0, x1, master_cpu
-
- /*
- * Slave CPUs
- */
- slave_cpu:
- wfe
- ldr x1, =CPU_RELEASE_ADDR
- ldr x0, [x1]
- cbz x0, slave_cpu
- br x0 /* branch to the given address */
-
- /*
- * Master CPU
- */
- master_cpu:
- bl _main
主要的流程如下:
(1)根据当前的EL级别,配置中断向量、MMU、Endian、i/d Cache等。
(2)配置ARM的勘误表,具体可参考apply_core_errata函数。
(3)调用lowlevel_init。
(4)如果是多CPU的场景,处理其它的CPU的boot。
(5)跳转到arm公共的_main中执行。
跳转到crt0_64.S(arch\arm\lib\crt0_64.S)中:
- #include <config.h>
- #include <asm-offsets.h>
- #include <asm/macro.h>
- #include <linux/linkage.h>
-
- ENTRY(_main)
-
- /*
- * Set up initial C runtime environment and call board_init_f(0).
- */
- ldr x0, =(CONFIG_SYS_INIT_SP_ADDR)
- sub x0, x0, #GD_SIZE /* allocate one GD above SP */
- bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */
- mov x18, sp /* GD is above SP */
- mov x0, #0
- bl board_init_f
-
- /*
- * 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_BD] /* x18 <- gd->bd */
- sub x18, x18, #GD_SIZE /* new GD is below bd */
-
- adr lr, relocation_return
- 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 */
-
- /*
- * Clear BSS section
- */
- ldr x0, =__bss_start /* this is auto-relocated! */
- ldr x1, =__bss_end /* this is auto-relocated! */
- mov x2, #0
- clear_loop:
- str x2, [x0]
- add x0, 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)
-
主要流程如下(源码注释翻译):
(1)设置board_init_f()初始化环境。
(2)调用board_init_f()。
如果是非SPL,则执行(3)-(6)
(3)设置board_init_f()在系统内存中分配的堆栈和GD中间环境,BSS 和非常量数据任然不可用。
(4)调用relocate_code()。
(5)设置calling board_init_r()调用环境。
(6)调用calling board_init_r()。
后续board_init_f()及board_init_r()都是C语言实现了,汇编部分到此为止,喜欢深入研究的可以多了解,下节我们分析C语言实现部分,也是我们日常经常需要修改的地方。