1. U-Boot启动流程源码分析

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_f
  • common/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控制台。

启动流程图

阶段一:汇编阶段(vectors.S / start.S / crt0.S) 阶段二:前初始化(board_init_f) 阶段三:后初始化(board_init_r) 阶段四:主循环(main_loop) CPU上电 → _start(复位向量) 设置SVC模式 / 关中断 / 关MMU _main:建栈 → 预留gd → 清BSS board_init_f() init_sequence_f[] 顺序执行 计算重定位地址 / 预留内存池 relocate_code / 更新gd指针 board_init_r() init_sequence_r[] 顺序执行 驱动初始化 / 环境变量加载 run_main_loop() main_loop() bootdelay 超时? 是 bootm 引导内核 否 命令行交互(控制台)

验证方法

在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>提示符,则进一步确认命令行主循环正常工作。