基于rockchip-px30平台arm v8架构下uboot启动分析

 

 

 

一:arch/arm/cpu/armv8/start.S

蓝色标注的是实际执行的代码片段,红色为注释

#include <asm-offsets.h>

#include <config.h>

#include <linux/linkage.h>

#include <asm/macro.h>

#include <asm/armv8/mmu.h>

 

.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 <asm/arch/boot0.h>

#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/SIMDEL1-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 <config.h>

#include <asm-offsets.h>

#include <asm/macro.h>

#include <linux/linkage.h>

 

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

 

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值