文章目录
以下是基于 U-Boot 源码的详细执行流程分析(以 ARMv7 架构为例,结合 U-Boot 2023.04 版本源码)。由于篇幅限制,我会聚焦关键代码段并解释其逻辑,但会覆盖所有核心阶段。
1. 启动入口(_start)
文件: arch/arm/lib/vectors.S
功能: 定义 CPU 的异常向量表和初始跳转。
/* arch/arm/lib/vectors.S */
.globl _start
_start:
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
- 关键点:
- 所有 ARM 异常向量(Reset、Undef、IRQ 等)在此定义。
- 复位后执行第一条指令
b reset
,跳转到reset
标签。
2. 低级初始化(reset)
文件: arch/arm/cpu/armv7/start.S
功能: 关闭 MMU/Cache、初始化关键硬件、设置栈、跳转到 C 环境。
2.1 关闭 MMU 和 Cache
reset:
/* 关闭 MMU 和 Cache */
mrc p15, 0, r0, c1, c0, 0 @ 读取 CP15 控制寄存器 (SCTLR)
bic r0, r0, #0x00002000 @ 关闭指令 Cache (bit 12)
bic r0, r0, #0x00000005 @ 关闭数据和 MMU (bits 0, 2)
mcr p15, 0, r0, c1, c0, 0 @ 写回 SCTLR
2.2 设置 CPU 模式和栈
/* 进入 SVC 模式并设置栈 */
msr cpsr_c, #0x13 @ SVC 模式, 关闭中断 (IRQ 和 FIQ)
ldr sp, =CONFIG_SYS_INIT_SP_ADDR @ 初始化栈地址(通常在链接脚本定义)
2.3 调用板级初始化 lowlevel_init
/* 执行板级特定初始化 */
bl lowlevel_init @ 跳转到板级 lowlevel_init(时钟、DDR 等)
文件: arch/arm/cpu/armv7/lowlevel_init.S
或板级自定义文件
示例(简化版):
ENTRY(lowlevel_init)
/* 初始化时钟 */
ldr r0, =0x12345678 @ 时钟控制寄存器地址
ldr r1, =0xABCD @ 配置值
str r1, [r0]
/* 初始化 DDR 控制器 */
ldr r0, =0xDEADBEEF @ DDR 控制器基地址
ldr r1, =0x5A5A @ 配置参数
str r1, [r0, #0x10] @ 写入时序寄存器
bx lr @ 返回
ENDPROC(lowlevel_init)
2.4 重定位 U-Boot 到 RAM
功能:是重定位的 物理基础(代码复制到 RAM),确保后续代码能运行
/* 检查是否需要重定位 */
ldr r0, =_start @ 当前代码地址(通常为 ROM/Flash 地址)
ldr r1, =CONFIG_SYS_TEXT_BASE @ 目标地址(RAM 地址)
cmp r0, r1
beq skip_relocate @ 如果已在 RAM 中,跳过重定位
/* 复制代码到 RAM */
ldr r2, =_end @ 代码结束地址
sub r2, r2, r0 @ 计算代码长度
mov r4, r1 @ 目标地址
bl copy_code @ 调用复制函数
copy_code:
ldr r3, [r0], #4 @ 从源地址读取 4 字节
str r3, [r4], #4 @ 写入目标地址
subs r2, r2, #4 @ 长度减 4
bgt copy_code @ 循环直到复制完成
skip_relocate:
/* 重定位完成后跳转到 RAM 中的地址 */
ldr pc, =after_relocation @ 强制跳转到 RAM 中的代码
3. C 语言环境初始化(board_init_f)
文件: common/board_f.c
功能: 初始化全局数据结构 gd
,执行一系列硬件初始化。
3.1 全局数据结构 gd
初始化
/* 定义全局数据指针 */
DECLARE_GLOBAL_DATA_PTR; // 实际为 register volatile gd_t *gd asm ("r9")
void board_init_f(ulong boot_flags)
{
/* 初始化 gd 结构体 */
gd = (gd_t *)CONFIG_SYS_INIT_SP_ADDR; // 通常栈顶预留空间给 gd
memset(gd, 0, sizeof(gd_t));
/* 填充 gd 的初始值 */
gd->flags = boot_flags;
gd->baudrate = CONFIG_BAUDRATE;
/* 执行初始化序列 */
initcall_run_list(init_sequence_f);
}
3.2 初始化序列 init_sequence_f
定义(部分):
static const init_fnc_t init_sequence_f[] = {
setup_mon_len, /* 计算 U-Boot 代码长度 */
initf_malloc, /* 初始化早期内存分配器 */
arch_cpu_init, /* 架构相关初始化(如缓存) */
mach_cpu_init, /* 芯片特定初始化 */
initf_dm, /* 初始化设备模型 */
board_e