RK3566 AB升级功能

RK3566 AB升级功能

2026-2-15 hongxi.zhu

RK3566 Linux SDK (kernel 4.19) 泰山派

配置分区表

1. 创建ab升级专属的分区表

bash 复制代码
cd device/rockchip/rk356x/
touch parameter-buildroot-fit-ab.txt

配置内容如下(格式参考默认的parameter-buildroot-fit.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
CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot_a),0x00002000@0x00006000(uboot_b),0x00002000@0x00008000(misc),0x00020000@0x0000a000(boot_a),0x00020000@0x0002a000(boot_b),0x00020000@0x0004a000(recovery),0x00010000@0x0006a000(backup),0x00c00000@0x0007a000(system_a),0x00c00000@0x00c7a000(system_b),0x00040000@0x0187a000(oem),-@0x018ba000(userdata:grow)

RK的分区表各项说明

FIRMWARE_VER: 1.0 固件版本,打包updata.img时会使用到,升级工具会根据这个识别固件版本。
MACHINE_MODEL: RK3568 机器型号,打包updata.img使用,不同的项目,可以自己修改,用于升级工具显示。在recovery里面升级固件时可以用于判断固件是否匹配。
MACHINE_ID: 007 产品开发ID,可以为字符和数字组合,打包updata.img使用,不同的项目使用不同的ID,可以用于识别机器机型。在recovery里面升级固件时可以用于判断固件是否匹配。
MANUFACTURER: RK3568 厂商信息,打包updata.img使用,可以自己修改,用于升级工具显示。
MAGIC: 0x5041524B MAGIC,不能修改,一些新的AP使用DTS,这一项没有用,为了兼容,不要删除或修改。
ATAG: 0x00200800 ATAG,不能修改,一些新的AP使用DTS,这一项没有用,为了兼容,不要删除或修改。
MACHINE: 0xffffffff 内核识别用,不能修改,这个定义和内核匹配。
CHECK_MASK: 0x80 保留,不能修改。
TYPE: GPT 指定该文件CMDLINE里面定义的分区用于创建GPT使用,不会烧录到NVMNANDEMMC等)存储器件里面。
CMDLINE 下面说明

关于CMDLINE以下是摘自瑞芯微文档的说明:

  1. 为了兼容性,目前RK所有AP都是用rk29xxnand做标识。
  2. 单个分区说明:
    例如:0x00010000@0x00008000(boot)@符号之前的数值是分区大小,@符号之后的数值是分区的起始位置,括号里面的字符是分区的名字。所有数值的单位是sector1sector512Bytes。上例中,boot分区起始位置为0x8000 sectors位置,大小为0x10000 sectors(32MB)
  3. 为了性能,每个分区起始地址需要32KB(64 sectors)对齐,大小也需要32KB的整数倍。
  4. 如果使用sparse格式的镜像,升级时会擦除数据,为了兼容性更好,对应的分区最好按4MB对齐,大小也按4MB整数倍配置。
  5. 使用GPT分区时,parameter里面定义的地址,都是真实的逻辑地址(LBA),例如uboot定义在0x4000,那么烧录到EMMCNAND里面时,逻辑地址也是0x4000。最后一个分区需要指定grow参数,工具会把剩余的空间都分配给最后一个分区。

对于上述配置的parameter-buildroot-fit-ab.txt的内容,整理出来对应的分区layout就如下表格:

名称 起始地址 结束地址 大小
uboot_a 0x00004000(8M) 0x00006000(12M) 0x00002000(4M)
uboot_b 0x00006000(12M) 0x00008000(16M) 0x00002000(4M)
misc 0x00008000(16M) 0x0000a000(20M) 0x00002000(4M)
boot_a 0x0000a000(20M) 0x0002a000(84M) 0x00020000(64M)
boot_b 0x0002a000(84M) 0x0004a000(148M) 0x00020000(64M)
recovery 0x0004a000(148M) 0x0006a000(212M) 0x00020000(64M)
backup 0x0006a000(212M) 0x0007a000(244M) 0x00010000(32M)
system_a 0x0007a000(244M) 0x00c7a000(6388M) 0x00c00000(6144M)
system_b 0x00c7a000(6388M) 0x0187a000(12532M) 0x00c00000(6144M)
oem 0x0187a000(12532M) 0x018ba000(12660M) 0x00040000(128M)
userdata 0x018ba000(12660M) -- EMMC剩余容量

