RK 平台升级开发:全场景方案与实践指南,覆盖常规系统和ab系统

电子说

1.4w人已加入

描述

 

 

 

 

 

 

在嵌入式Linux开发领域,瑞芯微(Rockchip)平台凭借其稳定的性能和丰富的生态支持,被广泛应用于各类智能设备中。而设备的升级功能作为保障产品生命周期、优化用户体验的核心模块,其开发质量直接影响产品的市场竞争力。本文基于Rockchip Linux updateEngine升级方案官方文档,系统梳理RK平台升级开发的核心技术方案、实现流程及关键注意事项,为开发工程师提供全面的实践指引。

开始之前我们先看一下spi+pcie升级log:

  •  
root@linaro-alip:/# updateEngine --image_url=/userdata/update.img --misc=update --savepath=/userdata/update.img --reboot &[1] 3788root@linaro-alip:/# LOG_INFO: *** update_engine: V1.0.1-g ***.LOG_INFO: Current Mode is 'A' system.LOG_INFO: start RK_ota_url url [/userdata/update.img] save path [/userdata/update.img].LOG_INFO: save image to /userdata/update.img.LOG_INFO: url = /userdata/update.img.LOG_INFO: [MiscUpdate:90] save path: /userdata/update.imgLOG_INFO: In A system, now upgrade B system.LOG_INFO: [RK_ota_set_partition:125] num [16]LOG_INFO: need update parameter.LOG_INFO: need update uboot_b.LOG_INFO: need update boot_b.LOG_INFO: need update system_b.LOG_INFO: start RK_ota_start.LOG_INFO: rk m_status = 1.LOG_INFO: where the file is local.LOG_INFO: [RK_ota_set_partition:125] num [16]LOG_INFO: entry 0: storage = 512 firmware_offset = 192, firmware_size = 6226506LOG_INFO: entry 1: storage = 2048 firmware_offset = 6226698, firmware_size = 5079775818LOG_DEBUG: uiTag = 57464b52.LOG_DEBUG: usSize = 66.LOG_DEBUG: dwVersion = 1000000.LOG_DEBUG: btMajor = 1, btMinor = 0, usSmall = 00.LOG_DEBUG: dwBootOffset = 66.LOG_DEBUG: dwBootSize = 771c0.LOG_DEBUG: dwFWOffset = 77226.LOG_DEBUG: dwFWSize = 579004.LOG_DEBUG: tag = 1178684242 size = 5738496 machine_model =  RK3588 manufacturer =  RK3588 version = 16777216 item = 5.LOG_INFO: ================================================LOG_DEBUG: name = package-file file = package-file offset = 490214 flash_offset = -1 usespace = 1 size = 127LOG_DEBUG: name = parameter file = parameter.txt offset = 492262 flash_offset = 0 usespace = 1 size = 299LOG_DEBUG: name = bootloader file = MiniLoaderAll.bin offset = 102 flash_offset = -1 usespace = 239 size = 487872LOG_DEBUG: name = uboot_a file = uboot.img offset = 983782 flash_offset = 16384 usespace = 2560 size = 5242880LOG_DEBUG: name = uboot_b file = uboot.img offset = 983782 flash_offset = 32768 usespace = 2560 size = 5242880LOG_INFO: new md5:7ea81bce7a98f59d890aafb5009c9f1bLOG_INFO: MD5Check is ok of /userdata/update.imgLOG_ERROR: MD5Check is error of /userdata/update.imgLOG_ERROR: Md5Check update.img fwSize:6226474LOG_DEBUG: uiTag = 57464b52.LOG_DEBUG: usSize = 66.LOG_DEBUG: dwVersion = 1000000.LOG_DEBUG: btMajor = 1, btMinor = 0, usSmall = 00.LOG_DEBUG: dwBootOffset = 66.LOG_DEBUG: dwBootSize = 771c0.LOG_DEBUG: dwFWOffset = 77226.LOG_DEBUG: dwFWSize = 2ebfc804.LOG_DEBUG: tag = 1178684242 size = 784320512 machine_model =  RK3588 manufacturer =  RK3588 version = 16777216 item = 10.LOG_INFO: ================================================LOG_DEBUG: name = package-file file = package-file offset = 6716720 flash_offset = -1 usespace = 1 size = 227LOG_DEBUG: name = parameter file = parameter.txt offset = 6718768 flash_offset = 0 usespace = 1 size = 460LOG_DEBUG: name = bootloader file = MiniLoaderAll.bin offset = 102 flash_offset = -1 usespace = 239 size = 487872LOG_DEBUG: name = misc file = misc.img offset = 7210288 flash_offset = 16384 usespace = 24 size = 49152LOG_DEBUG: name = boot_a file = boot.img offset = 7259440 flash_offset = 24576 usespace = 17525 size = 35889664LOG_DEBUG: name = boot_b file = boot.img offset = 7259440 flash_offset = 155648 usespace = 17525 size = 35889664LOG_DEBUG: name = system_a file = rootfs.img offset = 43150640 flash_offset = 352256 usespace = 2450944 size = 724566016LOG_DEBUG: name = system_b file = rootfs.img offset = 43150640 flash_offset = 15032320 usespace = 2450944 size = 724566016LOG_DEBUG: name = oem file = oem.img offset = 767716656 flash_offset = 29712384 usespace = 9182 size = 18804736LOG_DEBUG: name = userdata file = userdata.img offset = 786521392 flash_offset = 29974528 usespace = 2204 size = 4513792LOG_INFO: new md5:1fdb493d189fec4198c90d2f27974e9cLOG_INFO: MD5Check is ok of /userdata/update.imgLOG_ERROR: MD5Check is error of /userdata/update.imgLOG_ERROR: Md5Check update.img fwSize:784808490LOG_INFO: found rkimage_hdr.item[1].name = parameter mtd = 0.LOG_INFO: found rkimage_hdr.item[6].name = parameter mtd = 0.LOG_INFO: found rkimage_hdr.item[4].name = uboot_b mtd = 0.LOG_INFO: found rkimage_hdr.item[10].name = boot_b mtd = 0.LOG_INFO: found rkimage_hdr.item[12].name = system_b mtd = 0.LOG_INFO: size more than 4G, after adjusting is 5019533312.LOG_INFO: Current device is not MTDLOG_INFO: now write parameter to /dev/block/by-name/gpt.LOG_INFO: ingore misc.LOG_INFO: now write uboot_b to /dev/block/by-name/uboot_b.LOG_INFO: update_cmd.flash_offset = 0.LOG_INFO: flash_normal:200 start.LOG_INFO: flash_normal:222, diff check for uboot_bLOG_WARN: Not a diff image, ret = 80LOG_INFO: block_write src /userdata/update.img dest /dev/block/by-name/uboot_b.LOG_INFO: new md5:fdc69aec10a16d9d81b1a08b6ce8305dLOG_INFO: MD5Check is ok of /dev/block/by-name/uboot_bLOG_INFO: new md5:fdc69aec10a16d9d81b1a08b6ce8305dLOG_INFO: MD5Check is ok of /userdata/update.imgLOG_INFO: check /dev/block/by-name/uboot_b ok.LOG_INFO: now write boot_b to /dev/block/by-name/boot_b.LOG_INFO: update_cmd.flash_offset = 0.LOG_INFO: flash_normal:200 start.LOG_INFO: flash_normal:222, diff check for boot_bLOG_WARN: Not a diff image, ret = 80LOG_INFO: block_write src /userdata/update.img dest /dev/block/by-name/boot_b.LOG_INFO: new md5:8ac9471d56990e08c4b1b9245f32a002LOG_INFO: MD5Check is ok of /dev/block/by-name/boot_bLOG_INFO: new md5:8ac9471d56990e08c4b1b9245f32a002LOG_INFO: MD5Check is ok of /userdata/update.imgLOG_INFO: check /dev/block/by-name/boot_b ok.LOG_INFO: now write system_b to /dev/block/by-name/system_b.LOG_INFO: update_cmd.flash_offset = 0.LOG_INFO: flash_normal:200 start.LOG_INFO: flash_normal:222, diff check for system_bLOG_WARN: Not a diff image, ret = 80LOG_INFO: block_write src /userdata/update.img dest /dev/block/by-name/system_b.LOG_INFO: new md5:ba696b83e3db9d44f45c2a5378762517LOG_INFO: MD5Check is ok of /dev/block/by-name/system_bLOG_INFO: new md5:ba696b83e3db9d44f45c2a5378762517LOG_INFO: MD5Check is ok of /userdata/update.imgLOG_INFO: check /dev/block/by-name/system_b ok.LOG_INFO: RK_ota_start is ok!LOG_INFO: rk ota success.LOG_INFO: Current Mode is 'A' system.LOG_INFO: Current device is not MTDLOG_INFO: Current device is not MTDLOG_INFO: rk m_status = 0.

 

 

 

