u-boot在汇编启动阶段的相关操作介绍

描述

u-boot在汇编启动阶段对系统的一些初始化

当cpu交由u-boot接管进入u-boot后, 首先会到_start符号处开始执行初始化, 并在此期间完成一些必要的系统寄存器相关的初始化,包括保存boot参数, 进行地址无关fixed,系统寄存器复位,底层平台相关初始化等 ,启动代码位于arch/arm/cpu/armv8/start.S,入口地址为_start。

启动前为后续流程做的一些平台相关操作

从_start开始,u-boot会根据board定义做一些平台化相关的初始化工作或者是保存一些重要寄存器信息,代码如下:

/*************************************************************************
 *
 * Startup Code (reset vector)
 *
 *************************************************************************/

.globl _start
_start: ------------------------------------------------------------------------ (1)
#if defined(CONFIG_LINUX_KERNEL_IMAGE_HEADER) ---------------------------------- (2)
#include < asm/boot0-linux-kernel-header.h >
#elif defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK) -------------------------------- (3)
/*
 * 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 ----------------------------------------------------------------- (4)
#endif

    .align 3

.globl _TEXT_BASE ------------------------------------------------------------ (5)
_TEXT_BASE:
    .quad CONFIG_SYS_TEXT_BASE

/*
 * These are defined in the linker script.
 */
.globl _end_ofs -------------------------------------------------------------- (5)
_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 ----------------------------------------------------- (6)
.globl save_boot_params_ret
save_boot_params_ret:

... /* 此处省略无关代码,待分析到时再展开代码 */
...
WEAK(save_boot_params)
    b save_boot_params_ret /* back to my caller */
ENDPROC(save_boot_params)

#endif
  • • (1)_start段标记为全局可见并在链接脚本中被声明为入口地址,表示u-boot的入口地址为_start;
  • • (2)首先进入入口后有两种可配置情况,一种就是定义了LINUX_KERNEL_IMAGE_HEADER,boot0-linux-kernel-header.h展开部分后如下:
.macro le64sym, sym
    .long sym()_lo32
    .long sym()_hi32
    .endm

.globl _start
_start:
    /*
     * DO NOT MODIFY. Image header expected by Linux boot-loaders.
     */
    b reset    /* branch to kernel start, magic */
    .long 0    /* reserved */
    le64sym _kernel_offset_le  /* Image load offset from start of RAM, little-endian */
    le64sym _kernel_size_le   /* Effective size of kernel image, little-endian */
    le64sym _kernel_flags_le  /* Informative flags, little-endian */
    .quad 0    /* reserved */
    .quad 0    /* reserved */
    .quad 0    /* reserved */
    .ascii "ARMx64"   /* Magic number */
    .long 0    /* reserved */

此处将与在链接脚本中定义的LINUX_KERNEL_IMAGE_HEADER对应起来,为u-boot头部添加一个类似与Linux arm64 的Image头部,首先是起始8字节, 如果没有定义efi相关的功能则是一个跳转指令,跳转到reset段继续执行启动流程 ,其他如链接脚本中解释一致;

  • • (3)第二种可能的配置,就是定义了ENABLE_ARM_SOC_BOOT0_HOOK配置,此处的头文件根据不同board会引用到不同头文件,如瑞芯微的最终会引用到如下部分代码头文件:
#ifdef CONFIG_SPL_BUILD
    /*
     * We need to add 4 bytes of space for the 'RK33' at the
     * beginning of the executable.  However, as we want to keep
     * this generic and make it applicable to builds that are like
     * the RK3368 (TPL needs this, SPL doesn't) or the RK3399 (no
     * TPL, but extra space needed in the SPL), we simply insert
     * a branch-to-next-instruction-word with the expectation that
     * the first one may be overwritten, if this is the first stage
     * contained in the final image created with mkimage)...
     */
    b 1f  /* if overwritten, entry-address is at the next word */
1:
#endif
#if CONFIG_IS_ENABLED(ROCKCHIP_EARLYRETURN_TO_BROM)
    adr     r3, entry_counter
    ldr r0, [r3]
    cmp r0, #1           /* check if entry_counter == 1 */
    beq reset            /* regular bootup */
    add     r0, #1
    str r0, [r3]         /* increment the entry_counter in memory */
    mov     r0, #0           /* return 0 to the BROM to signal 'OK' */
    bx lr               /* return control to the BROM */
entry_counter:
    .word   0
#endif

#if (defined(CONFIG_SPL_BUILD) || defined(CONFIG_ARM64))
    /* U-Boot proper of armv7 do not need this */
    b reset
#endif

#if !defined(CONFIG_ARM64)
    /*
     * For armv7, the addr '_start' will used as vector start address
     * and write to VBAR register, which needs to aligned to 0x20.
     */
    .align(5), 0x0
_start:
    ARM_VECTORS
#endif

#if !defined(CONFIG_TPL_BUILD) && defined(CONFIG_SPL_BUILD) && 
    (CONFIG_ROCKCHIP_SPL_RESERVE_IRAM > 0)
    .space CONFIG_ROCKCHIP_SPL_RESERVE_IRAM /* space for the ATF data */
#endif

因为有些设备boot到u-boot之前已经有安全固件了,

所以此时控制权交给u-boot时,其实是可能有一些传递参数信息的要求,比如这里瑞芯微芯片通过bootrom boot到tpl后,

后续在完成tpl初始化后会将控制权再交还给bootrom固件,由bootrom固件继续加载spl,

所以这里在进行u-boot流程之前保存了bootrom的返回地址,以便后续瑞芯微板级软件使用。

定义有可能也是arm32的模式,所以还可能在入口地址处保存异常向量表;

  • • (4)如果对应board没有上述两种需求,那么_start段则是一条最简单的跳转指令b reset跳转到reset处继续启动流程初始化;
  • • (5)在_start到reset之间,有一个.align 3用于8字节对齐,因为可能在读取常量地址之前各自平台做了自己代码逻辑导致当前地址并不是8字节对齐的, 这里不管是否对齐都强制对齐了一下,之后还保存了一些常量信息,其中包括_TEXT_BASE保存了链接地址,用于在启动地址无关功能时进行对运行时地址的偏移计算,其他几个偏移值目前未使用;
  • • (6)save_boot_params用于保存一些board相关的重要寄存器,此处定义为了一个弱函数,为直接跳转回save_boot_params_ret继续往下执行,如果某些board需要保存寄存器参数则可以在自己的lowlevel.S文件中实现此函数。 一般由atf,bl2或者rom跳转到spl或u-boot时厂商可能需要在两个固件之间传递参数,比如由bl2在寄存器x0,x1,x2中分别存入了一些固件的地址信息,那么u-boot则可以在早期通过此函数保存这些信息,并在后续某个时机中使用。
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分