uboot启动阶段分析二

    xiaoxiao2025-08-21  11

    物理基址定义

    _TEXT_PHY_BASE: .word CFG_PHY_UBOOT_BASE

    start.s 中使用 _TEXT_PHY_BASE 存放物理基址。这个变量很重要,因为我们在 u-boot 中使用 MMU ,在 MMU 没有开启之前,需要这个变量来保证程序能在正确的地址运行

    通过在 u-boot 源码中全局搜索可以发现, CFG_PHY_UBOOT_BASE 定义在 uboot/include/configs/x210_sd.h 中

    #define MEMORY_BASE_ADDRESS 0x30000000 ... #define CFG_PHY_UBOOT_BASE MEMORY_BASE_ADDRESS + 0x3e00000

    CFG_PHY_UBOOT_BASE 这个宏是在 MEMORY_BASE_ADDRESS 的位置上偏移了 0x3e00000 的空间

    链接脚本需要的变量

    .globl _bss_start _bss_start: .word __bss_start .globl _bss_end _bss_end: .word _end

    _bss_start _bss_end 这两个变量之前也在链接脚本中见过

    BSS 段通常是指用来存放程序中未初始化的或者初始化为0的全局变量和静态变量的一块内存区域

    BSS 段使用前需要清0,通过在这里提供 BSS 段的地址,方便链接时清0

    复位

    reset: /* * set the cpu to SVC32 mode and IRQ & FIQ disable */ @;mrs r0,cpsr @;bic r0,r0,#0x1f @;orr r0,r0,#0xd3 @;msr cpsr,r0 msr cpsr_c, #0xd3 @ I & F disable, Mode: 0x13 - SVC

    到这里就是 u-boot 真正的复位代码了

    MSR 指令用亍将操作数的内容传送到程序状态寄存器的特定域中

    cpsr 是 ARM 架构的当前程序状态寄存器,而 cpsr_c 是程序状态寄存器的后8位,也就是控制位

    cpsr 寄存器的描述如下

    I 和 F 位对应的是 IRQ 和 FIQ 中断的标志位,置1为关闭

    因为模式位是前5位控制的,所以 0xd3 相当于 0x13,对应的就是 SVC(管理)模式

    再加上代码中的注释,我们就可以知道这段代码的作用就是让处理器进入 SVC 模式并关闭中断

    cpu_init_crit

    这里是为了初始化一些重要的寄存器和内存的时钟

    cpu_init_crit 只会在重启的时候运行,当 u-boot 在 ram 中的时候不会运行

    这部分做了这些事

    重新初始化开启 L2 cache刷新 L1 的数据和指令 cache关闭 MMU读取启动介质选择

    ## 读取启动信息

    ldr r0, =PRO_ID_BASE @ PRO_ID_BASE=E000 0000 ldr r1, [r0,#OMR_OFFSET] @ OMR_OFFSET=0000 0004 bic r2, r1, #0xffffffc1

    这段代码目的是从 E000 0004 这个寄存器读取电平信息,这个寄存器是 OM 引脚的地址。通过设置 OM 引脚的电平,就可以设置 u-boot 的启动介质

    bic 的作用是为了清除无关的位,方便后面进行启动介质的判断

    /* NAND BOOT */ cmp r2, #0x0 @ 512B 4-cycle moveq r3, #BOOT_NAND ... /* SD/MMC BOOT */ cmp r2, #0xc moveq r3, #BOOT_MMCSD /* NOR BOOT */ cmp r2, #0x14 moveq r3, #BOOT_NOR

    通过判断前面存入 r2 的值,得到不同的启动介质的信息

    lowlevel_init

    ldr sp, =0xd0036000 /* end of sram dedicated to u-boot */ sub sp, sp, #12 /* set stack */ mov fp, #0 bl lowlevel_init /* go setup pll,mux,memory */

    从图中可以看出 0xd0036000 是 sram 的地址空间,此时 ddr 还没有初始化完成,只能使用不需要初始化的 sram

    通过 sub 创建了一个 stack,再让 fp(栈帧指针)指向 stack 的开头(fp 用作栈的开头,sp 作为栈的当前位置,fp 和 sp 一起组成了一个栈帧)

    设置 stack 是为了用来存储 LR 的值,因为当前是被调用的子函数中, LR 中存储着当前子函数的范围地址,如果直接使用 bl 调用子函数,就会丢失当前子函数的返回地址

    所以在子函数中调用子函数时,需要先将当前的 LR 压栈

    后记

    关于 SP FP PC LR 寄存器有空会说说的,我也是在学习汇编才接触到这些寄存器,也是在看了些资料才稍微了解了些


    个人博客 公众号:greedyhao

    最新回复(0)