4. Zynq启动流程与镜像构建
Zynq-7000 的启动过程与普通 ARM 处理器最大的不同,在于它内部固化了一段不可修改的 BootROM,并且把 PS(Processing System)与 PL(Programmable Logic)的初始化绑定在启动链的前端。理解这条启动链,是构建工业通信网关镜像的基础:只有清楚每一级由谁加载、加载到哪里、失败时停在哪一步,才能在网关无法启动时快速定位问题。
一、启动链的整体结构
上电或复位后,Zynq 的启动顺序是固定的:BootROM → FSBL →(可选 PL 配置)→ U-Boot → Linux 内核 + 设备树 → 根文件系统 → 用户空间应用。每一级都是下一级的“加载器”,前一级只负责把后一级搬进内存并跳转执行。
BootROM 是芯片内部固化的只读代码,它在上电后首先运行,读取启动模式引脚(MIO[5:2] 等)决定的启动设备,然后从该设备中读取 Boot Header,解析出 FSBL 的位置并加载到 OCM(On-Chip Memory,约 256KB)中执行。BootROM 只认 Boot Header 格式,不认文件系统,因此启动介质上的镜像必须按 BootROM 规定的头部结构组织。
FSBL(First Stage Boot Loader)是用户可修改的第一级引导程序,通常由 Xilinx Vitis 根据硬件平台(.xsa)生成。它承担三件事:初始化 DDR 控制器和时钟、按需把 bitstream 写入 PL 完成 PL 配置、把下一级镜像(U-Boot 或直接是内核)从启动介质搬到 DDR 并跳转。工业网关通常需要 PL 逻辑参与通信协议加速或 IO 扩展,因此 FSBL 中的 PL 配置环节非常关键。
二、BOOT.BIN 与 image.ub 的组成
在 Vitis 或 PetaLinux 中,最终烧写到 QSPI 或 SD 卡的启动文件通常有两个:BOOT.BIN 和 image.ub。
BOOT.BIN 由 BootGen 工具生成,它把 Boot Header、FSBL.elf、PL bitstream、U-Boot.elf 按顺序打包成一个文件。BootROM 只解析这个文件的前半部分(Boot Header + FSBL),FSBL 再根据 Boot Header 中的分区表继续读取 bitstream 和 U-Boot。因此 BOOT.BIN 中分区的顺序和偏移必须与 BootGen 的 .bif 描述一致。
一个典型的 .bif 文件内容如下:
the_ROM_image:
{
[bootloader] fsbl.elf
system.bit
u-boot.elf
}
其中 [bootloader] 标记的 fsbl.elf 会被 BootROM 识别为第一阶段引导程序,其余分区由 FSBL 按顺序处理。如果网关不需要 PL 逻辑,可以去掉 system.bit 这一行,但工业网关通常保留,因为 PL 中可能实现了 EtherCAT、PROFINET 等实时协议或额外的串口、CAN 控制器。
image.ub 是 U-Boot 使用的 FIT(Flattened Image Tree)镜像,内部包含 Linux 内核 zImage/Image、设备树 DTB,有时还包含 initramfs。U-Boot 通过 bootm 或 booti 命令解析 FIT 结构,把内核和设备树分别放到内存约定地址,再跳转到内核入口。PetaLinux 默认生成的 image.ub 就是这种格式,它比单独的内核 + DTB 文件更便于版本管理和校验。
三、设备树在网关中的作用
设备树(Device Tree)是内核识别硬件的唯一依据。对于 Zynq 网关,设备树需要描述三类信息:PS 侧外设(UART、I2C、SPI、以太网、USB、SD 等)、PL 侧自定义 IP(通过 axi 总线挂载的寄存器节点)、以及内存和中断控制器的布局。
在 PetaLinux 中,设备树通常由 system-user.dtsi 与自动生成的 pl.dtsi 合并而成。例如,为 PL 中一个 AXI GPIO 添加节点,可以写成:
&axi_gpio_0 {
compatible = "xlnx,axi-gpio-2.0";
reg = <0x41200000 0x10000>;
interrupts = <0 29 4>;
gpio-controller;
#gpio-cells = <2>;
};
这里的 reg 地址必须与 Vivado 地址编辑器中分配的 PL 地址一致,interrupts 中的中断号必须与 Zynq 中断控制器连接关系一致。如果设备树写错,内核启动时会出现“无法申请内存区域”或“probe 失败”的日志,网关应用也就无法访问 PL 资源。
四、根文件系统的选择与构建
根文件系统决定网关启动后能运行什么。工业网关常见三种方案:
- initramfs:内核启动时直接解压到内存,启动快、无块设备依赖,适合功能固定的网关,但占用 RAM 且不易持久化配置。
- SD 卡 / eMMC 上的 ext4 根文件系统:容量大、可读写,适合需要日志、数据库或频繁升级的网关。
- QSPI + UBIFS/JFFS2:无机械部件、抗振动,适合工业现场,但容量有限,通常只放只读系统加少量配置分区。
PetaLinux 使用 petalinux-config -c rootfs 选择包和文件系统类型,再用 petalinux-build 生成 rootfs.tar.gz 或 rootfs.ext4。若采用 SD 卡启动,通常把 BOOT.BIN 和 image.ub 放在 FAT 分区,把根文件系统放在 ext4 分区,U-Boot 的 bootargs 中通过 root=/dev/mmcblk0p2 rootwait rw 指定根分区。
五、启动失败的定位思路
当网关上电后无输出,可以按启动链逐级排查。首先确认启动模式引脚是否正确,QSPI 与 SD 启动的 MIO 配置不同;其次用串口观察 BootROM 是否打印“BootROM”相关信息,若完全没有输出,说明 BootROM 未找到有效 Boot Header,应检查 BOOT.BIN 是否烧写正确、启动介质是否可读。
若 FSBL 阶段停住,常见原因是 DDR 初始化参数与硬件不匹配,或 bitstream 与硬件平台不一致。FSBL 会在串口输出“FSBL”版本和阶段信息,可据此判断卡在 DDR 初始化、PL 配置还是 U-Boot 加载。若 U-Boot 能启动但内核挂载根文件系统失败,则重点检查 bootargs 中的 root= 设备名、分区号以及文件系统类型是否与镜像一致。
bootdelay=3,便于中断启动流程、手动执行 printenv、mmc part、fatls mmc 0 等命令检查介质内容。六、镜像构建的完整流程示例
以 PetaLinux 2022.2 为例,从硬件平台到可启动镜像的典型命令序列如下:
# 1. 基于 .xsa 创建工程
petalinux-create -t project --template zynq -n gw_zynq
cd gw_zynq
petalinux-config --get-hw-description=../system.xsa
# 2. 配置根文件系统与启动参数
petalinux-config -c rootfs
petalinux-config -c kernel
# 3. 构建
petalinux-build
# 4. 打包 BOOT.BIN
petalinux-package --boot --fsbl images/linux/zynq_fsbl.elf \
--fpga images/linux/system.bit --u-boot --force
# 5. 生成 SD 卡镜像
petalinux-package --wic --images-dir images/linux/ \
--bootfiles "BOOT.BIN image.ub" --disk-name "sdb"
构建完成后,images/linux/ 目录下会得到 BOOT.BIN、image.ub、rootfs.tar.gz 等文件。把 BOOT.BIN 和 image.ub 放入 FAT 分区,把根文件系统解压到 ext4 分区,设置启动模式为 SD,即可上电验证。串口应依次看到 FSBL、U-Boot、内核解压、设备树解析、根文件系统挂载和 init 启动的日志,最终进入登录提示符或直接运行网关应用。