OpenWiFi Buildroot 镜像构建实战:为 Zynq-7000 + AD9361 设备打造可复现的迷你 Linux 系统
OpenWiFi Buildroot 镜像构建实战:为 Zynq-7000 + AD9361 设备打造可复现的迷你 Linux 系统
导读
本文基于 OpenWiFi 仓库中的 Buildroot 中文构建说明,完整讲解如何用 Buildroot 为 ANTSDR-E200、ANTSDR-E310/ANT、ANTSDR-E310V2 三款 Zynq-7000 + AD9361 设备构建一套"小型、可重复构建、可从 SD 卡快速启动"的嵌入式 Linux 镜像,替代体积达数 GiB 的完整发行版。你将掌握从子模块初始化、多板公共系统构建、SD 卡烧录、串口启动到网口在线升级完整固件的全流程,并理解公共 rootfs 与分板 BOOT 的架构划分、FPGA 动态重载策略以及单分区原地更新的设计边界。
1. 项目目标与当前状态
该移植为 OpenWiFi 的 Zynq-7000 + AD9361 平台提供一个体积小、构建可复现、启动快的 Buildroot 系统,用来替代原先数 GiB 的通用 Linux 发行版镜像。目前已在实物上完成启动与 OpenWiFi 基本功能验证的设备如下:
| 构建名称 | 硬件 | 串口控制台 | 内存 |
|---|---|---|---|
antsdr_e200 |
ANTSDR-E200 | ttyPS0 |
512 MiB |
antsdr |
ANTSDR-E310/ANT | ttyPS0 |
1 GiB |
e310v2 |
ANTSDR-E310V2 | ttyPS0 |
1 GiB |
三种设备共用同一个 Linux 内核、内核模块集合和 ext4 根文件系统;SPL/U-Boot、设备树、FPGA bitstream、PS 初始化代码和串口路径等硬件差异全部保留在各自设备的 BOOT 内容中。
需要强调的是,这是新增的并行构建方式。原有的 ADI Kuiper 大容量 SD 卡镜像流程和 OpenWrt 流程仍然保留,继续使用原有脚本、文档和输出目录。Buildroot 不会调用或替换 user_space/update_sdcard.sh、user_space/prepare_kernel.sh、user_space/boot_bin_gen.sh 或 kernel_boot/build_boot_bin.sh。
1.1 默认 SD 卡镜像布局
SD card
├── partition 1: 64 MiB FAT32, label BOOT
└── partition 2: 96 MiB ext4, label rootfs
分区布局由 buildroot-external/board/common/genimage.cfg 定义:FAT32 BOOT 分区(分区类型 0x0c,可启动),ext4 rootfs 分区(类型 0x83),并对齐到 1 MiB。完整 SD 卡镜像约 169 MB;包含完整根文件系统的压缩在线更新包通常约 20 MB,实际大小随 OpenWiFi 和软件包内容变化。
1.2 主要版本基线
| 组件 | 版本/来源 |
|---|---|
| Buildroot | 2025.02.11 子模块 |
| Linux | Analog Devices Linux 6.12,提交 40201abd70d8f7848547a09fc7e366fba064483c |
| U-Boot | Xilinx xlnx_rebase_v2024.01_2024.2 |
| libad9361-iio | v0.3 |
| OpenWiFi | 构建时的当前仓库源码和短 Git revision |
版本基线在 buildroot-external/configs/openwifi_common_defconfig 中有对应实现:Linux 通过 BR2_LINUX_KERNEL_CUSTOM_REPO_URL 指向 analogdevicesinc/linux 仓库、BR2_LINUX_KERNEL_CUSTOM_REPO_VERSION 锁定上述提交;U-Boot 通过 BR2_TARGET_UBOOT_CUSTOM_TARBALL_LOCATION 锁定 xlnx_rebase_v2024.01_2024.2。
2. 架构设计与已完成的主要修改
2.1 Buildroot 集成与仓库边界
- Buildroot
2025.02.11以固定版本 Git 子模块形式加入buildroot/,子模块保持原样,不保存任何 OpenWiFi 私有修改。 - 所有板级配置、软件包、补丁、rootfs overlay 和镜像生成逻辑都位于
buildroot-external/。 - 新增统一入口 buildroot-build.sh,负责公共系统构建和各设备镜像组装。
- 增加基于
curl的 Buildroot 下载适配器(见 buildroot-external/board/common/curl-wget)以及 GNU 镜像地址回退,下载内容仍由 Buildroot hash 校验。 output/(生成目录)和dl/(下载缓存)不进入 Git 跟踪。
预期仓库边界:
buildroot/ 未修改的 Buildroot Git 子模块
buildroot-external/ OpenWiFi Buildroot 外部树
buildroot-build.sh 多设备构建入口
host-tools/ 上位机固件更新工具
output/ 构建结果,Git 忽略
dl/ 公共下载缓存,Git 忽略
2.2 公共系统与分板 BOOT 架构
output/common/中只构建一次 ARMv7 hard-float 工具链、Linux 6.12、OpenWiFi 模块和公共 rootfs。- 公共内核同时编译
antsdr_e200.dtb、antsdr.dtb和e310v2.dtb(defconfig 中BR2_LINUX_KERNEL_INTREE_DTS_NAME="xilinx/antsdr_e200 xilinx/antsdr xilinx/e310v2")。 output/<board>/只组装对应设备的 BOOT 文件、SD 卡镜像和完整系统更新包。- 从设备对应的
system_top.xsa中提取 FPGA bitstream 以及ps7_init_gpl.c/h,避免混用不同硬件设计。 - 构建时由 buildroot-external/support/prepare-board.py 生成 U-Boot DTS 和 PS7 初始化补丁,不修改 OpenWiFi 仓库中已有的板级 DTS。
从 buildroot-build.sh 可以看到 build_common() 的逻辑:首次构建时加载 openwifi_common_defconfig,并用 openwifi-dirclean 强制重装本地包与 overlay;后续构建同一公共系统时只对 U-Boot 执行 uboot-dirclean 后重建,Linux/rootfs 保持共享。
2.3 启动链与 BOOT 分区
BOOT 分区沿用 OpenWiFi 官方镜像中容易识别的命名:
BOOT.BIN
u-boot.img
uEnv.txt
uImage
devicetree.dtb
system_top.bit.bin
关键差异:本镜像的 BOOT.BIN 是 U-Boot SPL,而不是官方 Kuiper 镜像中由 Xilinx FSBL 组成的复合启动文件,因此必须同时保留 u-boot.img。不能只依据文件名互换两种镜像中的 BOOT.BIN。
启动过程如下:
BootROM
-> BOOT.BIN (U-Boot SPL + board PS7 initialization)
-> u-boot.img
-> import uEnv.txt
-> load system_top.bit.bin into FPGA
-> load uImage and devicetree.dtb
-> mount /dev/mmcblk0p2 as ext4 rootfs
启动命令细节体现在两处模板中:
- buildroot-external/board/common/uEnv.txt.in:定义
kernel_image=uImage、devicetree_image=devicetree.dtb、bitstream_image=system_top.bit.bin及各自加载地址(内核0x02080000、设备树0x02000000、bitstream0x04000000),并在uenvcmd中用fpga load 0先配置 FPGA,再依次加载内核与设备树,最终设置bootargs(console=@CONSOLE@,115200 earlycon root=/dev/mmcblk0p2 rootwait rw rootfstype=ext4 clk_ignore_unused cpuidle.off=1 ignore_loglevel loglevel=8)。 - buildroot-external/board/common/uboot.fragment:启用
CONFIG_CMD_FPGA/CONFIG_FPGA/CONFIG_FPGA_ZYNQPL,bootcommand 先从 FAT 分区导入uEnv.txt环境再执行uenvcmd。
相关修正包括:
- 为 U-Boot 2024 更新 SPL 使用的
bootph-all标记,确保 UART、SD/MMC、SLCR、时钟和定时器节点不会被 SPL 设备树裁剪。 - 构建完成时由 buildroot-external/support/assemble-board.sh 自动检查 SPL 中的串口、MMC、TWD timer 和
stdout-path,发现错误时拒绝生成镜像。 - 修正三块板的实际 UART 路径:E200 使用
e0000000,ANTSDR/E310 和 E310V2 使用e0001000(对应ttyPS0串口地址差异)。 - 去掉公共内核中绑定单一 UART 的
DEBUG_LL(见 linux-common.fragment),使同一个内核可以安全用于三种设备。 - E200 增加 SPL MMC/复位诊断补丁(buildroot-external/patches/uboot/antsdr_e200/0002-antsdr-e200-spl-mmc-diagnostics.patch),用于定位早期启动复位循环。
- U-Boot 在启动阶段加载 FPGA,Linux 启动后无需再次破坏已经工作的 AD9361/IIO 链路。
2.4 Linux、AD9361 与 OpenWiFi
- 使用 Analog Devices Linux 6.12 源码和 OpenWiFi 已有的 AD9361/AXI 补丁。defconfig 中
BR2_LINUX_KERNEL_PATCH依次应用kernel_boot/axi_hdmi_crtc.patch、kernel_boot/ad9361_v6_12.patch、buildroot-external/patches/linux/ad9361-debugfs-capacity.patch、kernel_boot/ad9361_private.patch、kernel_boot/ad9361_conv.patch。 - 内核版本增加
-openwifi后缀,并通过 linux-minimal.fragment 与 linux-common.fragment 关闭不需要的 DRM、声音、媒体和调试信息以减小镜像。 - 将
cfg80211、mac80211和 Xilinx DMA 作为模块,在根文件系统可用后由用户空间加载。 - 修正 AD9361 debugfs 表容量(ad9361-debugfs-capacity.patch),使当前 AD9361 补丁组合可以正确构建和运行。
- OpenWiFi 驱动、side-channel 模块、脚本以及
sdrctl、side_ch_ctl、inject_80211和analyze_80211被安装到/root/openwifi(由 buildroot-external/package/openwifi/ 负责)。 - 针对精简系统调整官方用户脚本:用
modprobe复用系统中的 AD9361/Xilinx DMA 模块,去掉目标板上不需要的sudo,将 Debianservice调用改为 Buildroot init 脚本,并以 BusyBoxhttpd替代不存在的webfsd。 - user_space/wgd.sh 会确认 AD9361、DDS、ADC 已就绪,挂载 debugfs,并保证 OpenWiFi 网卡最终命名为
sdr0。 - 关闭内核的 mac80211 verbose/HT 调试菜单(
linux-common.fragment),避免预期的 BA 协商结果持续刷满控制台;debugfs 仍然保留用于诊断。
2.5 FPGA Manager 动态加载
正常启动时 FPGA 已由 U-Boot 加载,推荐只重载驱动:
cd /root/openwifi
OPENWIFI_RELOAD_FPGA=0 ./wgd.sh 0
需要调试一个拓扑兼容的 bitstream 时,可以通过 Linux FPGA Manager 强制重载:
cd /root/openwifi
OPENWIFI_RELOAD_FPGA=1 ./wgd.sh 0
从 user_space/wgd.sh 的源码可以看到 OPENWIFI_RELOAD_FPGA 的取值策略:显式传 1|yes|true 强制重载、0|no|false 跳过重载;auto(默认)时,若提供了显式 FPGA 镜像则重载,否则在 Buildroot 系统且 RF 链路(FPGA/AD9361/DDS/ADC)已就绪时跳过重复重载,Kuiper/OpenWrt 则保持历史默认行为(重载本地镜像)。
为避免动态重载期间 AXI/IIO 链路卡死,user_space/load_fpga_img.sh 进行了以下修改:
- 重载前停止
iiod,并解绑 AD9361、CF AXI DDS 和 CF AXI ADC 消费者。 - 不解绑 E200 上可能在 remove/probe 阶段访问已失效 PL 寄存器的 Xilinx VDMA 设备。
- FPGA Manager 写入成功后主动重新绑定 AD9361、DDS 和 ADC。
- 如果原来运行了
iiod,重绑定完成后恢复服务(兼容 Buildroot SysV init 和 Kuiper systemd)。 - 所有 sysfs 等待都有有限超时:默认 50 次、每次 0.2 秒,可通过
OPENWIFI_FPGA_WAIT_RETRIES调整(load_fpga_img.sh中WAIT_RETRIES=${OPENWIFI_FPGA_WAIT_RETRIES:-50}),不会再无限等待不存在的设备。 - 正确解析设备树中以 NUL 分隔的
compatible字符串,消除 shell 的 null-byte 警告。
限制:动态重载要求新旧 FPGA 设计的地址和设备拓扑兼容。对于普通 AP 或吞吐量测试,不需要动态重载 FPGA。
2.6 根文件系统内容
公共 rootfs 使用 musl,并包含:
- OpenWiFi 内核模块、脚本和用户空间工具;
hostapd、wpa_supplicant、ISC DHCP server/client;iw、iwconfig、iproute2、ethtool;iperf3、tcpdump;libiio、iiod及 IIO 测试工具;- 新增的
libad9361-iioBuildroot 外部软件包(buildroot-external/package/libad9361-iio/); - Dropbear SSH;
- 带 OpenWiFi 字符标识、官方链接和项目简介的
/etc/motd(buildroot-external/board/common/rootfs-overlay/etc/motd)。
上述软件包在 openwifi_common_defconfig 中逐项启用,还包括 wireless-regdb、batctl、libnl 及其工具、libpcap 等。
板型动态识别:系统启动时由 S02openwifi-board 调用 openwifi-board-name,读取 /proc/device-tree/model 并生成 /etc/openwifi-board(E200→antsdr_e200、E310V2→e310v2、E310 系列→antsdr),因此公共 rootfs 不需要写死设备型号。
BOOT 分区正常以只读方式挂载,/tmp 和 /run 使用 tmpfs;首次启动生成的 Dropbear 主机密钥保存在 BOOT 分区,重启和完整系统更新后继续使用同一 SSH 身份。
OpenWiFi application notes 中需要直接控制驱动、网卡、IIO 或 FPGA 的 shell 程序在板上运行;绘图、波形显示、离线数据分析以及文档中明确要求 MATLAB/Python GUI 的程序仍然在上位机运行。Buildroot 移植提供板端运行环境,并不把所有上位机可视化软件塞入 rootfs。
默认配置:
root password: openwifi
eth0: 192.168.10.122/24
serial: 115200 8N1
OpenWiFi dir: /root/openwifi
管理网口配置见 buildroot-external/board/common/rootfs-overlay/etc/network/interfaces。
2.7 完整系统在线更新
每个设备都会生成一个包含 BOOT 全部文件和完整 ext4 rootfs 的 .frm 包(由 buildroot-external/support/mk-firmware-package.sh 生成,内含 manifest、长度和 SHA-256)。更新方案只使用标准 SSH/SCP,不运行额外的更新守护进程,不需要端口或 Token。
板端更新器 openwifi-fw-update 的校验流程(对应 check_package())会:
- 检查包格式(
openwifi-zynq-system-v1)和目标板型号(与openwifi-board-name输出比对,不匹配直接拒绝); - 检查每个文件的长度和 SHA-256(manifest 中
file.<name>.size/file.<name>.sha256); - 使用
gzip -dc与普通tar分步解包,以兼容未启用tar -z的 BusyBox,并验证完整 ext4 镜像解压后的长度和 SHA-256(rootfs.uncompressed_size/rootfs.uncompressed_sha256); - 将 BOOT 文件暂存后按安全顺序替换(
uImage → devicetree.dtb → system_top.bit.bin → uEnv.txt → u-boot.img → BOOT.BIN); - 保留 Dropbear 主机密钥(复制到
/boot/.openwifi/dropbear,更新后恢复),避免更新后 SSH 身份变化; - 将当前 rootfs 重新挂载为只读;
- 流式写入
/dev/mmcblk0p2(gzip -dc | dd bs=1M conv=fsync); - 使用提前放在 tmpfs 中的重启程序(
/tmp/busybox+ musl loader)或 Magic SysRq 立即重启(生产内核启用了CONFIG_MAGIC_SYSRQ,见 linux-common.fragment); - 上位机看到完成标记后主动断开旧 SSH 会话,避免板卡已经重启而命令仍长时间不退出。
该方案为单 rootfs 更新,没有 A/B 回滚副本。写入期间必须保持供电。同时,由于更新器覆盖当前挂载的根文件系统,install 必须带 --reboot。
3. 获取源码与准备环境
在 Ubuntu/Debian 主机上安装 Buildroot 常用依赖:
sudo apt install build-essential git rsync cpio unzip bc file wget curl python3 \
libncurses-dev
克隆 OpenWiFi 后初始化 Buildroot 子模块:
git submodule update --init buildroot
默认从相邻的硬件镜像仓库中选择匹配的 XSA:
../openwifi-hw-img/boards/<board>/sdk/system_top.xsa
也可以指定硬件仓库或单个 XSA:
OPENWIFI_HW_IMG_DIR=/path/to/openwifi-hw-img \
./buildroot-build.sh antsdr_e200 build
OPENWIFI_XSA=/path/to/system_top.xsa \
./buildroot-build.sh antsdr_e200 build
必须使用与目标设备和 FPGA 设计匹配的 XSA。XSA 解析逻辑见 buildroot-build.sh:优先使用 OPENWIFI_XSA,否则回落到 OPENWIFI_HW_IMG_DIR/boards/<board>/sdk/system_top.xsa,文件不存在时明确报错退出。
4. 构建镜像
在 OpenWiFi 仓库根目录执行:
./buildroot-build.sh antsdr_e200 build
./buildroot-build.sh antsdr build
./buildroot-build.sh e310v2 build
第一次构建会创建公共系统,后续设备复用相同内核和 rootfs,只重建该设备的 U-Boot 和镜像。
主要产物:
output/common/images/uImage
output/common/images/rootfs.ext4
output/antsdr_e200/images/openwifi-antsdr_e200-sdcard.img
output/antsdr_e200/images/openwifi-antsdr_e200-system.frm
output/antsdr/images/openwifi-antsdr-sdcard.img
output/antsdr/images/openwifi-antsdr-system.frm
output/e310v2/images/openwifi-e310v2-sdcard.img
output/e310v2/images/openwifi-e310v2-system.frm
其他构建命令:
./buildroot-build.sh antsdr_e200 configure
./buildroot-build.sh antsdr_e200 menuconfig
./buildroot-build.sh antsdr_e200 rebuild-system
./buildroot-build.sh antsdr_e200 clean
各命令语义(对应 buildroot-build.sh 的实现):
build(默认):prepare_board生成板级输入 →build_common构建/复用公共系统 →assemble_board组装该设备镜像。configure:重新生成板级输入并加载公共 defconfig,同时清除公共系统就绪标记强制重建。menuconfig:修改公共 Buildroot 配置,并将公共系统标记为需要重建(rm .openwifi-common-ready)。rebuild-system:修改内核、OpenWiFi、外部软件包或 rootfs overlay 后,保留昂贵的工具链,仅对linux、openwifi、libad9361-iio执行-dirclean后强制重建公共系统,再重建 U-Boot 并组装镜像。clean:只删除所选设备的输出(rm -rf output/<board>),保留output/common/和下载缓存。
5. 首次烧录 SD 卡
首次安装必须烧录完整 .img,不能只把 BOOT 文件复制到一张没有正确分区和 ext4 rootfs 的卡中。
先确认设备名:
lsblk -o NAME,SIZE,MODEL,TRAN,MOUNTPOINTS
卸载该卡上已经自动挂载的分区,然后写入整个设备,例如 E200:
sudo umount /dev/sdX1 /dev/sdX2 2>/dev/null || true
sudo dd if=output/antsdr_e200/images/openwifi-antsdr_e200-sdcard.img \
of=/dev/sdX bs=4M conv=fsync status=progress
sync
将 /dev/sdX 替换为确认无误的 SD 卡整盘设备。该操作会覆盖目标设备上的数据,不能写到 /dev/sdX1(分区节点)。
6. 启动和基本使用
使用 115200 8N1 连接串口并启动。登录信息:
login: root
password: openwifi
检查板型、启动参数和 IIO:
cat /etc/openwifi-board
cat /proc/cmdline
iio_info -s
加载正常 OpenWiFi 栈:
openwifi-start 0
等价于:
cd /root/openwifi
./wgd.sh 0
openwifi-start 本质就是 cd /root/openwifi && exec ./wgd.sh "$@" 的包装。
检查结果:
ip link show sdr0
iw dev
dmesg | tail -100
目前经过稳定性验证的默认方式是 test_mode=0。只有明确验证某个 FPGA/驱动组合的聚合功能时才切换其他 test mode。
7. 通过网口更新完整系统
设备与主机的管理网口连通后,先查看状态:
./host-tools/openwifi_fw_update.py --host 192.168.10.122 status
在板上完整校验固件包:
./host-tools/openwifi_fw_update.py --host 192.168.10.122 check \
output/antsdr_e200/images/openwifi-antsdr_e200-system.frm
更新 BOOT 和完整 ext4 rootfs,并立即重启:
./host-tools/openwifi_fw_update.py --host 192.168.10.122 update --reboot \
output/antsdr_e200/images/openwifi-antsdr_e200-system.frm
上位机工具 host-tools/openwifi_fw_update.py 密码默认为 openwifi,使用普通 SSH 登录,将固件和板端更新脚本临时复制到 /tmp,完成后清理。设备型号不匹配时会拒绝更新。
也可以手动执行:
scp output/antsdr_e200/images/openwifi-antsdr_e200-system.frm \
root@192.168.10.122:/tmp/openwifi-system.frm
ssh root@192.168.10.122
openwifi-fw-update status
openwifi-fw-update check /tmp/openwifi-system.frm
openwifi-fw-update install --reboot /tmp/openwifi-system.frm
因为更新器覆盖当前挂载的根文件系统,install 必须带 --reboot。
8. 验证结论与注意事项
截至文档更新时:
- ANTSDR-E200、ANTSDR-E310/ANT 和 ANTSDR-E310V2 均已由用户在实物上验证可以正常启动并运行 OpenWiFi。
- 三种设备确认可以复用公共
uImage、模块和rootfs.ext4,同时使用各自的 BOOT 文件。 - E200 已验证 OpenWiFi AP/客户端连接及
iperf3数据传输。 - 原有 Kuiper 构建脚本和说明文件与官方版本保持不变,并使用 2025-03-18 ADI Kuiper 镜像实际跑通了完整的旧 SD 卡准备流程:镜像烧录后完成逐字节校验,成功构建 32/64 位 Linux 6.12 内核与模块,生成 E200 FSBL、BOOT.BIN、设备树和 bitstream,安装两种架构的 OpenWiFi 驱动,最终 FAT/ext4 文件系统检查均通过。
- 两块同时接入同一管理交换机的设备不能都保留默认
192.168.10.122,应临时修改其中一块的eth0地址。 - 普通运行优先使用 U-Boot 已加载的 FPGA,即
OPENWIFI_RELOAD_FPGA=0;动态加载只用于兼容 bitstream 的开发调试。 - 完整系统更新为单分区原地更新,不具备断电自动回滚能力,写入期间必须保持供电。
提交前确认 Buildroot 子模块没有被意外修改:
git -C buildroot status --short
git submodule status buildroot
9. 文件级修改索引
10. 小结
这套 Buildroot 移植通过"公共系统构建一次 + 分板 BOOT 各自组装"的架构,把三款 Zynq-7000 + AD9361 设备的部署镜像压缩到约 169 MB,并以约 20 MB 的 .frm 包支持纯 SSH 驱动的完整系统在线更新。对普通使用场景,U-Boot 在启动阶段完成 FPGA 配置,用户只需 openwifi-start 0 即可拉起 sdr0 网卡;对开发调试场景,OPENWIFI_RELOAD_FPGA 与 OPENWIFI_FPGA_WAIT_RETRIES 提供了可控的动态重载路径。理解"BOOT.BIN 是 SPL 而非 FSBL"、"单分区更新无回滚"这两个关键约束,是安全使用这套镜像的前提。