一、升级方案核心架构:两种启动模式的选择与对比

 

 

RK Linux平台提供两种核心升级启动模式,分别适配不同的应用场景,开发人员需根据产品需求灵活选择。

 

 

(一)Recovery模式

 

 

Recovery模式通过在设备中划分独立的recovery分区(由kernel+resource+ramdisk组成)专门负责升级操作。其核心逻辑是通过u-boot读取misc分区的引导参数,判断是否进入Recovery系统执行升级。

 

 

优势:升级完整性强,即便过程中出现异常掉电等中断情况,重启后仍可继续执行升级,避免升级失败导致设备故障。

 

 

劣势:额外占用存储分区资源,且升级必须重启进入Recovery模式,无法在正常系统(Normal系统)中直接完成。

 

 

(二)Linux A/B模式

 

 

A/B模式采用双固件设计,设备中存储两套独立的系统(slot Aslot B),可实现无缝切换。升级时无需进入专用升级模式,在Normal系统中即可完成,重启后直接切换到升级后的系统。

 

 

优势:升级过程无需切换至专用模式,用户体验流畅;双系统冗余设计可有效防止设备变砖,若当前slot升级失败或系统损坏,可自动切换至另一slot启动;支持版本回滚,保障系统稳定性。

 

 

劣势:双系统设计会增加Flash存储占用率,对存储资源要求更高。

 

 