这里为啥EMMC分区要从8M的地方开始呢,因为前面的区域被系统一些固定的内容占用了,如分区表、Loader、reserved part等

名称 起始地址 大小
GPT分区表 0 32KB
Loader 0x00000040 4MB - 32KB
保留的区域 0x00002000 4MB

2. 创建分区镜像打包规则文件

bash 复制代码
cd tools/linux/Linurk356x-package-file-ab
touch rk356x-package-file-ab

配置内容如下(格式参考默认的rk356x-package-file为模版):

bash 复制代码
# NAME		Relative path
#
#HWDEF		HWDEF
package-file	package-file
bootloader	Image/MiniLoaderAll.bin
parameter	Image/parameter.txt
uboot_a		Image/uboot.img
uboot_b		Image/uboot.img
misc		Image/misc.img
boot_a		Image/boot.img
boot_b		Image/boot.img
recovery	Image/recovery.img
system_a	Image/rootfs.img
system_b	Image/rootfs.img
oem		Image/oem.img
userdata	Image/userdata.img
backup		RESERVED

内容实际上描述每个分区使用对应镜像, 当分区烧写时,将对应的镜像写入对应的分区(如果原本有数据就意味着覆盖重刷该分区)

开启AB升级相关的配置项

1. uboot

u-boot/configs/rk3568_defconfig

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	

2. kernel

kernel不需要配置

3. buildroot

buildroot/configs/rockchip_rk3566_defconfig

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

4. SDK

device/rockchip/rk356x/BoardConfig-rk3566-tspi-v10.mk

shell 复制代码
export RK_PARAMETER=parameter-buildroot-fit-ab.txt	# 使用创建的AB分区表描述文件
export RK_PACKAGE_FILE=rk356x-package-file-ab 		# 使用创建的AB打包规则文件
export RK_PACKAGE_FILE_AB=rk356x-package-file-ab 	# 使用创建的AB打包规则文件

编译&打包

bash 复制代码
./build.sh # 会编译出update_ab.img
# 这个就用于AB升级
rockdev/update_ab.img

使用updateEngine升级

验证升级

  1. 首先先使用固件烧录工具RKDevTool_Release烧写这个全分区镜像文件到设备上

  2. 查看当前运行的分区信息

    • 查看方式1(updateEngine工具)

      bash 复制代码
      root@RK356X:/# updateEngine --misc=display
      ...
      LOG_INFO :slot.[0]->priority = 14.
      LOG_INFO :slot.[0]->successful_boot = 0.
      LOG_INFO :slot.[0]->tries_remaining = 7.
      LOG_INFO :slot.[1]->priority = 15.
      LOG_INFO :slot.[1]->successful_boot = 0.
      LOG_INFO :slot.[1]->tries_remaining = 7.
      LOG_INFO :last_boot : 1.
      ...

      last_boot: 0-> slot A; 1 -> slot B

      priority: 15 -> 活跃分区;14 -> 非活跃分区

      因此例子这里显示启动的是B分区。

    • 查看方式2(cmdline方式)

      bash 复制代码
      root@RK356X:/# cat /proc/cmdline
      storagemedia= ... android_slotsufix=_b ...

      android_slotsufix: uboot传递给kernel的分区index,用于挂载对应slot分区的rootfs

      因此例子这里显示启动的是B分区。

    • 查看方式3 (uboot的启动log)

      bash 复制代码
      A/B-slot: _b, successful: 0, tries-remain: 7
  3. 在根目录下创建一个标识文件(用于验证切换分区后是否升级成功)

bash 复制代码
touch update_flag.txt
  1. 使用updateEngine
bash 复制代码
updateEngine --image_url=/mnt/udisk/update_ab.img --update --reboot

这个过程会有log, 显示相关镜像的写入和分区的详细信息

  1. 观察结果

    重启后观察分区是否为另外一个分区,且根目录下update_flag.txt是否存在,同时还可以使用下面的命令切换回上一个分区观察该文件是是否存在做对比。

    bash 复制代码
    updateEngine --misc=other
    reboot

关于引导方式的区别:

