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 配置环节非常关键。

Zynq-7000 启动链与镜像组成 启动介质 QSPI / SD / NAND Boot Header FSBL.elf bitstream u-boot.elf image.ub rootfs BootROM 芯片固化,不可改 读 Boot Header 加载 FSBL 到 OCM FSBL 初始化 DDR / 时钟 配置 PL(bitstream) 搬 U-Boot 到 DDR 跳转执行 U-Boot 初始化外设 / 网络 加载 image.ub 传递 bootargs 跳转内核入口 Linux 内核 解压 / 自解压 解析设备树 DTB 挂载根文件系统 设备树 DTB 描述 PS 外设 描述 PL 节点 内存 / 中断 / 时钟 由内核解析 根文件系统 /bin /lib /etc init 进程 网关应用 通信协议栈 BOOT.BIN = Boot Header + FSBL + bitstream + U-Boot;image.ub = 内核 + DTB + 可选 initramfs

二、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= 设备名、分区号以及文件系统类型是否与镜像一致。

建议在网关开发阶段保留串口调试口,并在 U-Boot 中设置 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 启动的日志,最终进入登录提示符或直接运行网关应用。