4. Kria Ubuntu系统定制与设备树配置
Kria SOM 出厂通常预装 Kria Ubuntu(基于 Canonical 的 Ubuntu 22.04 LTS 与 Xilinx/AMD 内核),但产品化时几乎不可能直接沿用默认镜像:根文件系统需要裁剪与固化,外设需要按载板重新使能,引脚复用需要与硬件原理图对齐,启动链与固件也要能随产品版本迭代。本节围绕这四件事展开,重点讲清“改什么、在哪改、改完怎么验证”。
一、Ubuntu rootfs 定制:从通用镜像到产品镜像
Kria 的 Ubuntu rootfs 由 Canonical 维护,通过 ubuntu-image 或 AMD 提供的 kria-ubuntu 构建脚本生成。产品化定制一般分三层:
- 包裁剪:移除 snapd、桌面组件、示例应用,保留 systemd、网络管理、SSH 与必要的运行时库。可用
--snap与--extra-ppas控制,或在 chroot 中执行apt purge。 - 文件注入:把产品应用、systemd 服务、udev 规则、网络配置写入 rootfs。推荐用
overlay/目录 +rsync注入,避免直接改镜像。 - 只读与 A/B 升级:量产设备建议将 rootfs 挂载为只读,配合
overlayfs或 A/B 双分区,通过rauc或swupdate做原子升级。
一个可复现的构建流程示例(示例参数,非实测结果):
# 1. 准备构建环境
sudo apt install ubuntu-image qemu-user-static
# 2. 使用 Kria 官方模型
ubuntu-image snap kria-ubuntu-22.04.model \
--channel=stable \
--snap=kria-config \
-O kria-product.img
# 3. 挂载并注入产品文件
sudo losetup -Pf kria-product.img
sudo mount /dev/loop0p2 /mnt
sudo rsync -a overlay/ /mnt/
sudo chroot /mnt systemctl enable product-agent.service
sudo umount /mnt && sudo losetup -d /dev/loop0
验证要点:镜像能启动到登录提示;systemctl list-units --failed 无失败单元;产品服务随系统自启;df -h 显示 rootfs 占用符合预期(Kria KV260 上裁剪后通常可控制在 2 GB 以内)。
二、设备树覆盖(Device Tree Overlay)原理与编写
Kria 的 PL(可编程逻辑)与 PS(处理系统)外设通过设备树描述。由于载板差异大,AMD 采用 Device Tree Overlay 机制:基础设备树 system.dtb 描述 SOM 固定部分,overlay 以 .dtbo 形式在启动时叠加,动态添加或修改节点。Kria 的 kria-config 工具通过 /boot/firmware/config.txt 中的 dtoverlay= 行选择要加载的 overlay。
一个典型的 overlay 源文件结构如下(示例:使能 PL 端 AXI GPIO):
/dts-v1/;
/plugin/;
/ {
compatible = "xlnx,zynqmp-sk-kv260", "xlnx,zynqmp";
fragment@0 {
target-path = "/";
__overlay__ {
axi_gpio_0: gpio@a0000000 {
compatible = "xlnx,axi-gpio-2.0";
reg = <0x0 0xa0000000 0x0 0x10000>;
xlnx,all-inputs = <0x0>;
xlnx,gpio-width = <0x4>;
interrupts = <0 104 4>;
interrupt-parent = <&gic>;
clocks = <&clk 0>;
status = "okay";
};
};
};
};
编译与部署:
dtc -@ -I dts -O dtb -o axi-gpio.dtbo axi-gpio.dts
sudo cp axi-gpio.dtbo /boot/firmware/overlays/
echo "dtoverlay=axi-gpio" | sudo tee -a /boot/firmware/config.txt
sudo reboot
启动后验证:ls /proc/device-tree/ | grep gpio 应出现 gpio@a0000000;dmesg | grep axi-gpio 应显示驱动 probe 成功;gpiodetect 能看到对应 gpiochip。若节点未出现,优先检查 compatible 是否与驱动匹配、reg 地址是否与 PL 地址分配一致、status 是否为 okay。
三、外设使能与引脚复用配置
Kria 的 PS 外设(I2C、SPI、UART、以太网、USB)在基础设备树中默认可能处于 disabled。使能方式有两种:一是修改基础设备树,二是通过 overlay 覆盖 status。推荐后者,便于版本管理。
引脚复用(pinmux)由 pinctrl 节点描述。以 KV260 的 I2C1 为例,需在 overlay 中同时使能控制器并配置 MIO 引脚:
fragment@1 {
target = <&i2c1>;
__overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1_default>;
};
};
fragment@2 {
target = <&pinctrl>;
__overlay__ {
pinctrl_i2c1_default: i2c1-default {
mux {
groups = "i2c1_0_grp";
function = "i2c1";
};
conf {
groups = "i2c1_0_grp";
bias-pull-up;
slew-rate = <0>;
};
};
};
};
关键点:groups 名称必须与 SoC pinctrl 驱动中定义的一致(ZynqMP 的 pinctrl 定义在 drivers/pinctrl/pinctrl-zynqmp.c);bias-pull-up 对 I2C 是必需的;slew-rate 影响信号完整性,高速外设需按硬件手册调整。验证:i2cdetect -y 1 能扫描到从设备地址;cat /sys/kernel/debug/pinctrl/*/pinmux-pins 可确认引脚已绑定到 i2c1。
四、启动流程与固件更新
Kria 的启动链为:BootROM → FSBL(boot.bin)→ PMU Firmware → ATF(bl31.elf)→ U-Boot → Linux Kernel → rootfs。其中 boot.bin、bl31.elf、U-Boot 属于固件层,设备树与内核属于系统层。产品化时,固件更新必须与 rootfs 更新解耦,避免“刷一半变砖”。
Kria 提供 xkrtool 与 bootgen 用于生成 boot.bin;Ubuntu 侧可用 flash-kernel 或 fwupd 管理。推荐做法:
- 固件(boot.bin、bl31、U-Boot)放在 QSPI 或 eMMC 的独立分区,升级时先写备份分区再切换。
- 设备树与内核放在
/boot/firmware,随 rootfs 一起 A/B 升级。 - 使用
rauc时,system.conf中定义bootloader=uboot,通过fw_setenv切换bootslot。
验证启动链是否完整:串口日志应依次出现 FSBL、PMU、ATF、U-Boot、Kernel 版本;cat /proc/device-tree/chosen/u-boot,version 可确认 U-Boot 版本;fw_printenv 可查看当前 bootslot 与升级状态。
compatible 与驱动匹配,再确认 reg 地址与 PL 地址分配一致,最后检查 pinctrl 的 groups 名称是否与 SoC 驱动定义一致。三者中任一不匹配,节点都不会 probe 成功。boot.bin,若该文件损坏,设备将无法进入 U-Boot,只能通过 JTAG 恢复。把上述四件事串起来,产品化流程可以概括为:先用 ubuntu-image 生成裁剪后的 rootfs,再按载板编写 overlay 使能外设与 pinmux,接着用 bootgen 生成含 FSBL/ATF/U-Boot 的 boot.bin,最后通过 A/B 分区与 rauc 实现可回滚的固件更新。每一步都应在串口日志与 /proc/device-tree 中留下可验证的证据,而不是仅凭“能启动”就判定成功。