篇首
最近突发奇想,Xilinx 的集成开发环境已经很好了,很多必要的代码都直接生成了,这给开发者带来了巨大便利的同时,也让人错过了很多代码的精彩,可能有很多人用了很多年了,都还无法清楚的理解其中过程。博主准备以FSBL为例,与大家深入探讨一番,从而加深对ZYNQ的加载过程的理解,以便大家作出更精彩的设计!
Zynq镜像文件BOOT.BIN
结构详解
BOOT.BIN
是Zynq 7000系列启动的核心镜像文件,由Xilinx工具链(如Vitis或SDK)通过bootgen
工具生成。其本质是一个二进制容器,包含多个逻辑分区,每个分区对应不同的功能模块(如FSBL、PL比特流、U-Boot等)。以下是其详细结构和操作方法:
一、BOOT.BIN
的组成结构
BOOT.BIN
由 镜像头(Image Header) 和 多个分区(Partitions) 组成,结构如下:
BOOT.BIN
├── 启动头(BOOT Header) // BootROM执行的参数
├── 寄存器初始化区(Register initializetion) // BootROM执行时的一些寄存器配置
├── 镜像头表(Image Header table) // 描述镜像头信息
├── 分区头表(Image Header table) // 描述分区头信息
├── 分区头表(Image Header table) // 描述分区头信息
├── 镜像头(Image Header) // 描述镜像整体属性
├── 分区1(Partition 1) // 通常是FSBL
├── 分区2(Partition 2) // PL比特流(可选)
├── 分区3(Partition 3) // SSBL(如U-Boot)
└── 其他分区(用户自定义数据) // 设备树、配置文件等(可选)
二、镜像头(Image Header)
- 作用:描述镜像全局属性,包括:
- 加密标志(是否启用AES加密)
- 认证类型(如RSA签名或HMAC)
- 分区表信息(分区的数量、偏移地址、加载地址等)
- 存储位置:位于
BOOT.BIN
文件起始位置,长度固定(通常为64字节)。
三、分区的结构与用途
每个分区的组成如下:
-
分区头(Partition Header)
- 长度:32字节。
- 关键字段:
Partition Type
:分区类型(如FSBL、Bitstream、SSBL)。Load Address
:加载到内存的目标地址。Execution Address
:执行入口地址(通常与加载地址相同)。Encryption Key Source
:加密密钥来源(如eFUSE或BBRAM)。Authentication Type
:认证算法(如RSA-2048)。
-
分区数据(Partition Data)
- 实际内容(如FSBL代码、PL比特流、U-Boot二进制文件等)。
分区类型与用途
分区类型 | 用途 | 典型文件 |
---|---|---|
Bootloader (FSBL) | 第一阶段引导程序,初始化硬件并加载后续镜像。 | fsbl.elf |
PL Bitstream | FPGA逻辑配置比特流,用于初始化PL(Programmable Logic)。 | system.bit |
SSBL | 第二阶段引导程序(如U-Boot),负责加载操作系统内核。 | u-boot.elf |
Datafile | 用户自定义数据(如设备树devicetree.dtb 、配置文件等)。 | 任意二进制文件 |
四、如何区分BOOT.BIN
中的各个部分?
1. 使用bootgen
工具解析
通过bootgen
工具可逆向解析BOOT.BIN
,生成分区信息报告:
bootgen -arch zynq -image boot.bin -dumpbin -dumpdir output
生成的output
目录包含:
boot.bin.bif
:镜像的BIF(Boot Image Format)配置文件。- 各分区的原始二进制文件(如
partition_1.bit
、partition_2.elf
)。
2. 使用hexdump
查看二进制结构
通过hexdump
观察分区头特征:
hexdump -C -n 128 boot.bin
- 分区头标识:
- FSBL分区:以
Xilinx
字符串开头(ASCII码58 69 6C 69 6E 78
)。 - PL比特流:以同步字
0xAA995566
开头(Hex值AA 99 55 66
)。 - U-Boot分区:ELF文件头(
7F 45 4C 46
)。
- FSBL分区:以
3. 示例解析
Offset Hex Content ASCII 说明
0x00000000 58 69 6C 69 6E 78 Xilinx 镜像头标识
0x00000040 01 00 00 00 .... 分区数量=1
0x00000100 7F 45 4C 46 ELF U-Boot分区(ELF文件)
0x00002000 AA 99 55 66 ..Uf PL比特流分区
五、构建BOOT.BIN
的方法
通过编写BIF(Boot Image Format)文件定义镜像内容,再使用bootgen
生成BOOT.BIN
。
1. BIF文件示例
// bootimage.bif
the_ROM_image:
{
[bootloader] fsbl.elf // FSBL分区
system.bit // PL比特流分区
u-boot.elf // SSBL分区
devicetree.dtb // 设备树分区
custom_data.bin // 用户自定义数据
}
2. 生成命令
bootgen -arch zynq -image bootimage.bif -o BOOT.BIN -w on
-w on
:允许覆盖已有文件。-arch zynq
:指定目标架构为Zynq 7000。
3. 高级配置选项
- 加密与认证:
[aeskeyfile] key.nky // 指定AES密钥文件 [authentication] rsa // 启用RSA签名
- 加载地址指定:
{ [load=0x10000000] u-boot.elf } // 强制加载到0x10000000
- 启动设备配置:
[destination_device=pl] system.bit // 指定PL比特流仅用于PL配置
六、实际应用案例
1. 添加多个PL比特流
在BIF文件中定义多个比特流分区,实现动态重配置:
the_ROM_image:
{
[bootloader] fsbl.elf
[destination_device=pl] bitstream_1.bit // 默认配置
[destination_device=pl] bitstream_2.bit // 备用配置
u-boot.elf
}
在U-Boot中通过fpga load
命令切换PL配置。
2. 自定义数据分区
将配置文件嵌入BOOT.BIN
,供应用程序读取:
the_ROM_image:
{
[bootloader] fsbl.elf
system.bit
u-boot.elf
[offset=0x100000] config.txt // 指定分区偏移地址
}
在U-Boot中通过fatload
或内存映射访问该数据。
七、常见问题与调试
-
镜像无法启动
- 检查点:
- 分区顺序是否正确(FSBL必须为第一个分区)。
- 加载地址是否与内存映射冲突(如DDR未初始化时加载到DDR地址)。
- 检查点:
-
PL配置失败
- 原因:比特流文件损坏或PCAP接口未初始化。
- 调试方法:在FSBL中启用调试输出,检查
XFsbl_LoadPLBitstream
日志。
-
认证失败
- 解决步骤:
- 确认公钥已烧录到eFUSE。
- 检查BIF文件中是否指定正确的签名文件。
- 解决步骤:
八、总结
通过理解BOOT.BIN
的结构与分区逻辑,开发者可以:
- 灵活定制启动流程:动态加载多个PL配置或用户数据。
- 增强安全性:集成加密和签名机制。
- 快速定位问题:通过解析工具逆向分析镜像内容。
掌握这些技能,可显著提升Zynq系统的开发效率与可靠性。