在嵌入式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:LOG_INFO: entry0: storage =512firmware_offset =192, firmware_size =6226506LOG_INFO: entry1: storage =2048firmware_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 =1178684242size =5738496machine_model = RK3588 manufacturer = RK3588 version =16777216item =5.LOG_INFO: ================================================LOG_DEBUG: name = package-file file = package-file offset =490214flash_offset = -1usespace =1size =127LOG_DEBUG: name = parameter file = parameter.txt offset =492262flash_offset =0usespace =1size =299LOG_DEBUG: name = bootloader file = MiniLoaderAll.bin offset =102flash_offset = -1usespace =239size =487872LOG_DEBUG: name = uboot_a file = uboot.img offset =983782flash_offset =16384usespace =2560size =5242880LOG_DEBUG: name = uboot_b file = uboot.img offset =983782flash_offset =32768usespace =2560size =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 =1178684242size =784320512machine_model = RK3588 manufacturer = RK3588 version =16777216item =10.LOG_INFO: ================================================LOG_DEBUG: name = package-file file = package-file offset =6716720flash_offset = -1usespace =1size =227LOG_DEBUG: name = parameter file = parameter.txt offset =6718768flash_offset =0usespace =1size =460LOG_DEBUG: name = bootloader file = MiniLoaderAll.bin offset =102flash_offset = -1usespace =239size =487872LOG_DEBUG: name = misc file = misc.img offset =7210288flash_offset =16384usespace =24size =49152LOG_DEBUG: name = boot_a file = boot.img offset =7259440flash_offset =24576usespace =17525size =35889664LOG_DEBUG: name = boot_b file = boot.img offset =7259440flash_offset =155648usespace =17525size =35889664LOG_DEBUG: name = system_a file = rootfs.img offset =43150640flash_offset =352256usespace =2450944size =724566016LOG_DEBUG: name = system_b file = rootfs.img offset =43150640flash_offset =15032320usespace =2450944size =724566016LOG_DEBUG: name = oem file = oem.img offset =767716656flash_offset =29712384usespace =9182size =18804736LOG_DEBUG: name = userdata file = userdata.img offset =786521392flash_offset =29974528usespace =2204size =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 than4G, after adjusting is5019533312.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:200start.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:200start.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:200start.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 A和slot B),可實現無縫切換。升級時無需進入專用升級模式,在Normal系統中即可完成,重啟后直接切換到升級后的系統。
優勢:升級過程無需切換至專用模式,用戶體驗流暢;雙系統冗余設計可有效防止設備變磚,若當前slot升級失敗或系統損壞,可自動切換至另一slot啟動;支持版本回滾,保障系統穩定性。
劣勢:雙系統設計會增加Flash存儲占用率,對存儲資源要求更高。
兩種模式的核心差異還體現在代碼支持上:updateEngine工具同時支持兩種模式(RV1126/RV1109平臺專用),而rkupdate工具僅支持Recovery模式(適用于其他平臺)。
二、關鍵升級場景的實現流程
(一)基礎OTA升級:Recovery與A/B模式通用實現
OTA(Over-the-Air)升級是設備遠程更新的核心方式,支持網絡下載升級和本地升級兩種形式,核心流程如下:
1.版本校驗:通過--version_url參數指定版本文件地址,與設備本地/etc/version中的版本號對比,判斷是否需要升級(該參數可缺省,缺省時跳過版本校驗)。
2.固件獲取:通過--image_url參數指定遠程固件地址或本地固件路徑,下載并保存至--savepath指定的目錄(默認路徑為/tmp/update.img,建議自定義為/userdata/update.img以避免臨時目錄空間不足)。
3.分區升級:通過--partition參數指定待升級分區(建議使用0x3FFC00,不支持升級parameter和loader分區)。
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.前置依賴
?代碼依賴:需確保buildroot、external/recovery、tools目錄中包含差分升級相關補丁(如0001-ota-add-diff-firmware-script.patch等)。
?工具依賴:PC端需安裝bsdiff(sudo apt install bsdiff)和md5sum工具。
2.關鍵限制
?支持分區:uboot/trust/kernel分區及squashfs格式的rootfs分區。
?不支持場景:ext2/ext4文件系統、mtd驅動的nand flash系統、加密分區及A/B模式。
?分區空間要求:存儲差分補丁包的分區(如userdata)空閑空間需不小于差分包(update_diff.img)與完整新rootfs.img的體積之和。
3.補丁包制作
通過工具腳本實現新舊固件的差分處理,命令如下:
cdtools/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.編譯命令:
sourceenvsetup.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.img(OTA升級用)、update_sdcard.img(SD卡啟動用)。
(三)自定義分區升級
若需擴展升級自定義分區(如factory分區),需修改external/recovery/update_engine/update.cpp中的UPDATE_CMD結構體數組,添加自定義分區配置:
{"factory",false,false,0,0,0,"", flash_normal},
同時在--partition參數中設置對應位值為1,確保升級工具識別該分區。
(四)SPI+PCIe方案專屬配置:patch添加說明
若采用SPI+PCIe存儲方案(區別于上述eMMC方案),需額外添加以下專屬patch以保障升級功能正常實現,否則可能出現無法進入系統的問題,具體操作及問題說明如下:
1.必備patch清單
?核心驅動適配patch:0001-spi-pcie-storage-adapt-update-engine.patch(適配SPI+PCIe存儲設備與updateEngine工具的通信驅動,解決存儲識別異常問題)
?分區管理優化patch:0002-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.cvoid 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"))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/0default/read/poll queues[ 4.940453] nvme0n1: p1 p2 p3 p4 p5 p6 p7 p8[ 4.940808]Waitingforroot device...
四、調試與問題排查
(一)日志查看
1.串口日志:在buildroot/output/rockchip_***/target目錄下創建隱藏文件.rkdebug,可在串口輸出Recovery模式升級日志。
2.文件日志:升級完成后,在設備userdata/recovery/log文件中查看詳細升級記錄,命令:cat userdata/recovery/log。
(二)常見問題解決
1.升級失敗:檢查分區空間是否充足(尤其是差分升級時的userdata分區)、固件是否為對應模式支持的格式(A/B模式需使用update_ota.img或update_ab.img)、--partition參數是否包含不支持的分區(如loader、parameter)。
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卡離線升級、差分升級等全場景需求,開發人員需根據產品的存儲資源、用戶體驗要求選擇合適的啟動模式。在實際開發過程中,需重點關注編譯配置的完整性、分區空間的合理性及日志調試的有效性,同時遵循官方對分區升級的限制(如不支持loader和parameter分區升級),確保升級功能的穩定性和可靠性。通過本文的梳理,希望能為RK平臺開發工程師提供清晰的升級開發路徑,助力高效完成產品升級模塊的設計與實現。
下期我們詳細分析ab系統下spi+pcie雙存儲方案升級的點點滴滴。
審核編輯 黃宇
-
嵌入式
+關注
關注
5198文章
20442瀏覽量
333979 -
Linux
+關注
關注
88文章
11758瀏覽量
219009
發布評論請先 登錄
一文吃透RK平臺OTA升級開發:從邏輯到調試的完整指南
RK平臺Android設備OTA升級教程:從原理到U盤實操
RK3588 CPU?隔離:AB/非?AB?系統雙方案適配實戰
RK?平臺?SPI?開發完全指南(驅動?+?配置?+?測試?+?優化)
RK3562單板機系統使用與開發手冊:基礎操作、升級部署與工具鏈配置(一)
一文讀懂UEFI系統:從應用場景到RK平臺開發全攻略
米爾RK3506核心板SDK重磅升級,解鎖三核A7實時控制新架構
RK3576驅動高端顯控系統升級:多屏拼控與AI視覺融合解決方案
RK?平臺?DDR?測試終極指南:標準化步驟?+?全場景適配方案
RK?平臺升級開發:全場景方案與實踐指南,覆蓋常規系統和ab系統
評論