文章目录
本系列使用u-boot版本为u-boot-2018.01;
一、U-Boot启动流程详解
通过前面分析上文:u-boot移植篇——了解u-boot的分析,我们可以从u-boot.lds链接脚本入手开始分析u-boot,入口点是_start,_start 在文件 arch/arm/lib/vectors.S 中有定义,节选源码如下:
.macro ARM_VECTORS
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
.endm
前期做了一些异常向量跳转的加载,当一个异常或中断发生时,CPU根据异常,在异常(中断)向量表中找到对应的异常向量,然后执行异常向量处的跳转指令,CPU跳转到对应的异常处理程序执行。复位异常向量的指令“ b reset”决定 u-boot 启动后将自动跳转到标号 reset 处执行。标号reset 在arch/arm/cpu/armv7/start.S中定义,节选代码如下:
.globl reset
.globl save_boot_params_ret
.type save_boot_params_ret,%function
#ifdef CONFIG_ARMV7_LPAE
.global switch_to_hypervisor_ret
#endif
reset:
/* Allow the board to save important registers */
b save_boot_params
save_boot_params_ret:
#ifdef CONFIG_ARMV7_LPAE
/*
* check for Hypervisor support
*/
mrc p15, 0, r0, c0, c1, 1 @ read ID_PFR1
and r0, r0, #CPUID_ARM_VIRT_MASK @ mask virtualization bits
cmp r0, #(1 << CPUID_ARM_VIRT_SHIFT)
beq switch_to_hypervisor
switch_to_hypervisor_ret:
#endif
/*
* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
* except if in HYP mode already
*/
mrs r0, cpsr
and r1, r0, #0x1f @ mask mode bits
teq r1, #0x1a @ test for HYP mode
bicne r0, r0, #0x1f @ clear all mode bits
orrne r0, r0, #0x13 @ set SVC mode
orr r0, r0, #0xc0 @ disable FIQ and IRQ
msr cpsr,r0
/*
* Setup vector:
* (OMAP4 spl TEXT_BASE is not 32 byte aligned.
* Continue to use ROM code vector only in OMAP4 spl)
*/
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTLR Register
bic r0, #CR_V @ V = 0
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTLR Register
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
#endif
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_cp15
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
bl cpu_init_crit
#endif
#endif
bl _main
/*************************************************************************
*
* void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3)
* __attribute__((weak));
*
* Stack pointer is not yet initialized at this moment
* Don't save anything to stack even if compiled with -O0
*
*************************************************************************/
ENTRY(save_boot_params)
b save_boot_params_ret @ back to my caller
ENDPROC(save_boot_params)
.weak save_boot_params
继续跳转save_boot_params_ret函数,save_boot_params_ret函数原型如下:
save_boot_params_ret:
#ifdef CONFIG_ARMV7_LPAE
/*
* check for Hypervisor support
*/
mrc p15, 0, r0, c0, c1, 1 @ read ID_PFR1
and r0, r0, #CPUID_ARM_VIRT_MASK @ mask virtualization bits
cmp r0, #(1 << CPUID_ARM_VIRT_SHIFT)
beq switch_to_hypervisor
switch_to_hypervisor_ret:
#endif
/*
* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
* except if in HYP mode already
*/
mrs r0, cpsr
and r1, r0, #0x1f @ mask mode bits
teq r1, #0x1a @ test for HYP mode
bicne r0, r0, #0x1f @ clear all mode bits
orrne r0, r0, #0x13 @ set SVC mode
orr r0, r0, #0xc0 @ disable FIQ and IRQ
msr cpsr,r0
这里涉及到一下基础寄存器的读取和配置,一般我们可以不做过于深入的理解,可以从注释可以了解大概做了什么工作,比如:
- 第16行,讲cpsr寄存器的内容保存到r0寄存器,cpsr寄存器是什么:CPSR也叫程序状态寄存器,CPSR中包含条件码标志、中断禁止位、当前处理器模式以及其他状态和控制信息;
- 第17行,讲读取到的r0的值与上立即数0x1f,再将结果保存到r1寄存器中,目的是取出cpsr的低5位,而cpsr的低5位刚好又是控制位,用于设置处理器的工作模式的,所以也可以根据上面节选源码的注释进行直接理解即可;
- 后面就不一一解读了,有兴趣的可以继续深入理解,这就进行模式判断,设置处理器进入超级管理模式SVC模式,然后关闭FIQ和IRQ两种中断;
- 继续回到arch/arm/cpu/armv7/start.S节选源码–reset
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTLR Register
bic r0, #CR_V @ V = 0
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTLR Register
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
#endif
这里涉及到一个宏,CONFIG_SPL_BUILD,如果启动CONFIG_SPL_BUILD宏,一般会生成两个uboot相关的文件,一个为MLO(引导uboot)也叫SPL(Secondary Program Loader 的简称, 也就是第二阶段程序加载器)用于初始化DDR内存并将uboot主体加载到内存中的,剩下一个就是uboot主体镜像,一般TI的芯片比如AM335x、AM572x等芯片会使用CONFIG_SPL_BUILD来编译,而我目前使用zynq好像一般用FSBL(first stage boot loader 第一阶段的加载程序)比较多,FSBL和SPL在功能上是类似的,不用过于纠结。
- 第3行,读取CP15协处理器中c1寄存器的值到r0,至于CP15协处理器是什么,大家自行补充,CP15东西太多,这里不喧宾夺主介绍一遍了;
- 第4行,CR_V有段定义
#define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */,这里主要将r0寄存器中的第13位清除,该位代表SCTLR寄存器的V位向量表控制位,清零表示软件可以重定位向量表; - 第5行,将清零了第13位的r0重写回CP15 SCTLR寄存器中;
- 第8行,设置 r0 寄存器的值为_start,_start就是整个uboot 的入口地址,其值为0x4000000,相当于uboot的起始地址,因此0x4000000也是向量表的起始地址;
- 第9行,将r0寄存器的值(向量表值)写入到CP15的c12寄存器中,也就是VBAR寄存器。所以这段程序的作用总的来说就是设置向量表重定位的。
Keep going

本文详细解析U-Boot启动过程,从_start入口点出发,深入探讨reset函数、_main函数及board_init_f函数等内容。文章重点分析了关键函数的作用及其执行流程。
最低0.47元/天 解锁文章
9256

被折叠的 条评论
为什么被折叠?



