u-boot版本,u-boot-2016.11
硬件环境, HI3559av100
u-boot系统启动流程分为stage1和stage2两部分,stage1是依赖于CPU体系结构的代码。通常stage1用汇编语言来实现,stage2则用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。
有个小技巧可以快速确定.globl _start 等一些全局变量的地址,那就是反编译u-boot文件。因为这些个地址都是链接脚本(.lds文件)指定,看代码时不好确定其地址,等它编译出来,反编译出来就很清楚了。同时结合System.map、u-boot.map、u-boot.sym文件来看,就比较清晰了。
.lds文件中指定了入口、定义了各个SECTIONS,如常见的.text、.rodata、.data,另外大部分,都是不常见的。
反编译命令:
aarch64-himix100-linux-objdump -SD u-boot > /home/share/work/uboot0819.s
/*
* u-boot-2016.11/arch/arm/cpu/armv8/start.S
*/
/*
* (C) Copyright 2013
* David Feng
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include
#include
#include
#include
#include
/*************************************************************************
*
* Startup Code (reset vector)
*
*************************************************************************/
.globl _start /* u-boot启动入口, _start's address value 0000000048800000 */
_start:
b reset /* 跳转到reset */
#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
ARM_SOC_BOOT0_HOOK
#endif
.align 3
.globl _TEXT_BASE /* _TEXT_BASE's address value 0000000048800008 */
_TEXT_BASE:
.quad CONFIG_SYS_TEXT_BASE /* 0x48800000 */
/*
* These are defined in the linker script.
*/
.globl _end_ofs /* _end_ofs's address value 0000000048800010 */
_end_ofs:
.quad _end - _start /* 00000000488afa58 - 0000000048800000 = 0x000afa58 */
.globl _bss_start_ofs /* _bss_start_ofs's address value 0000000048800018 */
_bss_start_ofs:
.quad __bss_start - _start /* 00000000488afa58 - 0000000048800000 = 0x000afa58 */
.globl _bss_end_ofs /* _bss_end_ofs's address value 0000000048800020 */
_bss_end_ofs:
.quad __bss_end - _start /* 0000000048906758 - 0000000048800000 = 0x106758 */
reset: /* reset's address value 0000000048800028 */
/* Allow the board to save important registers */
b save_boot_params
.globl save_boot_params_ret
save_boot_params_ret:
#ifdef CONFIG_SYS_RESET_SCTRL
bl reset_sctrl
#endif
/*
* Could be EL3/EL2/EL1, Initial State: // Defines the ARMv8 Exception model, with up to four Exception levels, EL0 - EL3, that
// provide an execution privilege hierarchy. OS(EL1), Hypervisor (EL2), Secure Monitor (EL3)
* Little Endian, MMU Disabled, i/dCache Disabled
*/
adr x0, vectors /* exceptions.S */
switch_el x1, 3f, 2f, 1f /* 汇编宏,按异常级别选择下面3、2、1、0的分支, macro.h */
3: msr vbar_el3, x0 /* Vector Base Address Register (EL3) */
mrs x0, scr_el3 /* Secure Configuration Register */
orr x0, x0, #0xf /* SCR_EL3.NS|IRQ|FIQ|EA */
msr scr_el3, x0
msr cptr_el3, xzr /* Enable FP/SIMD , Architectural Feature Trap Register (EL3) */
#ifdef COUNTER_FREQUENCY
ldr x0, =COUNTER_FREQUENCY /* 0x1800000 */
msr cntfrq_el0, x0 /* Initialize CNTFRQ. Counter-timer Frequency register */
#endif
b 0f
2: msr vbar_el2, x0 /* Vector Base Address Register (EL2) */
mov x0, #0x33ff
msr cptr_el2, x0 /* Enable FP/SIMD. Architectural Feature Trap Register (EL2) */
b 0f
1: msr vbar_el1, x0 /* ector Base Address Register (EL1) */
mov x0, #3 << 20
msr cpacr_el1, x0 /* Enable FP/SIMD. Architectural Feature Trap Register (EL1) */
0:
/* Apply ARM core specific erratas */
bl apply_core_errata /* WEAK函数, 本文件实现 */
/*
* 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 CONFIG_IS_ENABLED(ARMV8_SPIN_TABLE) /* 无定义,不执行 */
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 /* crt0_64.S */
#ifdef CONFIG_SYS_RESET_SCTRL /* 无定义,不执行 */
reset_sctrl:
switch_el x1, 3f, 2f, 1f
3:
mrs x0, sctlr_el3 /* system Control Register (EL3), save x0 */
b 0f
2:
mrs x0, sctlr_el2 /* system Control Register (EL2), save x0 */
b 0f
1:
mrs x0, sctlr_el1 /* system Control Register (EL1), save x0 */
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 /* macro.h, 如果当前处理器是Cortex-A57内核,则进行分支 */
0:
mov lr, x29 /* Restore LR */
ret
apply_a57_core_errata: /* 如果是Cortex-A57 MPCore processor, 由上面 branch_if_a57_core 判断是后调用 */
#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
ENDPROC(apply_core_errata)
/*-----------------------------------------------------------------------*/
WEAK(lowlevel_init) /* 底层初始化 */
mov x29, lr /* Save LR */
#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3) /* 无定义,不执行 */
branch_if_slave x0, 1f
ldr x0, =GICD_BASE
bl gic_init_secure
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
#endif
#endif
#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.
*/
bl armv8_switch_to_el2 /* transition.S */
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
bl armv8_switch_to_el1
#endif
#endif /* CONFIG_ARMV8_MULTIENTRY */
2:
mov lr, x29 /* Restore LR */
ret
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 /* 按异常级别选择分支后把vectors赋给vbar_elX */
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)
从start.S调转至crt0_64.S
/*
* u-boot-2016.11/arch/arm/lib/crt0_64.S
*/
#include
#include
#include
#include
ENTRY(_main)
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) /* 无定义,不执行 */
ldr x0, =(CONFIG_SPL_STACK)
#else
ldr x0, =(CONFIG_SYS_INIT_SP_ADDR) /* 0x08004000 , 系统初始化堆栈地址 */
#endif
bic sp, x0, #0xf /* 16-byte alignment for ABI compliance, 符合ABI的16字节对齐 */
mov x0, sp
bl board_init_f_alloc_reserve /* 减掉CONFIG_SYS_MALLOC_F_LEN,再减掉sizeof(struct global_data)并16字节对齐后生成一个新的堆栈地址 */
mov sp, x0 /* x0 为新的堆栈地址 */
/* set up gd here, outside any C code 在这里设置gd,在任何C代码之外 */
mov x18, x0 /* x18 = x0, register volatile gd_t *gd asm ("x18") */
bl board_init_f_init_reserve /* 初始化保留空间(已从C运行时环境处理代码安全地分配到C堆栈上) */
mov x0, #0
bl 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.
*/
/*
* 设置中间环境(新的sp和gd)并调用relocate_code(addr_moni)。这里的诀窍是我们将返回"这里",但重新安置。
*/
ldr x0, [x18, #GD_START_ADDR_SP] /* x0 <- gd->start_addr_sp */ /* #GD_START_ADDR_SP=120 */
bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */
ldr x18, [x18, #GD_BD] /* x18 <- gd->bd */ /* #GD_BD=0 */
sub x18, x18, #GD_SIZE /* new GD is below bd */ /* #GD_SIZE=360 */
adr lr, relocation_return
ldr x0, [x18, #GD_RELOCADDR] /* x0 <- gd->relocaddr */ /* GD_RELOCADDR=88 */
adr x9, _start
sub x9, x0, x9 /* x9 <- gd->reloc_off */
add lr, lr, x9 /* new return address after relocation */
b relocate_code /* relocate_64.S */
relocation_return:
/*
* Set up final (full) environment
*/
bl c_runtime_cpu_setup /* still call old routine */
#endif /* !CONFIG_SPL_BUILD */
/* TODO: For SPL, call spl_relocate_stack_gd() to alloc stack relocation */
/*
* 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] /* _bss_start = 0 */
add x0, x0, #8 /* _bss_start += 8 */
cmp x0, x1 /* __bss_start ?= __bss_end */
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 */ /* run_main_loop */
/* NOTREACHED - board_init_r() does not return */
ENDPROC(_main)
调用 board_init_r 后,uboot开始死循环,已经准备好启动命令了。