successful_boot 模式:UBoot启动时会读取A、B分区的状态信息,主要检查 successful_boot标志。它会优先引导被标记为成功(successful_boot=1)且优先级最高的分区。如果该分区启动失败,UBoot会清除其 successful_boot标志,并尝试引导另一个分区。当系统(如Linux内核)被成功加载并运行后,用户空间的守护进程(如 bootcontrol)会负责将当前分区的 successful_boot标志设置为1,表示本次启动成功。实际测试,RK平台当前successful_boot模式不支持自动切换引导分区

reset_retry 模式:UBoot读取分区状态后,会优先选择 priority最高且 tries_remaining > 0的分区进行引导,并在尝试前先将该分区的 tries_remaining减1。如果启动失败,流程回转,该分区的计数器会再次被扣除,直至降为0后,系统才会切换到另一个分区进行尝试。如果一个分区能成功启动到系统,系统服务会将该分区的 tries_remaining重置为最大值(通常是7次),并将 last_boot记录更新为当前槽位,为下一次启动积累"信任"

特性对比

特性维度 successful_boot 模式 reset_retry 模式
核心机制 依赖successful_boot 标志位。系统成功启动后会标记该分区为"已成功启动"。 依赖tries_remaining (剩余尝试次数)。为每个分区设置一个尝试次数计数器。
决策依据 优先选择历史上成功启动过的分区。 优先选择优先级最高且还有剩余尝试次数的分区。
重试行为 相对"宽松"。一个分区只要曾经成功过,就倾向于继续使用它。 相对"严格"。给新分区有限的尝试机会,若多次启动失败则果断放弃。
适用场景 追求启动成功率和稳定性,对启动速度不特别敏感的环境。 需要快速尝试并切换到新系统(如完成OTA更新后)的环境,常见于消费电子。

关于misc分区的内容

数据结构

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

u-boot/include/android_avb/avb_ab_flow.h

c 复制代码
// Rockchip A/B 分区引导槽状态

/* Struct used for recording per-slot metadata.
 *
 * When serialized, data is stored in network byte-order.
 */
typedef struct AvbABSlotData {
  /* Slot priority. Valid values range from 0 to AVB_AB_MAX_PRIORITY,
   * both inclusive with 1 being the lowest and AVB_AB_MAX_PRIORITY
   * being the highest. The special value 0 is used to indicate the
   * slot is unbootable.
   */
  uint8_t priority;  // 启动优先级,0~15,0 表示禁用

  /* Number of times left attempting to boot this slot ranging from 0
   * to AVB_AB_MAX_TRIES_REMAINING.
   */
  uint8_t tries_remaining;  // 剩余启动尝试次数(最多 7 次)

  /* Non-zero if this slot has booted successfully, 0 otherwise. */
  uint8_t successful_boot;  // 1 表示已成功启动过

  /* Reserved for future use. */
  uint8_t reserved[1];  // 保留(或平台自定义)
} AVB_ATTR_PACKED AvbABSlotData;
c 复制代码
// Rockchip A/B 分区信息结构(存放于 misc 分区偏移 2048 处,共 32 字节)

/* Struct used for recording A/B metadata.
 *
 * When serialized, data is stored in network byte-order.
 */
typedef struct AvbABData {
  /* Magic number used for identification - see AVB_AB_MAGIC. */
  uint8_t magic[AVB_AB_MAGIC_LEN]; // 结构体头部魔术字:"\0AB0"

  /* Version of on-disk struct - see AVB_AB_{MAJOR,MINOR}_VERSION. */
  uint8_t version_major;  // 主版本号
  uint8_t version_minor;  // 次版本号

  /* Padding to ensure |slots| field start eight bytes in. */
  uint8_t reserved1[2];  // 保留字节(对齐)

  /* Per-slot metadata. */
  AvbABSlotData slots[2];  // A/B 分区引导槽状态(两个槽)

  /* Reserved for future use. */
  uint8_t last_boot;  // 上次成功启动的槽:0 表示 slot_a,1 表示 slot_b
  uint8_t reserved2[11];  // 保留字节(填充到 32 字节)

  /* CRC32 of all 28 bytes preceding this field. */
  uint32_t crc32;  // 结构体 CRC 校验(覆盖前 28 字节)
} AVB_ATTR_PACKED AvbABData;

我上面的配置misc分区是第三个分区,使用fdisk -l可以看到

