一:arch/arm/cpu/armv8/start.S
蓝色标注的是实际执行的代码片段,红色为注释
#include
#include
#include
#include
#include
.globl _start
_start:
#ifdef 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
#else
b reset
#endif
#if !CONFIG_IS_ENABLED(TINY_FRAMEWORK)
.align 3 //8字节对齐,可以在汇编文件中看出来
.globl _TEXT_BASE
_TEXT_BASE:
#if defined(CONFIG_SPL_BUILD)
.quad CONFIG_SPL_TEXT_BASE
#else
.quad CONFIG_SYS_TEXT_BASE //0x00200000,include/configs/px30_comm.h
#endif
// These are defined in the linker script. Arch/arm/cpu/armv8/u-boot.lds
.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:
/* Allow the board to save important registers */
b save_boot_params
.globl save_boot_params_ret
save_boot_params_ret:
//由汇编可以看出,跳到save_boot_params之后什么也没干就又跳回了save_boot_params_ret
#if CONFIG_POSITION_INDEPENDENT
/*
* 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 */
sub x9, x0, x1 /* x9 <- Run-vs-link offset */
adr x2, __rel_dyn_start /* x2 <- Runtime &__rel_dyn_start */
adr x3, __rel_dyn_end /* x3 <- Runtime &__rel_dyn_end */
pie_fix_loop:
ldp x0, x1, [x2], #16 /* (x0, x1) <- (Link location, fixup) */
ldr x4, [x2], #8 /* x4 <- addend */
cmp w1, #1027 /* relative fixup? */
bne pie_skip_reloc
/* relative fix: store addend plus offset at dest location */
add x0, x0, x9
add x4, x4, x9
str x4, [x0]
pie_skip_reloc:
cmp x2, x3
b.lo pie_fix_loop
pie_fixup_done:
#endif
#ifdef CONFIG_SYS_RESET_SCTRL
bl reset_sctrl
#endif
/*
* Could be EL3/EL2/EL1, Initial State:
* Little Endian, MMU Disabled, i/dCache Disabled
*/
adr x0, vectors //将中断向量的地址给到x0,中断向量文件的位置在 arch/arm/cpu/armv8/exceptions.S
switch_el x1, 3f, 2f, 1f
/*switch_el的定义为
.macro switch_el, xreg, el3_label, el2_label, el1_label
mrs \xreg, CurrentEL
cmp \xreg, 0xc
b.eq \el3_label
cmp \xreg, 0x8
b.eq \el2_label
cmp \xreg, 0x4
b.eq \el1_label
.endm
此处switch_el定义为:读取CurrentEL状态寄存器的值,如果等于0xc则跳到el3_label,0x8则跳到el2_label,0x4则跳到el1_label,此处为根据中断等级跳到响应的位置*/
3: msr vbar_el3, x0 //将中断向量保存到vbar_el3(Vector Base Address Register (EL3))
mrs x0, scr_el3 //获取scr_el3(Secure Configuration Register)的值
orr x0, x0, #0xf //将低四位设置为1:EA|FIQ|IRQ|NS
msr scr_el3, x0 //写入scr_el3
msr cptr_el3, xzr // Enable FP/SIMD,XZR/WZR(word zero rigiser)分别 代表64/32位,zero register的作用就是0,写进 去代表丢弃结果,拿出来是0
#ifdef COUNTER_FREQUENCY
ldr x0, =COUNTER_FREQUENCY
msr cntfrq_el0, x0 /* Initialize CNTFRQ */
//晶振频率设置,px30_comm.h中 #define COUNTER_FREQUENCY 24000000,写入cntfrq_el0
#endif
b 0f //0f处的指令为bl apply_core_errata
2: msr vbar_el2, x0
mov x0, #0x33ff
msr cptr_el2, x0 /* Enable FP/SIMD */
//使能EL2等级下的FP/SIMD
b 0f
1: msr vbar_el1, x0
mov x0, #3 << 20
msr cpacr_el1, x0 /* Enable FP/SIMD */
//使能EL1等级下的FP/SIMD,EL1-3是armv8架构下的特权等级,EL0为用户空间
0:
/*
* Enable SMPEN bit for coherency.
* This register is not architectural but at the moment
* this bit should be set for A53/A57/A72.
*/
#ifdef CONFIG_ARMV8_SET_SMPEN
switch_el x1, 3f, 1f, 1f
3:
mrs x0, S3_1_c15_c2_1 /* cpuectlr_el1 */
orr x0, x0, #0x40
msr S3_1_c15_c2_1, x0
1:
#endif
/* Apply ARM core specific erratas */
bl apply_core_errata
/*
* 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
#if defined(CONFIG_ARMV8_SPIN_TABLE) && !defined(CONFIG_SPL_BUILD)
branch_if_master x0, x1, master_cpu
b spin_table_secondary_jump
/* never return */
#elif defined(CONFIG_ARMV8_MULTIENTRY)
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 */
#endif /* CONFIG_ARMV8_MULTIENTRY */
master_cpu:
bl _main
//调用main函数,本文件执行结束
#ifdef CONFIG_SYS_RESET_SCTRL
reset_sctrl:
switch_el x1, 3f, 2f, 1f
3:
mrs x0, sctlr_el3
b 0f
2:
mrs x0, sctlr_el2
b 0f
1:
mrs x0, sctlr_el1
0:
ldr x1, =0xfdfffffa
and x0, x0, x1
switch_el x1, 6f, 5f, 4f
6:
msr sctlr_el3, x0
b 7f
5:
msr sctlr_el2, x0
b 7f
4:
msr sctlr_el1, x0
7:
dsb sy
isb
b __asm_invalidate_tlb_all
ret
#endif
/*-----------------------------------------------------------------------*/
WEAK(apply_core_errata)
mov x29, lr /* Save LR */
/* For now, we support Cortex-A57 specific errata only */
/* Check if we are running on a Cortex-A57 core */
branch_if_a57_core x0, apply_a57_core_errata
//branch_if_a57_core在arch/arm/include/asm/macro.h中定义,根据核初始化一些寄存器
0:
mov lr, x29 /* Restore LR */
ret
//返回caller,继续往下执行
apply_a57_core_errata:
#ifdef CONFIG_ARM_ERRATA_828024
mrs x0, S3_1_c15_c2_0 /* cpuactlr_el1 */
/* Disable non-allocate hint of w-b-n-a memory type */
orr x0, x0, #1 << 49
/* Disable write streaming no L1-allocate threshold */
orr x0, x0, #3 << 25
/* Disable write streaming no-allocate threshold */
orr x0, x0, #3 << 27
msr S3_1_c15_c2_0, x0 /* cpuactlr_el1 */
#endif
#ifdef CONFIG_ARM_ERRATA_826974
mrs x0, S3_1_c15_c2_0 /* cpuactlr_el1 */
/* Disable speculative load execution ahead of a DMB */
orr x0, x0, #1 << 59
msr S3_1_c15_c2_0, x0 /* cpuactlr_el1 */
#endif
#ifdef CONFIG_ARM_ERRATA_833471
mrs x0, S3_1_c15_c2_0 /* cpuactlr_el1 */
/* FPSCR write flush.
* Note that in some cases where a flush is unnecessary this
could impact performance. */
orr x0, x0, #1 << 38
msr S3_1_c15_c2_0, x0 /* cpuactlr_el1 */
#endif
#ifdef CONFIG_ARM_ERRATA_829520
mrs x0, S3_1_c15_c2_0 /* cpuactlr_el1 */
/* Disable Indirect Predictor bit will prevent this erratum
from occurring
* Note that in some cases where a flush is unnecessary this
could impact performance. */
orr x0, x0, #1 << 4
msr S3_1_c15_c2_0, x0 /* cpuactlr_el1 */
#endif
#ifdef CONFIG_ARM_ERRATA_833069
mrs x0, S3_1_c15_c2_0 /* cpuactlr_el1 */
/* Disable Enable Invalidates of BTB bit */
and x0, x0, #0xE
msr S3_1_c15_c2_0, x0 /* cpuactlr_el1 */
#endif
b 0b
//上述宏都没有定义,跳转到上面的标号0处
ENDPROC(apply_core_errata)
/*-----------------------------------------------------------------------*/
WEAK(lowlevel_init)
mov x29, lr /* Save LR */
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_IRQ)
branch_if_slave x0, 1f
ldr x0, =GICD_BASE
bl gic_init_secure
//调用gic_init_secure初始化主cpu的中断控制寄存器,x0是传入的参数
1:
#if defined(CONFIG_GICV3)
ldr x0, =GICR_BASE
bl gic_init_secure_percpu
#elif defined(CONFIG_GICV2)
ldr x0, =GICD_BASE
ldr x1, =GICC_BASE
bl gic_init_secure_percpu
//调用gic_init_secure_percpu初始化各个cpu的中断控制寄存器,x0 x1是传入的参数
#endif
#endif
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_IRQ)
/*
* Setting HCR_EL2.TGE AMO IMO FMO for exception rounting to EL2
*/
mrs x0, CurrentEL /* check currentEL */
cmp x0, 0x8
b.ne end /* currentEL != EL2 */
mrs x9, hcr_el2
orr x9, x9, #(7 << 3) /* HCR_EL2.AMO IMO FMO set */
orr x9, x9, #(1 << 27) /* HCR_EL2.TGE set */
msr hcr_el2, x9
//Hypervisor Configuration寄存器设置,并未处于LE2,不执行
end:
nop
#endif /* CONFIG_IRQ */
#ifdef CONFIG_ARMV8_MULTIENTRY
branch_if_master x0, x1, 2f
/*
* Slave should wait for master clearing spin table.
* This sync prevent salves observing incorrect
* value of spin table and jumping to wrong place.
*/
#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3)
#ifdef CONFIG_GICV2
ldr x0, =GICC_BASE
#endif
bl gic_wait_for_interrupt
#endif
/*
* All slaves will enter EL2 and optionally EL1.
*/
adr x4, lowlevel_in_el2
ldr x5, =ES_TO_AARCH64
bl armv8_switch_to_el2
lowlevel_in_el2:
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
adr x4, lowlevel_in_el1
ldr x5, =ES_TO_AARCH64
bl armv8_switch_to_el1
lowlevel_in_el1:
#endif
#endif /* CONFIG_ARMV8_MULTIENTRY */
2:
mov lr, x29 /* Restore LR */
ret
//返回caller,继续往下调用_main
ENDPROC(lowlevel_init)
WEAK(smp_kick_all_cpus)
/* Kick secondary cpus up by SGI 0 interrupt */
#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3)
ldr x0, =GICD_BASE
b gic_kick_secondary_cpus
#endif
ret
ENDPROC(smp_kick_all_cpus)
/*-----------------------------------------------------------------------*/
ENTRY(c_runtime_cpu_setup)
/* Relocate vBAR */
adr x0, vectors
switch_el x1, 3f, 2f, 1f
3: msr vbar_el3, x0
b 0f
2: msr vbar_el2, x0
b 0f
1: msr vbar_el1, x0
0:
ret
ENDPROC(c_runtime_cpu_setup)
WEAK(save_boot_params)
b save_boot_params_ret /* back to my caller */
ENDPROC(save_boot_params)
#endif
二:arch/arm/lib/crt0_64.S
#include
#include
#include
#include
ENTRY(_main)
#if defined(CONFIG_SPL_BUILD)
.equ SCTLR_A_BIT, (1 << 1)
.equ SCTLR_SA_BIT, (1 << 3)
.equ SCTLR_I_BIT, (1 << 12)
/*
* Enable the instruction cache, stack pointer
* and data access alignment checks
*/
mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
mrs x0, sctlr_el3
orr x0, x0, x1
msr sctlr_el3, x0
isb
/*
* Enable External Abort and SError
*/
msr daifclr, #4
#endif
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
#if defined(CONFIG_TPL_BUILD) && defined(CONFIG_TPL_NEEDS_SEPARATE_STACK)
ldr x0, =(CONFIG_TPL_STACK)
#elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr x0, =(CONFIG_SPL_STACK)
#else
ldr x0, =(CONFIG_SYS_INIT_SP_ADDR) //0x00400000
#endif
bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */
mov x0, sp //设置栈,需要16字节对齐
bl board_init_f_alloc_reserve
mov sp, x0
/* set up gd here, outside any C code */
mov x18, x0 //在SP上面分配了一块GLOBAL DATA
bl board_init_f_init_reserve
//将上面分配的一块global data区域初始化为0,并将其地址指针向高地址增加global data的大小
bl board_init_f_init_serial
//调用arch/arm/mach-rockchip/board.c里的board_init_f_init_serial函数完成串口初始化
mov x0, #0
bl board_init_f
//将0作为参数传入board_init_f函数,在common/board_f.c中。
board_init_f中调用initcall_run_list(init_sequence_f),init_sequence_f是个数组,里面是将要进行初始化的函数列表,完成一些前期的初始化工作,比如board相关的early的初始化board_early_init_f、环境变量初始化env_init、串口初始化的serial_init、I2C初始化init_func_i2c、设备树相关准备工作fdtdec_prepare_fdt、打印CPU信息print_cpuinfo、SDRAM初始化dram_init、计算重定位信息setup_reloc等
#if (defined(CONFIG_SPL_BUILD) && !defined(CONFIG_TPL_BUILD) && !defined(CONFIG_SPL_SKIP_RELOCATE)) || \
!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 */
//更新gd结构体
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
adr lr, relocation_return //重定位异常向量表
#if CONFIG_POSITION_INDEPENDENT
/* Add in link-vs-runtime offset */
adr x0, _start /* x0 <- Runtime value of _start */
ldr x9, _TEXT_BASE /* x9 <- Linked value of _start */
sub x9, x9, x0 /* x9 <- Run-vs-link offset */
add lr, lr, x9
#endif
/* 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 //code的重定位,在arch/arm/lib/relocate_64.S
#endif
relocation_return:
/*
* Set up final (full) environment
*/
bl c_runtime_cpu_setup /* still call old routine */
//该函数在start.S中,重定位异常向量表
#endif /* !CONFIG_SPL_BUILD */
#if defined(CONFIG_SPL_BUILD)
bl spl_relocate_stack_gd /* may return NULL */
/* set up gd here, outside any C code, if new stack is returned */
cmp x0, #0
csel x18, x0, x18, ne
/*
* Perform 'sp = (x0 != NULL) ? x0 : sp' while working
* around the constraint that conditional moves can not
* have 'sp' as an operand
*/
mov x1, sp
cmp x0, #0
csel x0, x0, x1, ne
mov sp, x0
#endif
// 清 BSS段
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 */
//board_init_r所在文件路径:u-boot/common/board_r.c。
与前面的board_init_f类似,board_init_r中调用 initcall_run_list(init_sequence_r),init_sequence_r是个数组, 里面是将要进行初始化的函数列表,又是一系列的初始化操作。初始化 数组列表最后一个成员是run_main_loop,将最终跳到主循环 main_loop。
/* NOTREACHED - board_init_r() does not return */
ENDPROC(_main)
附:aarch64寄存器说明
参考:https://blog.csdn.net/hceng_linux/article/details/89913950
https://blog.csdn.net/yanggx0929/article/details/88597294
http://www.wowotech.net/armv8a_arch/armv8-a_overview.html