两种模式的核心差异还体现在代码支持上:updateEngine工具同时支持两种模式(RV1126/RV1109平台专用),而rkupdate工具仅支持Recovery模式(适用于其他平台)。

 

 

二、关键升级场景的实现流程

 

 

(一)基础OTA升级:RecoveryA/B模式通用实现

 

 

OTAOver-the-Air)升级是设备远程更新的核心方式,支持网络下载升级和本地升级两种形式,核心流程如下:

 

 

1.版本校验:通过--version_url参数指定版本文件地址,与设备本地/etc/version中的版本号对比,判断是否需要升级(该参数可缺省,缺省时跳过版本校验)。

 

 

2.固件获取:通过--image_url参数指定远程固件地址或本地固件路径,下载并保存至--savepath指定的目录(默认路径为/tmp/update.img,建议自定义为/userdata/update.img以避免临时目录空间不足)。

 

 

3.分区升级:通过--partition参数指定待升级分区(建议使用0x3FFC00,不支持升级parameterloader分区)。

 

 

4.重启生效:添加--reboot参数,升级完成后自动重启设备,Recovery模式重启进入Recovery系统完成最终升级,A/B模式重启后切换至升级后的slot

 

 

示例命令

 

 

网络升级(A/B模式):

updateEngine --image_url=http://xxx/update_ota.img --update --reboot

 

 

本地升级(Recovery模式):

updateEngine --image_url=/userdata/update.img --misc=update --reboot &

 

 

(二)差分升级:高效压缩升级包

 

 

针对大尺寸固件升级时带宽占用高、传输耗时久的问题,RK平台支持差分升级方案,通过制作新旧固件的差分补丁包(update_diff.img),仅传输变化部分数据,大幅降低升级包体积。

 

 

1. 前置依赖

 

 

代码依赖:需确保buildrootexternal/recoverytools目录中包含差分升级相关补丁(如0001-ota-add-diff-firmware-script.patch等)。

 

 

工具依赖:PC端需安装bsdiffsudo apt install bsdiff)和md5sum工具。

 

 

2. 关键限制

 

 

支持分区:uboot/trust/kernel分区及squashfs格式的rootfs分区。

 

 

不支持场景:ext2/ext4文件系统、mtd驱动的nand flash系统、加密分区及A/B模式。

 

 

分区空间要求:存储差分补丁包的分区(如userdata)空闲空间需不小于差分包(update_diff.img)与完整新rootfs.img的体积之和。

 

 

3. 补丁包制作

 

 

通过工具脚本实现新旧固件的差分处理,命令如下:

 

 

  •  
  •  
cd tools/linux/Linux_Diff_Firmware/./mk-diff-ota.sh update_old.img update_new.img update_diff.img

