为Mender配置支持A/B分区的U-Boot环境
Radxa Zero A/B分区与U-Boot环境配置方案
问题背景
正在Radxa Zero设备上实现A/B分区,用于Mender系统更新及回滚。已通过PARTUUID解决设备编号随机变化问题,更新流程如下:
- 自定义脚本覆盖rootfsB后,执行
fw_setenv upgrade_available 1 - rootfsB启动成功后,执行
fw_setenv upgrade_available 0和fw_setenv bootcount 0
当前fw_config.cfg已配置U-Boot环境存储在数据分区的/mnt/uboot.env中,需解决以下核心问题:
- 将
uboot.env加载到U-Boot - 从操作系统写入并保留环境变量更改
- 确保
bootcount等于bootlimit时,altbootcmd控制启动分区切换
设备规格
| 组件 | 规格 |
|---|---|
| SBC | Radxa Zero v1.51,2GB RAM,8GB eMMC,4核 |
| SOC | S905Y2 |
| Processor | ARM Cortex-A53 |
| Architecture | ARMv8-A |
| WiFi/BT | AP6256,BCM43456/BCM4345C5,b/g/n/a/ac - BT5.0 |
| OS | Buildroot 2022.11,System V |
| Kernel | 最新CIP SLTS版本(5.10.145-cip17) |
| Bootloader | 带厂商FIP的自定义U-Boot 2021.01 |
| Pinout | 官方引脚定义 |
| Quick Reference Manual | 官方快速参考手册 |
一、U-Boot侧加载环境文件配置
1. 配置数据分区挂载逻辑(基于PARTUUID)
在U-Boot中添加环境变量,通过PARTUUID定位数据分区,避免设备名变化:
# 设置存储设备类型与编号(Radxa Zero的eMMC通常是mmc 0) setenv devtype mmc setenv devnum 0 # 获取数据分区的PARTUUID(替换<数据分区编号>为实际值,如3) part uuid ${devtype} ${devnum}:<数据分区编号> partuuid_data
2. 定义环境文件加载脚本
创建loadenv_from_data变量,用于从数据分区加载uboot.env:
setenv loadenv_from_data 'fatload ${devtype} ${devnum}:<数据分区编号> ${loadaddr} uboot.env && env import -t ${loadaddr} ${filesize}'
3. 调整启动流程优先加载环境文件
修改bootcmd,确保U-Boot启动时先加载自定义环境文件:
setenv bootcmd 'run loadenv_from_data; <原bootcmd内容>'
注:若未保存环境变量,需执行
saveenv(此时会将当前U-Boot环境写入默认存储,后续启动会优先加载uboot.env)
二、操作系统侧写入与保留环境变量更改
1. 验证fw_config.cfg配置
确保fw_config.cfg中正确指定环境文件路径与大小(大小需与U-Boot环境变量总容量一致,通常为0x2000或0x4000):
/mnt/uboot.env 0x2000
2. 持久化挂载数据分区
在/etc/fstab中添加PARTUUID挂载项,确保系统启动时自动挂载数据分区:
PARTUUID=<数据分区PARTUUID> /mnt vfat defaults 0 2
执行 mount -a 验证挂载,重启后确认/mnt/uboot.env可访问。
3. 权限与写入验证
- 确保
fw_setenv工具拥有足够权限:chown root:root /usr/sbin/fw_setenv chmod u+s /usr/sbin/fw_setenv - 写入环境变量后,用
fw_printenv验证更改:fw_setenv upgrade_available 1 fw_printenv upgrade_available
三、A/B分区启动逻辑配置与验证
1. 核心环境变量配置
通过fw_setenv设置以下关键变量:
# 设置启动失败重试次数 fw_setenv bootlimit 3 # 定义rootfsA启动逻辑(替换<rootfsA的PARTUUID>) fw_setenv boot_rootfsA 'setenv root PARTUUID=<rootfsA的PARTUUID>; run boot_kernel' # 定义rootfsB启动逻辑(替换<rootfsB的PARTUUID>) fw_setenv boot_rootfsB 'setenv root PARTUUID=<rootfsB的PARTUUID>; run boot_kernel' # 通用内核启动脚本(替换<boot分区编号>,通常为1) fw_setenv boot_kernel 'fatload ${devtype} ${devnum}:<boot分区编号> ${kernel_addr_r} Image; fatload ${devtype} ${devnum}:<boot分区编号> ${fdt_addr_r} dtb/amlogic/meson-g12a-radxa-zero.dtb; booti ${kernel_addr_r} - ${fdt_addr_r}' # 主启动命令:根据upgrade_available选择启动分区 fw_setenv bootcmd 'run loadenv_from_data; if test ${upgrade_available} -eq 1; then run boot_rootfsB; else run boot_rootfsA; fi' # 回滚命令:当bootcount达到bootlimit时触发,切回rootfsA并重置计数 fw_setenv altbootcmd 'setenv upgrade_available 0; setenv bootcount 0; run boot_rootfsA'
2. 启动计数与回滚验证
- 确保U-Boot已启用
CONFIG_BOOTCOUNT_LIMIT配置(编译时开启) - 手动测试回滚:设置
bootcount等于bootlimit,重启后验证是否自动切换到rootfsAfw_setenv bootcount 3 reboot
内容的提问来源于stack exchange,提问作者mister_kanister
相关产品推荐
相关产品推荐

