4. U-Boot启动链总览
在嵌入式SoC上,上电后的第一条指令并不是U-Boot,而是固化在芯片内部ROM中的BootROM代码。BootROM负责最基础的时钟、引脚和存储控制器初始化,然后按预设顺序寻找可启动介质中的第一阶段引导程序。对于使用U-Boot的典型系统,这条链通常表现为:BootROM → TPL → SPL → U-Boot proper → Linux内核。理解每一级的职责、加载地址和传递参数,是板级调试和启动失败定位的基础。
一、每一级的职责边界
BootROM是芯片厂商固化的只读代码,它不依赖外部DDR,只使用片内SRAM。它的主要任务是:初始化最基本的时钟和启动引脚,然后根据BOOT_MODE引脚或eFUSE配置,从SD、eMMC、NAND、SPI NOR等介质中读取头部信息,验证签名或校验和,最后把TPL或SPL镜像搬到片内SRAM并跳转。
TPL(Tiny Program Loader)是可选的一级。当片内SRAM太小,无法容纳SPL时,TPL负责更小的初始化任务,典型场景是初始化DDR控制器并完成DDR训练,然后把SPL从存储介质搬到DDR中执行。很多SoC并不需要TPL,BootROM直接加载SPL即可。
SPL(Secondary Program Loader)是U-Boot编译产物中的第二阶段。它运行在片内SRAM或已初始化的DDR中,负责初始化DDR、时钟、串口和启动介质,然后从存储介质中读取完整的U-Boot proper镜像到DDR,并跳转到其入口。SPL通常不包含命令行和完整驱动,体积被严格限制。
U-Boot proper是用户最熟悉的完整U-Boot。它拥有完整的驱动模型、命令行、环境变量、网络和文件系统支持。它的核心任务是为内核准备启动环境:加载内核镜像、设备树和可选的initrd,设置bootargs,最后通过bootm、booti或bootz命令跳转到内核入口。
二、镜像加载与地址传递流程
启动链的每一级都遵循“加载—校验—跳转”的模式。以典型ARM64 SoC为例,BootROM从eMMC的0x40偏移读取SPL头部,校验通过后加载到0x20000000附近的SRAM;SPL运行后初始化DDR,从eMMC的0x100000偏移读取u-boot.img到0x40000000;U-Boot proper运行后从eMMC的0x2000000偏移读取Image和DTB到0x48000000和0x4A000000,最后执行booti。
# 典型启动日志片段
BootROM: loading SPL from eMMC offset 0x40
SPL: DDR init done, loading U-Boot proper from offset 0x100000
U-Boot 2024.01: board_init_r, DRAM: 2 GiB
Loading kernel from mmc 0:1 ...
Loading DTB from mmc 0:1 ...
Starting kernel at 0x48080000 ...
参数传递方面,SPL会把自己的全局数据结构gd和已初始化的设备树地址传给U-Boot proper;U-Boot proper则通过bootargs环境变量和设备树/chosen节点把内存布局、控制台、根文件系统信息传给内核。如果中间任何一级校验失败,BootROM会按启动顺序尝试下一个介质,SPL也可能回退到USB或串口下载模式。
三、典型场景与板级调试切入点
在板级调试中,启动链的每一级都有明确的观察点。BootROM阶段通常没有串口输出,只能通过测量启动引脚、读取eFUSE或使用厂商工具确认。TPL和SPL阶段可以通过串口打印确认DDR训练是否成功、镜像偏移是否正确。U-Boot proper阶段则可以通过命令行检查环境变量、存储设备和内核加载地址。
| 阶段 | 运行位置 | 关键任务 | 常见故障 | 调试手段 |
|---|---|---|---|---|
| BootROM | 片内ROM | 时钟/引脚初始化、介质选择 | 启动引脚错误、eFUSE配置错误 | 测量引脚、厂商下载工具 |
| TPL | 片内SRAM | DDR训练、加载SPL | DDR参数错误、镜像偏移错误 | 串口日志、示波器测DDR |
| SPL | SRAM/DDR | DDR初始化、加载U-Boot proper | DDR不稳定、存储读取失败 | SPL串口打印、mmc命令 |
| U-Boot proper | DDR | 驱动初始化、加载内核 | 环境变量错误、内核地址冲突 | 命令行、printenv、bdinfo |
| 内核 | DDR | 解压、启动、挂载根文件系统 | bootargs错误、DTB不匹配 | earlycon、内核日志 |
四、常见误区与复盘要点
掌握这条完整传递关系后,再看具体的BOOT_MODE配置、SPL编译选项、U-Boot环境变量和bootm流程,就能把每个配置项映射到启动链的某一级,从而快速缩小问题范围。启动链的本质不是“一堆镜像的堆叠”,而是每一级在资源受限条件下完成最小必要初始化,并把执行权和关键参数可靠地交给下一级。