生成的update_diff.img可直接通过updateEngine工具进行OTA升级。

 

 

(三)SD卡启动盘升级:离线升级方案

 

 

SD卡升级适用于设备无法联网或首次烧录固件的场景,需根据系统模式区分制作流程:

 

 

1. 通用制作步骤

 

 

使用RK提供的SDDiskTool工具(Windows端路径:toolswindowsSDDiskTool),选择目标SD卡、升级模式(SD启动),加载对应的固件文件,点击开始创建生成启动盘。成功后SD卡根目录会生成sdupdate.img(由原始update.img重命名而来),将SD卡插入设备并重启即可自动触发升级。

 

 

2. 模式专属配置

 

 

Recovery模式:直接使用update.img通过SDDiskTool制作启动盘。

 

 

A/B模式:需先通过SDK编译生成update_sdcard.img(专门用于制作A/B模式启动盘),用该镜像制作启动盘后,再将update_ab.img(完整双分区固件)或update_ota.img(单slot固件)拷贝至SD卡,设备启动时会优先识别update_ab.img

 

 

(四)恢复出厂设置:数据清除方案

 

 

恢复出厂设置的核心是格式化userdata分区(存储用户配置数据和应用数据),回归出厂默认配置,实现方式如下:

 

 

1.触发方式:通过硬件按键组合(RECOVERY + VOLUMEUP)触发,或执行命令updateEngine --misc=wipe_userdata --reboot

 

 

2.执行流程:命令会向misc分区偏移4K位置写入格式化指令,设备重启后,S21mountall.sh脚本识别该指令并格式化userdata分区。

 

 

3.注意事项:--reboot参数可缺省,缺省时需等待设备下次重启才会执行格式化。

 

 

三、开发配置与编译关键步骤

 

 

(一)Recovery模式编译配置

 

 

1.Buildroot配置(make menuconfig):

 

 

  •  
  •  
  •  
  •  
  •  
BR2_PACKAGE_RECOVERY=y  # 开启升级功能BR2_PACKAGE_RECOVERY_USE_UPDATEENGINE=y  # 使用updateEngine工具BR2_PACKAGE_RECOVERY_RECOVERYBIN=y  # 开启recovery bin文件BR2_PACKAGE_RECOVERY_UPDATEENGINEBIN=y  # 编译updateEngineBR2_PACKAGE_RECOVERY_NO_UI=y  # 关闭UI(无屏设备必选)

2.编译命令:

 

 

  •  
  •  
  •  
  •  
  •  
source envsetup.sh# 选择对应平台的rootfs和recovery配置make clean:recovery./build.sh# 新SDK可简化为:./build.sh recovery && ./build.sh

(二)A/B模式编译配置

 

 

1.Uboot配置(修改defconfig,如rk3308_defconfig):

 

 

  •  
  •  
  •  
CONFIG_AVB_LIBAVB=yCONFIG_AVB_LIBAVB_AB=yCONFIG_ANDROID_AB=y

2.Buildroot配置(make menuconfig):

 

 

  •  
  •  
  •  
  •  
BR2_PACKAGE_RECOVERY=yBR2_PACKAGE_RECOVERY_BOOTCONTROL=y  # 开启引导控制脚本BR2_PACKAGE_RECOVERY_RETRY=  # 可选,引导模式为reset retry(默认successful boot)BR2_PACKAGE_RECOVERY_USE_UPDATEENGINE=y

3.分区表配置:在BoardConfig.mk中指定A/B模式分区表,如export RK_PARAMETER=parameter-ab-64bit.txt

 

 

4.固件输出:编译后生成update_ab.img(烧录用)、update_ota.imgOTA升级用)、update_sdcard.imgSD卡启动用)。

 

 

(三)自定义分区升级

 

 

若需扩展升级自定义分区(如factory分区),需修改external/recovery/update_engine/update.cpp中的UPDATE_CMD结构体数组,添加自定义分区配置:

 

 

  •  
{"factory"falsefalse000"", flash_normal},

同时在--partition参数中设置对应位值为1,确保升级工具识别该分区。

 

 

(四)SPI+PCIe方案专属配置:patch添加说明

 

 

若采用SPI+PCIe存储方案(区别于上述eMMC方案),需额外添加以下专属patch以保障升级功能正常实现,否则可能出现无法进入系统的问题,具体操作及问题说明如下:

 

 

1. 必备patch清单

 

 

