RK3568 AB分区+OTA升级(Linux)

文章目录

1、前言

硬件:飞凌ok3568-c开发板

软件:原厂rk356x sdk(Linux)

2、概念理清

前段时间发布了一个基于uboot的镜像更新菜单:https://github.com/Cohen0415/USUM,可以通过uboot菜单来更新镜像。但这种方式在更新镜像时,整个系统是不可被使用的,必须升级完后才可使用,我们将这种更新称为"离线更新"。

而AB分区概念的诞生,是为了实现"在线更新",即镜像更新过程中,不影响当前系统的正常运行。

3、Rockchip Linux A/B

这里简单介绍下原理,文章结尾会再着重介绍。

目前只对 boot 和 system 进⾏了双分区:

其实就是为内核和rootfs多弄了一个分区。届时uboot根据misc分区的一些标志位来决定引导那个分区。

4、实践

4.1、替换分区表

sdk中提供了AB分区的分区表parameter-buildroot-fit-ab.txt

shell 复制代码
FIRMWARE_VER: 1.0
MACHINE_MODEL: RK3568
MACHINE_ID: 007
MANUFACTURER: RK3568
MAGIC: 0x5041524B
ATAG: 0x00200800
MACHINE: 0xffffffff
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
GROW_ALIGN: 0
CMDLINE: mtdparts=:0x00002000@0x00004000(uboot),0x00002000@0x00006000(misc),0x00020000@0x00008000(boot_a),0x00020000@0x00028000(boot_b),0x00010000@0x00048000(backup),0x00c00000@0x00058000(system_a),0x00c00000@0x00c58000(system_b),0x00040000@0x01858000(oem),-@0x01898000(userdata:grow)

将方案中的分区表换成parameter-buildroot-fit-ab.txt,以便于后续打包生成的镜像是支持AB分区的:

4.2、uboot配置

uboot需开启以下配置:

shell 复制代码
CONFIG_AVB_LIBAVB=y
CONFIG_AVB_LIBAVB_AB=y
CONFIG_AVB_LIBAVB_ATX=y
CONFIG_AVB_LIBAVB_USER=y
CONFIG_RK_AVB_LIBAVB_USER=y
CONFIG_ANDROID_AB=y						# 启用 A/B 引导槽机制(核心)

4.3、buildroot配置

buildroot开启以下配置后,系统会多出一个工具叫updateEngine,该工具由rk实现,后续将使用该工具完成镜像的更新操作。

shell 复制代码
BR2_PACKAGE_RECOVERY=y					# 开启升级功能
BR2_PACKAGE_RECOVERY_BOOTCONTROL=y		# 开启引导控制脚本
BR2_PACKAGE_RECOVERY_RETRY=y			# 引导⽅式为retry模式,不配置则默认为successful_boot模式
BR2_PACKAGE_RECOVERY_USE_UPDATEENGINE=y # 使⽤新升级程序
BR2_PACKAGE_RECOVERY_UPDATEENGINEBIN=y 	# 编译新升级程序
BR2_PACKAGE_RECOVERY_NO_UI=y			# 关掉UI

这个工具倒不是必须的,你也可以自己实现镜像的更新操作。

4.4、编译打包镜像

至此,编译打包镜像,并更新到板卡,以确保系统镜像是支持AB分区的:

shell 复制代码
./build.sh

进入系统后,在根目录下创建一个文件,用于验证后续rootfs是否更新成功:

shell 复制代码
echo 666 > flag.txt

4.5、生成OTA镜像

我们需要生成一个专门用于AB系统的ota镜像,在sdk根目录下执行:

shell 复制代码
./build.sh ota-updateimg

ota镜像位于:

shell 复制代码
<sdk>/output/update-ota/update.img

将update.img拷贝至板卡。

4.6、OTA升级

使用updateEngine工具进行本地ota升级:

shell 复制代码
# 后台运行,不影响目前系统正常工作
updateEngine --image_url=/mnt/udisk/update.img --update --reboot &

