4. 启动镜像格式与Boot Header解析

Zynq 的 BootROM 在复位后并不认识 ELF、BIT 或裸二进制文件,它只认一种由 bootgen 打包出来的 Boot Image(BOOT.BIN)。理解这个镜像的内部结构,是排查“为什么板子不启动”的关键。BOOT.BIN 本质上是一串按固定字节偏移排列的记录:最前面是 BootROM Header,随后是 Image Header Table,再往后是若干 Partition Header 及其对应的分区数据,最后可能附加认证证书。BootROM 只按偏移和长度字段去解析,任何一个字段写错,都会导致解析失败或跳转到错误地址。

镜像的字节级布局

BootROM Header 固定位于镜像偏移 0x00 处,长度 0x8C0 字节,是 BootROM 唯一强制解析的结构。它包含几个决定性字段:Width Detection 用于判断 Flash 数据位宽,Image Identification 固定为 0x584C4E58(ASCII "XLNX"),Encryption Status 标识是否加密,Image Offset 指向 Image Header Table 的起始位置,Checksum 是对 Header 前 0x48 字节的累加和取反。BootROM 首先校验这个 Checksum,若不符则直接进入错误状态,不会继续解析后续内容。

Image Header Table 位于 BootROM Header 之后,由 Image Header 描述:它记录分区总数、每个 Partition Header 的偏移,以及镜像属性(如是否使用 FSBL、是否加密)。每个 Partition Header 长 0x40 字节,描述一个分区的关键信息:Partition Data Word Length(分区数据长度,以字为单位)、Destination Device(目标设备,如 PS、PL、DDR)、Destination CPU(A9-0/A9-1)、Execution Address(执行地址)、Load Address(加载地址)以及 Partition Checksum。BootROM 会按 Partition Header 的指示,把数据搬运到 Load Address,再跳转到 Execution Address。

BOOT.BIN 字节级布局与 BootROM 解析路径 镜像文件偏移 BootROM Header (0x8C0) Image ID / Checksum / Image Offset Encryption Status / Width Detection Image Header Table 分区总数 / 各 Partition Header 偏移 Partition Header 0 (0x40) 长度 / 目标设备 / 加载地址 / 执行地址 Partition Header 1 (如 PL bitstream 分区) Partition Data 0 (FSBL) 实际可执行代码 Partition Data 1 (Bitstream) PL 配置数据 BootROM 解析动作 ① 读偏移 0x00,校验 Image ID = 0x584C4E58 ② 累加 Header 前 0x48 字节,与 Checksum 比对 ③ 按 Image Offset 定位 Image Header Table ④ 读取分区数量与各 Partition Header 偏移 ⑤ 逐分区校验 Partition Checksum ⑥ 按 Load Address 搬运数据到目标设备 ⑦ 跳转到 Execution Address 执行 FSBL ⑧ 若启用认证,先验证证书链再执行 任一 Checksum 失败或地址越界,BootROM 停止解析并进入错误状态,不会执行任何用户代码

校验和与认证证书

BootROM Header 的 Checksum 计算方式很直接:把 Header 前 0x48 字节按 32 位字累加,取反后写入偏移 0x48。Partition Checksum 则是对该分区数据按字累加取反。这两个校验和是“完整性”检查,不是安全机制——它们只能发现传输或打包错误,不能防止恶意篡改。真正的安全启动依赖 Authentication Certificate:当 Encryption Status 或认证标志置位时,每个分区前会附加一个证书,包含公钥、签名和分区哈希。BootROM 用 eFUSE 中烧录的 PPK 哈希验证证书公钥,再用公钥验证分区签名,全部通过才执行。证书由 bootgen 在打包时自动生成,私钥不进入镜像。

bootgen 使用与 BIF 文件

bootgen 的输入是一个 BIF(Boot Image Format)文本文件,它描述分区顺序、类型和属性。一个典型的 BIF 如下:

// boot.bif
the_ROM_image:
{
    [bootloader] fsbl.elf
    system.bit
    u-boot.elf
}

执行 bootgen -image boot.bif -o BOOT.BIN -w on 即可生成镜像。-w on 表示覆盖已有文件。若需要认证,BIF 中要加入 [auth_params] 和 [keys] 段,并指定 ppk、psk、ssk 文件;若需要加密,还要加入 [encryption] 与 aeskey。bootgen 会按 BIF 顺序把每个分区打包,自动计算长度、地址和校验和,并插入 Partition Header。

常见错误与排查

实际调试中,镜像问题往往表现为“串口无输出”或“卡在 BootROM”。可按以下顺序排查:

  • Image ID 错误:镜像不是 bootgen 生成,或文件头被工具改写。用十六进制查看偏移 0x00 处是否为 58 4E 4C 58。
  • Checksum 失败:BIF 中分区顺序与地址冲突,或手动修改了镜像字节。重新用 bootgen 生成,不要手工编辑 BOOT.BIN。
  • Load Address 越界:FSBL 的 Load Address 与 Execution Address 设置错误,或 DDR 未初始化就被搬运。检查 Partition Header 中的地址字段是否落在有效内存范围。
  • 分区长度不匹配:BIF 中引用的 ELF 被重新编译但未重新打包,导致长度字段与实际数据不一致。每次修改代码后必须重新运行 bootgen。
  • 认证失败:eFUSE 中 PPK 哈希与证书不匹配,或私钥签名时使用的密钥与烧录的 PPK 不对应。此时 BootROM 会静默停止,串口无任何输出。
排查镜像问题时,可先用 bootgen -image boot.bif -o BOOT.BIN -debug 生成带调试信息的镜像,或使用 Xilinx 提供的 bootgen -read BOOT.BIN 反解析镜像结构,直接查看每个 Partition Header 的地址、长度和校验和字段,比盲目猜测高效得多。

掌握镜像的字节布局后,BootROM 的行为就不再是黑盒:它按偏移读 Header、按 Checksum 判断完整性、按 Partition Header 搬运数据、按 Execution Address 跳转。任何一步的字段错误都会在对应阶段暴露,而 bootgen 的职责就是保证这些字段自洽。下一阶段 FSBL 接手后,才会进入更复杂的时钟、DDR 和 PL 配置流程。