核心驱动适配patch0001-spi-pcie-storage-adapt-update-engine.patch(适配SPI+PCIe存储设备与updateEngine工具的通信驱动,解决存储识别异常问题)

 

 

分区管理优化patch0002-spi-pcie-partition-manager-enhance.patch(优化SPI+PCIe方案下的分区读写逻辑,提升升级过程中数据传输稳定性)

 

 

A/B模式根分区适配patch:修改u-boot/common/android_ab.c文件(解决SPI+PCIe方案下A/B模式启动时根分区识别失败问题),具体patch内容如下:

  •  
  •  
--- a/u-boot/common/android_ab.c+++ b/u-boot/common/android_ab.c@@ -472,6 +472,7 @@ void ab_update_root_partition(void)        /* Judge the partition device type. */        switch (dev_desc->if_type) {        case IF_TYPE_MMC:+       case IF_TYPE_SCSI: /* scsi 0: UFS */                if (strstr(part_type, "ENV"))                        snprintf(root_part_dev, 64, "root=/dev/mmcblk0p%d", part_num);                else if (strstr(part_type, "EFI"))@@ -496,6 +497,8 @@ void ab_update_root_partition(void)                break;        default:                printf("%s: Not found part type, failed to set root part device.n", __func__);+               ab_update_root_uuid();+               printf("Unknown part type, set default 'root=' with UUID.n");                return;        }

2. 未添加patch的报错信息

 

 

若未添加上述A/B模式根分区适配patch,设备启动时会因根分区识别失败无法进入系统,具体错误日志如下:

 

 

  •  
  •  
  •  
[    4.933965] nvme nvme0: 8/0/0 default/read/poll queues[    4.940453]  nvme0n1: p1 p2 p3 p4 p5 p6 p7 p8[    4.940808Waiting for root device ...

四、调试与问题排查

 

 

(一)日志查看

 

 

1.串口日志:在buildroot/output/rockchip_***/target目录下创建隐藏文件.rkdebug,可在串口输出Recovery模式升级日志。

 

 

2.文件日志:升级完成后,在设备userdata/recovery/log文件中查看详细升级记录,命令:cat userdata/recovery/log

 

 

(二)常见问题解决

 

 

1.升级失败:检查分区空间是否充足(尤其是差分升级时的userdata分区)、固件是否为对应模式支持的格式(A/B模式需使用update_ota.imgupdate_ab.img)、--partition参数是否包含不支持的分区(如loaderparameter)。

 

 

2.A/B模式切换失败:检查misc分区中引导参数(偏移2K位置)是否正确,通过updateEngine --misc=display调试查看分区引导信息,确保slot优先级和尝试启动次数配置合理。

 

 

3.SD卡升级无响应:确认SD卡启动盘制作正确(A/B模式需包含update_sdcard.img和对应的升级固件)、SD卡是否正常识别、固件文件名是否为sdupdate.img

 

 

五、工具与附录支持

 

 

(一)固件打包工具

 

 

1.Windows平台:toolswindowsAndroidToolrockdev,修改package-file文件指定需打包的镜像,执行mkupdate.bat生成update.img

 

 

2.Linux平台:tools/linux/Linux_Pack_Firmware/rockdev,修改package-file文件,执行mkupdate.sh生成update.img

 

 

(二)Misc分区关键说明

 

 

Misc分区为无文件系统分区,用于存储引导配置参数,核心偏移地址功能如下:

 

 

2K位置:存储A/B模式分区引导信息(优先级、启动次数、启动状态等)。

 

 

4K位置:存储格式化命令(恢复出厂设置用)。

 

 

16K位置:实现Recovery系统与Normal系统的通信。

 

 

结语

 

 

RK平台的升级方案覆盖了OTA远程升级、SD卡离线升级、差分升级等全场景需求,开发人员需根据产品的存储资源、用户体验要求选择合适的启动模式。在实际开发过程中,需重点关注编译配置的完整性、分区空间的合理性及日志调试的有效性,同时遵循官方对分区升级的限制(如不支持loaderparameter分区升级),确保升级功能的稳定性和可靠性。通过本文的梳理,希望能为RK平台开发工程师提供清晰的升级开发路径,助力高效完成产品升级模块的设计与实现。

下期我们详细分析ab系统下spi+pcie双存储方案升级的点点滴滴。


审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 相关推荐
  • 热点推荐
  • L

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分