# 如果想网络升级
# updateEngine --image_url=http://172.16.21.110:8080/linuxab/update.img --update --reboot &

4.7、验证

更新完后,系统会自动重启,此时观察根目录已经不存在flag.txt文件,说明系统在线更新成功。

5、AB系统升级流程的详细介绍

5.1、数据结构

misc分区的2k偏移处存放了如下结构体,用于存放 slot_a 和 slot_b 的引导信息:

c 复制代码
// Rockchip A/B 分区信息结构(存放于 misc 分区偏移 2048 处,共 32 字节)
typedef struct AvbABData {			
    uint8_t magic[4];  				// 结构体头部魔术字:"\0AB0"
    uint8_t version_major;			// 主版本号
    uint8_t version_minor;			// 次版本号
    uint8_t reserved1[2];			// 保留字节(对齐)

    // A/B 分区引导槽状态(两个槽)
    struct SlotData {				
        uint8_t priority;			// 启动优先级,0~15,0 表示禁用
        uint8_t tries_remaining;	// 剩余启动尝试次数(最多 7 次)
        uint8_t successful_boot;	// 1 表示已成功启动过
        uint8_t is_update;			// 1 表示升级成功,后 7 位为保留(或平台自定义)
    } slots[2]; // slot_a、slot_b,共 8 字节

    uint8_t last_boot;				// 上次成功启动的槽:0 表示 slot_a,1 表示 slot_b
    uint8_t reserved2[11];			// 保留字节(填充到 32 字节)
    uint32_t crc32;					// 结构体 CRC 校验(覆盖前 28 字节)
} AvbABData;

整个AvbAbData结构体大小为32Byte,存储在misc分区的2KByte偏移处。可以通过dd命令查看其数据,如下是第一次烧录镜像后的misc分区数据:

shell 复制代码
root@rk3568-buildroot:/# dd if=/dev/mmcblk0p2 bs=1 skip=2048 count=32 | hexdump -C
00000000  00 41 42 30 01 00 00 00  0f 07 00 00 0e 07 00 00  |.AB0............|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 79 f1 e5 bf  |............y...|

解析后得到结论如下:

shell 复制代码
字段							值						含义
magic						00 41 42 30				"\0AB0",结构有效
version						1.0						A/B 数据结构版本
slot_a.priority				15						启动优先级
slot_a.tries_remaining		7						剩余启动尝试次数
slot_a.successful_boot		0						未标记成功启动(Successful boot模式才有用)
slot_a.is_update			0						表示升级是否成功(可选,平台自定义)
slot_b.priority				14						启动优先级
slot_b.tries_remaining		7						剩余启动尝试次数
slot_b.successful_boot		0						未标记成功启动(Successful boot模式才有用)
slot_b.is_update			0						表示升级是否成功(可选,平台自定义)
last_boot					0						上次引导的是 slot_a
crc32						0x79f1e5bf				CRC 校验值

5.2、引导流程

引导⽅式分为 successful_boot 和 reset retry。 两种模式的对⽐如下:

下图为引导流程图:

例如现在我们使用的是reset retry模式:

  1. uboot读取misc分区
  2. 镜像的crc校验
  3. 比较优先级
  4. 当系统A优先级最高时,同时tries_remaining>0,tries_remaining减一
  5. 开始引导系统A,引导失败重回第一步。引导成功后,通过bootcontrol设置misc

这里最后一步中的通过bootcontrol设置misc,其实就是通过/etc/init.d/S99_bootcontrol脚本,将tries_remaining设置为7,last_boot设置为0。

若此时通过updateEngine升级镜像,升级的就是系统B。升级结束后会将系统B的优先级设置为15,系统A的优先级设置为14。下次重启,将引导的是系统B,流程和上述一样。

6、总结

参考文章:

《Rockchip_Developer_Guide_Linux_Upgrade_CN.pdf》

rk3568 A/B系统 OAT升级 实践_ok3568-c配置ab分区-CSDN博客