2. u-boot启动流程概览:从ROM代码到SPL再到u-boot proper的加载链,CRC校验在哪个环节触发
嵌入式系统的启动是一个多阶段、逐级验证的过程。理解从片上ROM到SPL再到u-boot proper的完整加载链,是定位CRC校验失败故障的前提。本章将拆解这一流程,并明确指出CRC校验在哪个环节被触发。
2.1 三阶段启动模型
现代嵌入式处理器(如i.MX、Rockchip、TI OMAP等)普遍采用三级启动架构,每一级都承担着“加载并验证下一级”的职责。
| 阶段 | 存储位置 | 主要职责 | 是否包含CRC校验 |
|---|---|---|---|
| ROM Code | 芯片内部Mask ROM | 初始化基础硬件(时钟、PLL、DDR),从启动介质读取SPL | 通常由硬件或固定算法校验SPL头部 |
| SPL (Secondary Program Loader) | SPI Flash / eMMC / SD卡 | 初始化DDR、时钟、存储控制器,加载u-boot proper | 是(对u-boot proper镜像进行CRC校验) |
| u-boot proper | SPI Flash / eMMC / SD卡 | 加载内核、设备树、文件系统,提供命令行环境 | 可选(对内核/DTB进行CRC校验) |
关键结论:在标准u-boot启动流程中,CRC校验的主要触发点位于SPL加载u-boot proper的阶段。SPL在将u-boot proper从存储介质读入DDR后,会对其镜像头部或整体进行CRC校验,以确认镜像完整性。
2.2 启动流程详细拆解
下图展示了从芯片上电到u-boot proper运行的完整加载链,以及CRC校验的触发位置。
2.3 SPL中的CRC校验机制
SPL对u-boot proper的CRC校验通常发生在以下代码路径中:
- 读取镜像头部:SPL从存储介质中读取u-boot proper的头部结构(通常为
struct image_header或struct legacy_img_hdr)。 - 提取CRC值:从头部中提取预存的CRC校验值(
ih_hcrc或image_header->ih_hcrc)。 - 计算实际CRC:对头部数据或整个镜像数据重新计算CRC32。
- 比较验证:将计算值与预存值比较,一致则跳转到u-boot proper入口,不一致则进入错误处理流程。
调试提示:在SPL启动日志中,如果看到
Bad CRC、CRC error 或 Verification failed 等关键字,说明CRC校验失败。此时应优先检查u-boot proper镜像在存储介质中的写入是否正确,以及SPL读取的地址是否与镜像实际存储位置匹配。
2.4 CRC校验触发的具体代码位置
在u-boot源码中,CRC校验的核心函数位于以下文件中:
| 文件路径 | 关键函数 | 说明 |
|---|---|---|
common/image.c |
image_check_hcrc() |
校验镜像头部CRC(ih_hcrc) |
common/image.c |
image_check_dcrc() |
校验镜像数据CRC(ih_dcrc) |
common/spl/spl.c |
spl_load_image() |
SPL加载镜像入口,内部调用校验函数 |
common/spl/spl_legacy.c |
spl_parse_legacy_header() |
解析传统镜像头部并触发CRC校验 |
典型的校验调用链如下:
// spl_load_image() 中调用
spl_load_image(&bdev, &header, image_sector, count);
// 内部调用 spl_parse_legacy_header()
spl_parse_legacy_header(&header);
// 最终调用 image_check_hcrc() 进行CRC校验
if (!image_check_hcrc(&header)) {
printf("Bad CRC: header CRC check failed\n");
return -EINVAL;
}
2.5 不同启动介质下的CRC校验差异
CRC校验的触发时机和方式会因启动介质的不同而略有差异:
- SPI Flash:SPL通过SPI控制器读取u-boot proper镜像,CRC校验在数据完全读入DDR后执行。常见故障:SPI时钟配置错误导致数据读取错位。
- eMMC/SD卡:通过MMC控制器读取,CRC校验在块读取完成后触发。常见故障:分区表错误或块偏移量配置不正确。
- NAND Flash:由于NAND存在坏块,SPL需要处理ECC校验后再进行CRC校验。常见故障:坏块管理表损坏或ECC纠错失败。
- USB/网络启动:在开发调试阶段使用,CRC校验在数据接收完成后触发。常见故障:传输中断或数据包乱序。
常见误区:很多开发者误以为CRC校验失败一定是镜像文件损坏。实际上,SPL读取地址错误、存储介质驱动配置不当、DDR初始化不稳定等硬件或驱动层面的问题,同样会导致读入DDR的数据与原始镜像不一致,从而触发CRC校验失败。