bash 复制代码
root@RK356X:/# fdisk -l /dev/mmcblk0
Found valid GPT with protective MBR; using GPT

Disk /dev/mmcblk0: 30535680 sectors, 2622M
Logical sector size: 512
Disk identifier (GUID): 203e0000-0000-4e6b-8000-14e0000074a2
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 30535646

Number  Start (sector)    End (sector)  Size Name
     1           16384           24575 4096K uboot_a
     2           24576           32767 4096K uboot_b
     3           32768           40959 4096K misc
     4           40960          172031 64.0M boot_a
     5          172032          303103 64.0M boot_b
     6          303104          434175 64.0M recovery
     7          434176          499711 32.0M backup
     8          499712        13082623 6144M system_a
     9        13082624        25665535 6144M system_b
    10        25665536        25927679  128M oem
    11        25927680        30535615 2249M userdata
    
# 或者通过块驱动节点查看 ls -al /dev/block/by-name/*
root@RK356X:/# ls -al /dev/block/by-name/*
lrwxrwxrwx 1 root root 15 Aug  4 09:00 /dev/block/by-name/backup -> ../../mmcblk0p7
lrwxrwxrwx 1 root root 15 Aug  4 09:00 /dev/block/by-name/boot_a -> ../../mmcblk0p4
lrwxrwxrwx 1 root root 15 Aug  4 09:00 /dev/block/by-name/boot_b -> ../../mmcblk0p5
lrwxrwxrwx 1 root root 15 Aug  4 09:00 /dev/block/by-name/misc -> ../../mmcblk0p3
lrwxrwxrwx 1 root root 16 Aug  4 09:00 /dev/block/by-name/oem -> ../../mmcblk0p10
lrwxrwxrwx 1 root root 15 Aug  4 09:00 /dev/block/by-name/recovery -> ../../mmcblk0p6
lrwxrwxrwx 1 root root 15 Aug  4 09:00 /dev/block/by-name/system_a -> ../../mmcblk0p8
lrwxrwxrwx 1 root root 15 Aug  4 09:00 /dev/block/by-name/system_b -> ../../mmcblk0p9
lrwxrwxrwx 1 root root 15 Aug  4 09:00 /dev/block/by-name/uboot_a -> ../../mmcblk0p1
lrwxrwxrwx 1 root root 15 Aug  4 09:00 /dev/block/by-name/uboot_b -> ../../mmcblk0p2
lrwxrwxrwx 1 root root 16 Aug  4 09:00 /dev/block/by-name/userdata -> ../../mmcblk0p11

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

bash 复制代码
root@RK356X:/# dd if=/dev/mmcblk0p3 bs=1 skip=2048 count=32 | hexdump -C
00000000  00 41 42 30 01 00 00 00  0e 07 00 00 0f 07 00 00  |.AB0............|
00000010  01 00 00 00 00 00 00 00  00 00 00 00 29 5b 03 07  |............)[..|
32+0 records in
32+0 records out
00000020
32 bytes copied, 0.00150938 s, 21.2 kB/s

解析后得到结论如下:

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

引导流程,kernel 4.19的流程比较老,网上的图不适合,关于successful_boot的逻辑不一样,后续补充,但是关于更新misc分区的地方是一样的,都是通过开机脚本设置的。

各种测试

待补充

相关推荐
SakitamaX2 小时前
LVS(Linux virual server)介绍与实验
linux·运维·lvs
小义_2 小时前
【Docker】知识八
linux·docker·云原生
开开心心_Every2 小时前
CDR版本转换工具,支持多版本互转免升级软件
linux·运维·服务器·云原生·edge·pdf·serverless
czxyvX3 小时前
009-Linux程序地址空间
linux
苏宸啊3 小时前
进程的概念
linux
yuezhilangniao3 小时前
程序人生-杂谈-简单对比一下 学霸和linux科学设计
linux·程序人生·职场和发展
只想恰口饭3 小时前
程序人生-Hello’s P2P
linux·c语言·ubuntu
hoperest3 小时前
程序人生-Hello‘s P2P
linux·c语言·程序人生·ubuntu
quixoticalYan3 小时前
哈工大计算机系统大作业报告-程序人生-Hello’s P2P
linux·windows·程序人生·ubuntu·课程设计