1. U-Boot启动流程源码分析
任务目标
通过阅读U-Boot源码中arch/arm/lib/vectors.S(或arch/arm/cpu/armv7/start.S)、common/board_f.c和common/board_r.c,梳理U-Boot从复位向量到主循环的完整启动流程,理解各阶段的核心职责,并绘制一张准确的启动流程图。
源码版本与准备
本案例基于U-Boot v2023.04(ARMv7架构,以vexpress_qemu_defconfig为例)。先获取源码并建立索引:
git clone https://github.com/u-boot/u-boot.git
cd u-boot
git checkout v2023.04
make vexpress_qemu_defconfig
关键文件路径:
arch/arm/lib/vectors.S— 异常向量表,复位入口arch/arm/cpu/armv7/start.S— 早期CPU初始化(仅ARMv7)arch/arm/lib/crt0.S— C运行环境建立,调用board_init_fcommon/board_f.c— 板级前初始化(init_sequence_f)common/board_r.c— 板级后初始化(init_sequence_r),进入主循环common/main.c— main_loop()主循环
启动流程源码梳理
U-Boot启动分为三个阶段:汇编阶段(复位向量→重定位前)、C语言前初始化阶段(board_init_f)、C语言后初始化阶段(board_init_r→主循环)。
1. 复位入口(vectors.S)
CPU上电后从_start(复位向量)执行,代码先设置为SVC模式并关闭中断,然后跳转reset。关键代码如下:
.section .vectors, "ax"
.globl _start
_start:
ARM_VECTORS
reset:
/* 设置SVC模式,关闭IRQ/FIQ */
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
/* 关闭MMU与缓存 */
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x0005
mcr p15, 0, r0, c1, c0, 0
/* 跳转到crt0.S中的_main */
b _main
2. C运行环境建立(crt0.S)
_main依次完成:为早期栈分配空间→调用board_init_f_alloc_reserve→调用board_init_f_init_reserve→调用board_init_f→重定位代码→设置重定位后的栈→清除BSS→跳转board_init_r。核心调用序列:
_main:
/* 设置初始栈(CONFIG_SYS_INIT_SP_ADDR) */
ldr sp, =CONFIG_SYS_INIT_SP_ADDR
/* 预留早期malloc区域与全局数据gd */
bl board_init_f_alloc_reserve
/* 初始化gd与早期malloc */
bl board_init_f_init_reserve
/* 前初始化:执行init_sequence_f[] */
bl board_init_f
/* 代码重定位 */
bl relocate_code
/* 重定位后设置新栈 */
bl relocate_vectors
/* 清除BSS段 */
ldr r0, =__bss_start
ldr r1, =__bss_end
bl __bss_clear
/* 跳转到后初始化 */
bl board_init_r
3. board_init_f(board_f.c)
init_sequence_f[]数组按顺序执行约30个初始化函数,核心包括:setup_machine(保存机器ID)、setup_dest_addr(计算重定位地址)、reserve_global_data(预留gd空间)、reserve_malloc(预留malloc池)、reserve_board(预留板级数据)、setup_bd_t(初始化bd信息)、display_new_sp(打印栈指针)。该阶段不访问全局变量(gd除外),因为代码尚未重定位。
4. board_init_r(board_r.c)
重定位完成后,init_sequence_r[]执行后初始化:initr_malloc(启用完整malloc)、initr_reloc_global_data(修正gd指针)、initr_mem(显示内存信息)、initr_mmc/initr_net(驱动初始化)、initr_env(加载环境变量)、initr_jumptable(建立跳转表)、最后调用run_main_loop进入主循环。
5. main_loop(common/main.c)
main_loop()执行启动延迟检查(bootdelay),若倒计时内无按键中断则执行bootm(引导内核);否则进入run_command_list处理命令行交互,即U-Boot控制台。
启动流程图
验证方法
在QEMU中运行以观察启动日志,确认流程节点:
make vexpress_qemu_defconfig
make -j4
qemu-system-arm -M vexpress-a9 -m 256M -nographic -kernel u-boot
通过判定标准:串口输出依次出现以下关键日志即证明启动流程正确:
U-Boot 2023.04— 进入board_init_f前的版本打印DRAM: 256 MiB— board_init_f中DRAM检测完成relocation Offset is: ...— 重定位完成(board_init_f→board_init_r过渡)MMC: .../Net: ...— board_init_r中驱动初始化Hit any key to stop autoboot— 进入main_loop,启动流程闭环
若在倒计时内按下任意键进入U-Boot>提示符,则进一步确认命令行主循环正常工作。