0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Tina Linux OTA開發(fā)指南

嵌入式Linux那些事 ? 來源:嵌入式Linux那些事 ? 作者:嵌入式Linux那些事 ? 2023-03-06 11:04 ? 次閱讀

1 概述

OTA 是Over The Air 的簡(jiǎn)稱,顧名思義就是通過無線網(wǎng)絡(luò)從服務(wù)器上下載更新文件對(duì)本地系統(tǒng)或文件進(jìn)行升級(jí),便于客戶為其用戶及時(shí)更新系統(tǒng)和應(yīng)用以提供更

好的產(chǎn)品服務(wù),這對(duì)于客戶和消費(fèi)者都極其重要。

1.1 編寫目的

本文主要服務(wù)于使用Tina 軟件平臺(tái)的廣大客戶,以冀幫助客戶使用Tina 平臺(tái)的OTA 升級(jí)系統(tǒng)并做二次開發(fā)。

1.2 適用范圍

Allwinner 軟件平臺(tái)Tina。

1.3 相關(guān)人員

適用Tina 平臺(tái)的廣大客戶和關(guān)心OTA 的相關(guān)人員。

1.4 OTA 方案

1.4.1 recovery 系統(tǒng)方案

recovery 系統(tǒng)方案,是在主系統(tǒng)之外,增加一個(gè)recovery 系統(tǒng)。升級(jí)時(shí),主系統(tǒng)負(fù)責(zé)升級(jí)recovery系統(tǒng),recovery 系統(tǒng)負(fù)責(zé)升級(jí)主系統(tǒng)。

這樣如果升級(jí)中途發(fā)生掉電,也不會(huì)影響當(dāng)前正在使用的這個(gè)系統(tǒng)。重啟后仍可正常進(jìn)入系統(tǒng),繼續(xù)完成升級(jí)。

一般recovery 系統(tǒng)會(huì)使用intiramfs 功能,并大量裁剪不必要的應(yīng)用,只保留OTA 必需的功能,把size 盡量減小。

recovery 系統(tǒng)方案優(yōu)點(diǎn):

recovery 系統(tǒng)可以做得比較小,省flash 空間。

recovery 系統(tǒng)方案缺點(diǎn):

recovery 系統(tǒng)一般不包含主應(yīng)用,所以O(shè)TA 期間,處于recovery 系統(tǒng)中時(shí),無法為用戶正常提供服務(wù)。

需要重啟兩次。

需要維護(hù)兩份系統(tǒng)配置,即主系統(tǒng)和recovery 系統(tǒng)。

1.4.2 AB 系統(tǒng)方案

AB 系統(tǒng)方案,是將原有的系統(tǒng),增加一份。即flash 上總共有AB 兩套系統(tǒng)。兩套系統(tǒng)互相升級(jí)。OTA 時(shí),若當(dāng)前運(yùn)行的是A 系統(tǒng),則升級(jí)B 系統(tǒng),升級(jí)完成后,

設(shè)置標(biāo)志,重啟切換到B系統(tǒng)。OTA 時(shí),若當(dāng)前運(yùn)行的是B 系統(tǒng),則升級(jí)A 系統(tǒng),升級(jí)完成后,設(shè)置標(biāo)志,重啟切換到A 系統(tǒng)。

AB 系統(tǒng)方案優(yōu)點(diǎn):

更新過程是在完整系統(tǒng)中進(jìn)行的,更新期間可正常提供服務(wù),用戶無感知。最終做一次重啟即可。

邏輯簡(jiǎn)單,只重啟一次。

只維護(hù)一套系統(tǒng)配置。

AB 系統(tǒng)方案缺點(diǎn):

flash 占用較大。

2 ota-burnboot 介紹

2.1 文檔說明

此文檔主要介紹如何在OTA 時(shí)升級(jí)boot0/uboot。

升級(jí)工具包含兩個(gè)方面內(nèi)容:

OTA 命令升級(jí)boot0 和uboot。

OTA 升級(jí)boot0 和uboot 的C/C++ APIs。

2.2 概念說明

?

表2-1: ota-burnboot 相關(guān)概念說明表

?

概念 說明
boot0 較為簡(jiǎn)單, 主要作用是初始化dram 并加載運(yùn)行uboot。一般不需修改。
uboot 功能較豐富, 支持燒寫, 啟動(dòng)內(nèi)核, 燒key 及其他一些定制化的功能。
sys_config 全志特有的配置文件, 對(duì)于使用linxu3.4/uboot2011 的平臺(tái), 在打包之 后sys_config 會(huì)跟uboot 拼接到一起。對(duì)于使用 linux3.10/uboot2014 及更高版本的平臺(tái),sys_config 會(huì)在打包階段, 跟設(shè)備樹的配置合并, 生成最終的dtb。linux5.4 開始不再合并到 dtb。
dtb 設(shè)備樹, 由dts 配置和sys_config 配置綜合得到。
u-boot.fex 使用linxu3.4/uboot2011 的平臺(tái)最終用到的uboot, 其實(shí)是 uboot+sys_config。
boot_package.fex 使用linux3.10/uboot2014 及更高版本的平臺(tái)最終用到的uboot, 其 實(shí)包含的文件由配置文件boot_package.cfg 決定, 一般至少包含了 uboot 和dtb, 安全方案會(huì)包含一些安全所需文件文件, 可能還有 bootlogo 等文件。
toc0.fex 安全方案使用的boot0。
toc1.fex 安全方案使用的uboot, 類似boot_package.fex 說明, 其中實(shí)際也包 含了dts 等多個(gè)文件。

即, 本文介紹的升級(jí)uboot, 其實(shí)是升級(jí)uboot+dtb 這樣的一個(gè)整體文件。后文不再區(qū)分更新uboot, 更新sys_config, 更新dtb。這幾個(gè)打包完畢是合成一個(gè)文件的,

暫不支持單獨(dú)更新其中一個(gè), 需整體更新。

2.3 用于更新的bin 文件

獲取用于OTA 的boot0 與uboot 的bin 文件, 用于加入OTA 包中。

2.3.1 編譯boot0 uboot

如果原本的固件生成流程已經(jīng)包含編譯uboot, 則正常編譯固件即可。

否則可按照如下步驟編譯生成uboot

$ source build/envsetup.sh

=> 設(shè)置環(huán)境變量。

$ lunch

=> 選擇方案。

$ muboot

=> 編譯uboot。

$ mboot0

=> 編譯boot0 (注意,此命令在大多數(shù)平臺(tái)無效,因?yàn)閎oot0不開源,SDK中提供了編譯好的bin文件)。

編譯后會(huì)自行拷貝bin 文件到該平臺(tái)的目錄下, 即:

對(duì)于tina3.5.0 及之前版本,路徑為:

target/allwinner/xxx-common/bin

對(duì)于tina3.5.1 及之后版本,路徑為:

device/config/chips/${CHIP}/bin

編譯出的boot0/uboot 還不能直接用于OTA, 請(qǐng)繼續(xù)編譯和打包固件, 如執(zhí)行:

$ make -j

=> 編譯命令,若只修改boot0/uboot/sys_config 無需重新編譯,可跳過。

=> 若修改了dts 則需要執(zhí)行,重新編譯。

$ pack [-d]。

=> 非安全方案的打包命令。

$ pack -s [-d]

=> 安全方案的打包命令。

2.3.2 關(guān)于更新boot0

大多數(shù)平臺(tái),代碼環(huán)境中并不包含boot0 相關(guān)代碼, 因此無法編譯boot0。

一般情況下并不需要修改boot0, 而是直接使用提供的boot0 的bin 文件即可。少部分平臺(tái)提供了可編譯的boot0 代碼,可使用mboot0 編譯。

2.3.3 Bin 文件路徑

2.3.3.1 使用uboot2011 的非安全方案

以R16 的astar-parrot 方案為例。

根據(jù)對(duì)應(yīng)存儲(chǔ)介質(zhì)選擇bin。

boot0:

out/astar-parrot/image/boot0_nand.fex :nand 方案使用的boot0。

out/astar-parrot/image/boot0_sdcard.fex :mmc 方案使用的boot0。

out/astar-parrot/image/boot0_spinor.fex :nor 方案使用的boot0。

uboot:

out/astar-parrot/image/u-boot.fex :nand/mmc 方案使用的uboot。

out/astar-parrot/image/u-boot-spinor.fex :nor 方案使用的uboot。

2.3.3.2 使用uboot2014 及更高版本的非安全方案

以R6 的sitar-evb 方案為例。

根據(jù)對(duì)應(yīng)存儲(chǔ)介質(zhì)選擇bin。

boot0:

out/sitar-evb/image/boot0_nand.fex :nand 方案使用的boot0。

out/sitar-evb/image/boot0_sdcard.fex :mmc 方案使用的boot0。

out/sitar-evb/image/boot0_spinor.fex :nor 方案使用的boot0。

uboot:

out/sitar-evb/image/boot_package.fex :nand/mmc 方案使用的uboot。

out/sitar-evb/image/boot_package_nor.fex :nor 方案使用的uboot。

2.3.3.3 安全方案

以R18 的tulip-noma 方案為例。

boot0:

out/tulip-noma/image/toc0.fex :安全方案使用的boot0。

uboot:

out/tulip-noma/image/toc1.fex :安全方案使用的uboot。

2.4 OTA 升級(jí)命令

2.4.1 支持OTA 升級(jí)命令

升級(jí)boot0 與uboot 分別使用ota-burnboot0 與ota-burnuboot 命令。

兩個(gè)命令都是OTA 升級(jí)boot0 和uboot 的C/C++ APIs 的封裝。

要支持本功能, 需要選中ota-burnboot 的包, 即:

Make menuconfig --> Allwinner ---> <*>ota-burnboot

2.4.2 ota-burnboot0

2.4.2.1 命令說明

$ Usage: ota-burnboot0

升級(jí)boot0, 其中boot0-image 是鏡像的路徑。

請(qǐng)注意, 安全和非安全方案所使用的boot0-image 是不同的, 具體見“用于更新的bin 文件” 章節(jié)。

2.4.2.2 使用示例

root@TinaLinux:/# ota-burnboot0 /tmp/boot0_nand.fex Burn Boot0 Success

2.4.3 ota-burnuboot

2.4.3.1 命令說明

$ Usage: ota-burnuboot

升級(jí)uboot, 其中uboot-image 是鏡像的路徑。請(qǐng)注意, 安全和非安全方案, 不同的uboot 版本,所使用的uboot-image 是不同的,具體見第二章。

2.4.3.2 使用示例

root@TinaLinux:/# ota-burnuboot /tmp/u-boot.fex Burn Uboot Success

2.5 OTA 升級(jí)C/C++ APIs

包含頭文件OTA_BurnBoot.h,使用庫libota-burnboot.so

2.5.1 int OTA_burnboot0(const char *img_path)

?

表2-2: OTA_burnboot0 函數(shù)說明表

?

函數(shù)原型 int OTA_burnboot0(const char *img_path);
參數(shù)說明 img_path:boot0 鏡像路徑
返回說明 0:成功; 非零:失敗
功能描述 燒寫boot0

2.5.2 int OTA_burnuboot(const char *img_path)

?

表2-3: OTA_burnuboot 函數(shù)說明表

?

函數(shù)原型 int OTA_burnuboot(const char *img_path);
參數(shù)說明 img_path:uboot 鏡像路徑
返回說明 0:成功; 非零:失敗
功能描述 燒寫uboot

2.6 底層實(shí)現(xiàn)

2.6.1 如何保證安全更新boot0/uboot

前提條件是,flash 中存有不止一份boot0/uboot。在這個(gè)基礎(chǔ)上, 啟動(dòng)流程需支持校驗(yàn)并選擇完整的boot0/uboot 進(jìn)行啟動(dòng), 更新流程需保證任意時(shí)刻掉電,flash 上

總存在至少一份可用的boot0/uboot。

2.6.2 Nand Flash NFTL 方案實(shí)現(xiàn)

在nand nftl 方案中,boot0 和uboot 是由nand 驅(qū)動(dòng)管理, 保存在物理地址中, 邏輯分區(qū)不可見。

Nand 驅(qū)動(dòng)會(huì)保存多份boot0 和uboot, 啟動(dòng)時(shí), 從第一份開始依次嘗試, 直到找到一份完整的boot0/uboot 進(jìn)行使用。

更新boot0/uboot 時(shí), 上層調(diào)用nand 驅(qū)動(dòng)提供的接口, 驅(qū)動(dòng)中會(huì)從第一份開始依次更新, 多份全部更新完畢后返回。因此可保證在OTA 過程中任意時(shí)刻掉電,flash

中均有至少一份完整的boot0/uboot 可用。再次啟動(dòng)后, 只需重新調(diào)用更新接口進(jìn)行更新, 直到調(diào)用成功返回即可。

目前nand 中的多份boot0/uboot 是由nand 驅(qū)動(dòng)管理的, 只能整體更新, 暫不支持單獨(dú)更新其中的一份。

2.6.3 Nand Flash UBI 方案實(shí)現(xiàn)

在nand ubi 方案中, boot0 一般存放于mtd0 中,uboot 存放于mtd1 中。

與nftl 方案一樣,底層實(shí)際是保存多份boot0 和uboot。啟動(dòng)時(shí), 從第一份開始依次嘗試, 直到找到一份完整的boot0/uboot 進(jìn)行使用。對(duì)上提供多份統(tǒng)一的更新接

口,軟件包會(huì)通過對(duì)mtd的iotcl 接口發(fā)起更新。

注:用戶空間直接讀寫/dev/mtdx 節(jié)點(diǎn),需要內(nèi)核使能CONFIG_MTD_CHAR=y。

2.6.4 MMC Flash 實(shí)現(xiàn)

在mmc 方案中, boot0 和uboot 各有兩份, 存在mmc 上的指定偏移處, 邏輯分區(qū)不可見。需要讀寫可直接操作/dev/mmcblk0 節(jié)點(diǎn)的指定偏移。

具體位置:

1 sector = 512 bytes = 0.5k。 boot0/toc0 保存了兩份,offset1: 16 sector, offset2: 256 sector。 uboot/toc1 保存了兩份,offset1: 32800 sector, offset2: 24576 sector。

啟動(dòng)時(shí)會(huì)先讀取offset1,如果完整性校驗(yàn)失敗,則讀取offset2。

更新時(shí), 默認(rèn)只更新offset1, 而offset2 是保持在出廠狀態(tài)的。只要offset1 正常更新了, 則啟動(dòng)時(shí)會(huì)優(yōu)先使用。如果在更新offset1 的過程中掉電導(dǎo)致數(shù)據(jù)損壞, 則自

動(dòng)使用offset2 進(jìn)行啟動(dòng)。

如需定制策略,例如改成每次offset1 和offset2 均更新,可自行修改ota-burnboot 代碼。

2.6.5 NOR Flash 實(shí)現(xiàn)

nor 方案中, 只保存一份boot0 和uboot, 更新過程中掉電可能導(dǎo)致無法啟動(dòng), 只能進(jìn)行刷機(jī)。故目前未實(shí)現(xiàn)ota 更新, 需后續(xù)擴(kuò)展。

3 Tina SWUpdate OTA 介紹

3.1 swupdate 介紹

3.1.1 簡(jiǎn)介

SWUpdate 是一個(gè)開源的OTA 框架,提供了一種靈活可靠的方式來更新嵌入式系統(tǒng)上的軟件。

官方源碼:

https://github.com/sbabic/swupdate

官方文檔:

http://sbabic.github.io/swupdate/

非官方翻譯的中文文檔:

https://zqb-all.github.io/swupdate/

源碼自帶文檔:

解壓tina/dl/swupdate-xxx.tar.xz ,解壓后的doc 目錄下即為此版本源碼附帶的文檔。

社區(qū)論壇

https://groups.google.com/forum/#!forum/swupdate

3.1.2 移植到tina 的改動(dòng)

移植到tina 主要做了以下修改:

? 位置在package/allwinner/swupdate。

? 仿照busybox,添加了配置項(xiàng),可通過make menuconfig 直接配置。

? 添加patch,支持了更新boot0,uboot。

? 添加了自啟動(dòng)腳本。

? 默認(rèn)啟動(dòng)progress 在后臺(tái),輸出到串口。這樣升級(jí)時(shí)會(huì)打印進(jìn)度條。實(shí)際方案不需要的話,可去除??蛻魬?yīng)用可參考progress 源碼,自行獲取進(jìn)度信息。

? 默認(rèn)啟動(dòng)一個(gè)腳本swupdate_cmd.sh,負(fù)責(zé)完善參數(shù),最終調(diào)用swupdate。腳本介紹詳見后續(xù)章節(jié)。

3.2 配置

3.2.1 recovery 系統(tǒng)介紹

若選用主系統(tǒng)+recovery 系統(tǒng)的方式,則需要一個(gè)recovery 系統(tǒng)。

recovery 系統(tǒng)是一個(gè)帶initramfs 的kernel。對(duì)應(yīng)的配置文件是target/allwinner/xxx/defconfig_ota。

如果沒有此文件,可以拷貝defconfig 為defconfig_ota,再做配置裁剪。

3.2.2 系統(tǒng)配置命令

對(duì)于主系統(tǒng),使用:

make menuconfig

配置結(jié)果保存在:

target/allwinner/xxx/defconfig

對(duì)于recovery 系統(tǒng),使用:

make ota_menuconfig

配置結(jié)果保存在:

target/allwinner/xxx/defconfig_ota

3.2.3 主系統(tǒng)和recovery 都需要的swupdate 包

選上swupdate 包。

Allwinner --> [*]swupdate

swupdate 中還有很多細(xì)分選項(xiàng),一般用默認(rèn)配置即可。需要的話可以做一些調(diào)整,比如裁剪掉網(wǎng)絡(luò)部分。

swupdate 會(huì)依賴選中uboot-envtools 包,以提供用戶空間讀寫env 分區(qū)的功能。

3.2.4 主系統(tǒng)和recovery 都需要的wifimanager daemon

如果想從網(wǎng)絡(luò)升級(jí),則需要啟動(dòng)系統(tǒng)自動(dòng)聯(lián)網(wǎng)。

一種實(shí)現(xiàn)方式是,使用wifimanager daemon 。當(dāng)然,如果用戶自己在腳本或應(yīng)用中去做聯(lián)網(wǎng),則不需要此選項(xiàng)。

Allwinner ---> <*> wifimanager ---> [*] Enable wifimanager daemon support ---> <*> wifimanager-daemon-demo..................... Tina wifimanager daemon demo

3.2.5 配置主系統(tǒng)

就以上提到的幾個(gè)包,暫時(shí)沒有只針對(duì)主系統(tǒng)的需要選的包。

3.2.6 編譯主系統(tǒng)

正常make 即生成主系統(tǒng)。

make

3.2.7 配置recovery 系統(tǒng)

對(duì)于recovey 系統(tǒng),需要選上ramdisk,同時(shí)建議使用xz 壓縮方式以節(jié)省flash 空間。

make ota_menuconfig ---> Target Images ---> [*] ramdisk ---> Compression (xz)

選上recovery 后綴,避免編譯recovery 系統(tǒng)時(shí),影響到主系統(tǒng)。

make ota_menuconfig ---> Target Images ---> [*] customize image name ---> Boot Image(kernel) name suffix (boot_recovery.img/boot_initramfs_recovery.img) ---> Rootfs Image name suffix (rootfs_recovery.img)

3.2.8 編譯recovery 系統(tǒng)

要編譯生成recovery 系統(tǒng),可使用: swupdate_make_recovery_img 或手工調(diào)用: make -j16 TARGET_CONFIG=./target/allwinner/xxx/defconfig_ota 編譯得到: out/xxx/boot_initramfs_recovery.img

3.2.9 配置env

本方案推薦使用env 來保存信息,不使用misc 分區(qū)。

uboot 會(huì)從env 分區(qū)讀取啟動(dòng)命令,并根據(jù)啟動(dòng)命令來啟動(dòng)系統(tǒng)。只要我們能在用戶空間改動(dòng)到env,即可控制下次啟動(dòng)的系統(tǒng)。

3.2.9.1 boot_partition 變量

增加一個(gè)boot_partition 變量,用于指定要啟動(dòng)的內(nèi)核所在分區(qū)。

配置env 主要是修改boot_normal 命令,將要啟動(dòng)的分區(qū)獨(dú)立成boot_partition 變量。

即從:

boot_normal=fatload sunxi_flash boot 40007fc0 uImage;bootm 40007fc0

改成:

boot_partition=boot boot_normal=fatload sunxi_flash ${boot_partition} 40007fc0 uImage;bootm 40007fc0

這樣可以通過控制boot_partition 來直接選擇下次要啟動(dòng)的系統(tǒng),無需uboot 介入。uboot 只需按照boot_normal 啟動(dòng)即可。

對(duì)于recovery 方案,可設(shè)置boot_partition 為boot 或recovery。OTA 切換系統(tǒng)時(shí),只需要改變此變量即可達(dá)到切換主系統(tǒng)和recovery 系統(tǒng)的目的。

對(duì)于AB 系統(tǒng)方案,可設(shè)置為boot_partition 為bootA 或bootB。OTA 切換系統(tǒng)時(shí),只需要改變此變量即可達(dá)到切換kernel 的目的。

3.2.9.2 root_partition 變量

增加一個(gè)root_partition 變量,用于指定要啟動(dòng)的rootfs 所在分區(qū)。

uboot 會(huì)解析分區(qū)表,找出此變量指定的分區(qū)并在cmdline 中指定root 參數(shù)。

例如,在env 中設(shè)置:

root_partition=rootfs

則啟動(dòng)時(shí)uboot 會(huì)遍歷分區(qū)表,找到名字為rootfs 的分區(qū),假設(shè)找到的分區(qū)為/dev/nand0p4,則在cmdline 中增加root=/dev/nand0p4。

kernel 需要掛載rootfs 時(shí),取出root 參數(shù),則得知需要掛載/dev/nand0p4 分區(qū)。

對(duì)于recovery 方案,就一直設(shè)置root_partition 為rootfs 即可。主系統(tǒng)需要從rootfs 分區(qū)讀取數(shù)據(jù),而recovery 系統(tǒng)使用initramfs,無需從rootfs 分區(qū)讀取數(shù)據(jù)

即可正常運(yùn)行OTA 應(yīng)用等。當(dāng)然,recovery 系統(tǒng)中要更新rootfs 的話,還是會(huì)訪問(寫入)rootfs 分區(qū)的,但這個(gè)動(dòng)作就跟env 的root_partition 無關(guān)了。

對(duì)于AB 系統(tǒng)方案,可設(shè)置root_partition 為rootfsA 或rootfsB,以匹配不同的系統(tǒng)。OTA切換系統(tǒng)時(shí),只需要改變此變量即可達(dá)到切換rootfs 的目的。

3.2.10 配置備份env

由于寫入env 時(shí)斷電,可能導(dǎo)致env 的數(shù)據(jù)被破壞,因此需要支持備份env。

3.2.10.1 方式一:env 分區(qū)擴(kuò)展為存放兩份env

此方式是在uboot 中進(jìn)行定制實(shí)現(xiàn),非社區(qū)原生方案。

可在uboot源碼中搜索CONFIG_SUNXI_ENV_NOT_BACKUP, 若存在則說明支持此功能。

支持此功能后,只要uboot不配置CONFIG_SUNXI_ENV_NOT_BACKUP,則此功能默認(rèn)開啟。uboot會(huì)將env數(shù)據(jù)在同一分區(qū)中進(jìn)行備份。

啟用方法:

修改分區(qū)表,將env 分區(qū)擴(kuò)大到128k*2=256k。

工作方式: uboot 檢測(cè)到env 分區(qū)足夠大,則激活env 備份功能,認(rèn)為0-128k 存放第一份env 數(shù)據(jù),128k-256k 存放第二份env 數(shù)據(jù)。由于env 數(shù)據(jù)本身帶有CRC 校驗(yàn),所

以可判斷一份env 是否完整。啟動(dòng)時(shí),uboot 會(huì)對(duì)兩份env 進(jìn)行同步,若某一份損壞則取另一份進(jìn)行覆蓋,若兩份均完整,則以第一份為準(zhǔn)。

對(duì)于用戶空間的fw_printenv,默認(rèn)只會(huì)更新第一份env,即執(zhí)行fw_setenv 之后兩份env 就有差異了,要到下次啟動(dòng)才由uboot 進(jìn)行同步。若更新env 的過程中發(fā)

生掉電,則第一份env不完整,重新啟動(dòng)時(shí),uboot 會(huì)識(shí)別到并用第二份env 覆蓋第一份。

確認(rèn)是否生效:

1.直接觀察。 用戶空間控制臺(tái)執(zhí)行:

hexdump -C /dev/by-name/env

確認(rèn)是否存在兩份。

2.嘗試破壞env。

dd if=/dev/zero of=/dev/by-name/env bs=1k count=1

損壞第一份env,重啟看能否正常啟動(dòng),并嘗試

fw_printenv hexdump -C /dev/by-name/env

確認(rèn)env 分區(qū)數(shù)據(jù)是否正常。

3.2.10.2 方式二:增加env-redund 分區(qū)

此方式是uboot 原生功能。雖然也需要修改sunxi 的env 讀取代碼進(jìn)行適配,但總體讀寫邏輯是社區(qū)原生的。 啟用方法:

1.增加env-redund 分區(qū)。

將env 分區(qū)復(fù)制一份,分區(qū)名改為env-redund。

注意只是分區(qū)名修改為env-redund,其downloadfile 仍然指定為env.fex

2.支持在打包時(shí)制作冗余env。

make menuconfig --> Global build settings --> [*] sunxi make redundant env data

注意事項(xiàng): 啟用上述選項(xiàng)之后,打包時(shí)會(huì)調(diào)用mkenvimage 工具來制作env,對(duì)env 的格式有一定要求。

如注釋和有效配置不能合并在一行。

若env-x.x.cfg 中存在類似如下配置

bootcmd=run setargs_nand boot_normal#default nand boot

則需要改成:

#default nand boot bootcmd=run setargs_nand boot_normal

3.配置uboot 并重新編譯uboot bin。

以r328 spinand 方案為例。

lichee/brandy-2.0/u-boot-2018/configs/sun8iw18p1_defconfig

中增加配置:

CONFIG_SUNXI_REDUNDAND_ENVIRONMENT=y

重新編譯uboot。

4.修改fw_env.config

拷貝

package/utils/uboot-envtools/files/fw_env.config

target/allwinner//base-files/etc/ (若使用procd-init) target/allwinner//busybox-init-base-files/etc/ (若使用busybox-init)

修改拷貝后的fw_env.config,增加備份env 的配置。

例如原本最后一行為:

/dev/by-name/env 0x0000 0x20000

則增加一行:

/dev/by-name/env-redund 0x0000 0x20000

這樣用戶空間的fw_printenv 和fw_setenv 即可正確處理兩份env。

3.2.11 配置啟動(dòng)腳本

procd-init 是默認(rèn)配置好的。

busybox-init 需要手工配置下。

參考《Tina System init 使用說明文檔》, 拷貝

/package/busybox-init-base-files/files/etc/init.d/load_script.conf

/target/allwinner//busybox-init-base-files/etc/init.d/

并在其中添加一行:

swupdate_autorun

3.3 OTA 包

OTA 包中,需要包含sw-description 文件,以及本次升級(jí)會(huì)用到的各個(gè)文件,例如kernel,rootfs。

整個(gè)OTA 包是cpio 格式,且要求sw-description 文件在第一個(gè)。

3.3.1 OTA 策略描述文件:sw-description

sw-description 文件是swupdate 官方規(guī)定的,OTA 策略的描述文件,具體語法可參考swupdate官方文檔。

tina 提供了幾個(gè)示例:

target/allwinner/generic/swupdate/sw-description-ab target/allwinner/generic/swupdate/sw-description

也可以自行為具體的方案編寫描述文件:

target/allwinner//swupdate/sw-description

本文件在SDK 中的存放路徑和名字沒有限定,只要最終打包進(jìn)OTA 包中,重命名為swdescription并放在第一個(gè)文件即可。

3.3.2 OTA 包配置文件:sw-subimgs.cfg

sw-subimgs.cfg 是tina 提供的,用于指示如何生成OTA 包。

基本格式為

swota_file_list=( #表示把文件xxx拷貝到swupdate目錄下,重命名為yyy,并把yyy打包到最終的OTA包中 xxx:yyy ) swota_copy_file_list=( #表示把文件xxx拷貝到swupdate目錄下,重命名為yyy,但不把yyy打包到最終的OTA包中 xxx:yyy )

swota_copy_file_list 存在的原因是,有一些文件我們只需要其sha256 值,而不需要文件本身。例如使用差分包配合readback handler 時(shí),readback handler 需

要原始鏡像的sha256值用于校驗(yàn)。

例子:

swota_file_list=( #將target/allwinner/generic/swupdate/sw-description-ab-sign拷貝成sw-description,后續(xù)同理。 target/allwinner/generic/swupdate/sw-description-ab-sign:sw-description out/${TARGET_BOARD}/uboot.img:uboot out/${TARGET_BOARD}/boot0.img:boot0 out/${TARGET_BOARD}/image/boot.fex.gz:kernel.gz out/${TARGET_BOARD}/image/rootfs.fex.gz:rootfs.gz out/${TARGET_BOARD}/image/rootfs.fex.zst:rootfs.zst )

tina 提供了幾個(gè)示例:

target/allwinner/generic/swupdate/sw-subimgs.cfg # 普通系統(tǒng),recovery系統(tǒng),整包升級(jí)。這是其余demo的基礎(chǔ)版本。 target/allwinner/generic/swupdate/sw-subimgs-ab.cfg # 改為AB系統(tǒng)。 target/allwinner/generic/swupdate/sw-subimgs-secure.cfg # 改為安全系統(tǒng)。 target/allwinner/generic/swupdate/sw-subimgs-ab-rdiff.cfg # 改為AB方案,差分方案。 target/allwinner/generic/swupdate/sw-subimgs-readback.cfg # 增加回讀校驗(yàn)。 target/allwinner/generic/swupdate/sw-subimgs-sign.cfg # 增加簽名校驗(yàn)。 target/allwinner/generic/swupdate/sw-subimgs-ubi.cfg # 改為ubi方案。

也可以自行為具體的方案編寫描述文件。

target/allwinner//swupdate/sw-subimgs.cfg

本文件在SDK 中的路徑需位于target/allwinner//swupdate 目錄下,或target/allwinner/generic/swupdate 目錄下。

名字需要命名為sw-subimg.cfg 或sw-subimgsxxx.cfg,其中xxx 可自定義。

這個(gè)限定主要是為了方便打包函數(shù)處理。在打包時(shí),命令行傳入?yún)?shù)xxx,則會(huì)使用swsubimgsxxx.cfg 進(jìn)行打包。

3.3.3 OTA 包生成:swupdate_pack_swu

在build/envsetup.sh 中提供了一個(gè)swupdate_pack_swu 函數(shù)。 可以參考該函數(shù),自行實(shí)現(xiàn)一套打包swupdate 升級(jí)包的腳本。也可以直接使用,使用方式如下。

準(zhǔn)備好sw-descrition 文件,具體作用和語法請(qǐng)參考swupdate 說明文檔。

準(zhǔn)備好sw-subimgs.cfg 文件,里面需要每一行列出一個(gè)打包需要的子鏡像文件,即內(nèi)核,rootfs 等??梢允褂妹疤?hào)分隔,前面為SDK 中的文件,后面為打包進(jìn)OTA 包的文件名。若沒有冒號(hào)則使用原文件名字。使用相對(duì)于tina 根目錄的相對(duì)路徑進(jìn)行描述。其中第一個(gè)必須為swdescription。

編譯好所需的子鏡像,例如主系統(tǒng)的內(nèi)核和rootfs,recovery 系統(tǒng)等。

執(zhí)行swupdate_pack_swu 生成swupdate 升級(jí)包。不帶參數(shù)執(zhí)行,則會(huì)在特定路徑下尋找sw-subimgs.cfg,解析配置生成OTA 包。帶參數(shù)-xx 執(zhí)行,則會(huì)在特定路徑下尋找swsubimgs-xx.cfg,解析配置生成OTA 包。例如執(zhí)行swupdate_pack_swu -sign,則會(huì)尋找sw-subimgs-sign.cfg,如此方便配置多個(gè)不同用途的sw-subimgs-xx.cfg。

注:不同介質(zhì)使用的boot0/uboot 鏡像不同,swupate_pack_swu 需要sys_config.fex 中的storage_type 配置明確指出介質(zhì)類型,才能取得正確的boot0.img 和

uboot.img 具體可直接查看build/envsetup.sh 中swupdate_pack_swu 的實(shí)現(xiàn)。

3.4 recovery 系統(tǒng)方案舉例

3.4.1 配置分區(qū)和env

在分區(qū)表中,增加一個(gè)recovery 分區(qū),用于保存recovery 系統(tǒng)。

size 根據(jù)實(shí)際recovery 系統(tǒng)的大小,再加點(diǎn)裕量。

download_file 可以留空,因?yàn)镺TA 第一步就是寫入一個(gè)recovery 系統(tǒng)。

當(dāng)然也可以配置上download_file,并在打包固件之前先編譯好recovery 系統(tǒng),一并打包到固件中,這樣出廠就帶recovery 系統(tǒng),后續(xù)的OTA 執(zhí)行過程,可以考

慮不寫入recovert 系統(tǒng),用現(xiàn)成的,直接重啟并升級(jí)主系統(tǒng)。

在env 中指定:

boot_partition=boot root_partition=rootfs

并配置boot_normal 命令,從$boot_partition 變量指定的分區(qū)加載系統(tǒng)。

3.4.2 配置主系統(tǒng)

lunch 選擇方案后, make menuconfig, 選上swupdate。

3.4.3 配置recovery 系統(tǒng)

假設(shè)沒有現(xiàn)成的recovery 系統(tǒng)配置,則我們從主系統(tǒng)配置修改得到。lunch 選擇方案后, 拷貝配置文件。

cdevice cp defconfig defconfig_ota

根據(jù)上文介紹,make ota_menuconfig 選上swupdate, ramdisk, recovery 后綴等必要的配置。

recovery 系統(tǒng)整個(gè)運(yùn)行在ram 中,如果系統(tǒng)過大會(huì)無法啟動(dòng),所以需要進(jìn)行裁剪。make ota_menuconfig, 將不必要的包盡量從recovery 系統(tǒng)中去掉。

3.4.4 準(zhǔn)備sw-description

這里我們直接使用:

target/allwinner/generic/swupdate/sw-description

內(nèi)容如下,中文部分是注釋,原文件中沒有。

/* 固定格式,最外層為software = { } */ software = { /* 版本號(hào)和描述*/ version = "0.1.0"; description = "Firmware update for Tina Project"; /* * 外層tag,stable, * 沒有特殊含義,就理解為一個(gè)字符串標(biāo)志即可。 * 可以修改,調(diào)用的時(shí)候傳入匹配的字符串即可 */ stable = { /* * 內(nèi)層tag,upgrade_recovery, * 當(dāng)調(diào)用swupdate xxx -e stable,upgrade_recovery時(shí),就會(huì)匹配到這部分,執(zhí)行{}內(nèi)的動(dòng)作, * 可以修改,調(diào)用的時(shí)候傳入匹配的字符串即可 */ /* upgrade recovery,uboot,boot0 ==> change swu_mode,boot_partition ==> reboot */ upgrade_recovery = { /* 這部分是為了在主系統(tǒng)中,升級(jí)recovery系統(tǒng),升級(jí)uboot和boot0 */ /* upgrade recovery */ images: ( /* 處理各個(gè)image */ { filename = "recovery"; /* 源文件是OTA包中的recovery文件*/ device = "/dev/by-name/recovery"; /* 要寫到/dev/by-name/recovery節(jié)點(diǎn)中, 這 個(gè)節(jié)點(diǎn)在tina上就對(duì)應(yīng)recovery分區(qū)*/ installed-directly = true; /* 流式升級(jí),即從網(wǎng)絡(luò)升級(jí)時(shí)邊下載邊寫入, 而不是先完 整下載到本地再寫入,避免占用額外的RAM或ROM */ }, { filename = "uboot"; /* 源文件是OTA包中的uboot文件*/ type = "awuboot"; /* type為awuboot,則swupdate會(huì)調(diào)用對(duì)應(yīng)的handler做處理*/ }, { filename = "boot0"; /* 源文件是OTA包中的boot0文件*/ type = "awboot0"; /* type為awuboot,則swupdate會(huì)調(diào)用對(duì)應(yīng)的handler做處理*/ } ); /* image處理完之后,需要設(shè)置一些標(biāo)志,切換狀態(tài)*/ /* change swu_mode to upgrade_kernel,boot_partition to recovery & reboot*/ bootenv: ( /* 處理bootenv,會(huì)修改uboot的env分區(qū)*/ { /* 設(shè)置env:swu_mode=upgrade_kernel, 這是為了記錄OTA進(jìn)度*/ name = "swu_mode"; value = "upgrade_kernel"; }, { /* 設(shè)置env:boot_partition=recovery, 這是為了切換系統(tǒng),下次uboot就會(huì)啟動(dòng) recovery系統(tǒng)(kernel位于recovery分區(qū)) */ name = "boot_partition"; value = "recovery"; }, { /* 設(shè)置env:swu_next=reboot, 這是為了跟外部腳本配合,指示外部腳本做reboot動(dòng)作*/ name = "swu_next"; value = "reboot"; } /* 實(shí)際有什么其他需求,都可以靈活增刪標(biāo)志來解決, 外部腳本和應(yīng)用可通過fw_setenv/ fw_printenv操作env */ /* 注意,以上幾個(gè)env,是一起在ram中修改好再寫入的, 不會(huì)出現(xiàn)部分寫入部分未寫入的情況*/ ); }; /* * 內(nèi)層tag,upgrade_kernel, * 當(dāng)調(diào)用swupdate xxx -e stable,upgrade_kernel時(shí),就會(huì)匹配到這部分,執(zhí)行{}內(nèi)的動(dòng)作, * 可以修改,調(diào)用的時(shí)候傳入匹配的字符串即可。 */ /* upgrade kernel,rootfs ==> change sw_mode */ upgrade_kernel = { /* upgrade kernel,rootfs */ /* image部分,不贅述*/ images: ( { filename = "kernel"; device = "/dev/by-name/boot"; installed-directly = true; }, { filename = "rootfs"; device = "/dev/by-name/rootfs"; installed-directly = true; } ); /* change sw_mode to upgrade_usr,change boot_partition to boot */ bootenv: ( { /* 設(shè)置env:swu_mode=upgrade_usr, 這是為了記錄OTA進(jìn)度*/ name = "swu_mode"; value = "upgrade_usr"; }, { /* 設(shè)置env:boot_partition=boot, 這是為了切換系統(tǒng),下次uboot就會(huì)啟動(dòng)主系統(tǒng)( kernel位于boot分區(qū)) */ name = "boot_partition"; value = "boot"; } ); }; /* 內(nèi)層tag,upgrade_usr, 當(dāng)調(diào)用swupdate xxx -e stable,upgrade_usr時(shí),就會(huì)匹配到這部分,執(zhí)行{}內(nèi)的動(dòng)作, 可以修改,調(diào)用的時(shí)候傳入匹配的字符串即可*/ /* upgrade usr ==> clean ==> reboot */ upgrade_usr = { /* * misc-upgrade的小容量方案,將usr拆成獨(dú)立分區(qū)了。 * 這里我們不需要,如果保留的話,不做任何image操作即可。 * 也可以徹底刪除這一部分,并將上面的upgrade_usr改掉。 */ /* upgrade usr */ /* OTA結(jié)束,清空各種標(biāo)志*/ /* clean swu_param,swu_software,swu_mode & reboot */ bootenv: ( { name = "swu_param"; value = ""; }, { name = "swu_software"; value = ""; }, { name = "swu_mode"; value = ""; }, { name = "swu_next"; value = "reboot"; } ); }; }; /* 當(dāng)沒有匹配上面的tag,進(jìn)入對(duì)應(yīng)的處理流程時(shí),則運(yùn)行到此處。我們默認(rèn)清除掉一些狀態(tài)*/ /* when not call with -e xxx,xxx just clean */ bootenv: ( { name = "swu_param"; value = ""; }, { name = "swu_software"; value = ""; }, { name = "swu_mode"; value = ""; }, { name = "swu_version"; value = ""; } ); }

說明:

升級(jí)過程會(huì)進(jìn)行兩次重啟。具體的: (1)升級(jí)recovery 分區(qū)(recovery),uboot(uboot),boot0(boot0) 。設(shè)置boot_partition為recovery。 (2)重啟,進(jìn)入recovery 系統(tǒng)。 (3)升級(jí)內(nèi)核(kernel) 和rootfs(rootfs) 。設(shè)置boot_partition 為boot。 (4)重啟,進(jìn)入主系統(tǒng),升級(jí)完成。

3.4.5 準(zhǔn)備sw-subimgs.cfg

我們直接看下tina 默認(rèn)的:

target/allwinner/generic/swupdate/sw-subimgs.cfg

內(nèi)容如下,中文部分是注釋,原文件中沒有。

swota_file_list=( #取得sw-description,放到OTA包中。 #注意第一行必須為sw-description。如果源文件不叫sw-description,可在此處加:sw-description做一次重命名 target/allwinner/generic/swupdate/sw-description #取得boot_initramfs_recovery.img,重命名為recovery,放到OTA包中。以下雷同 out/${TARGET_BOARD}/boot_initramfs_recovery.img:recovery #uboot.img和boot0.img是執(zhí)行swupdate_pack_swu時(shí)自動(dòng)拷貝得到的,需配置sys_config.fex中的 storage_type out/${TARGET_BOARD}/uboot.img:uboot #注:boot0沒有修改的話,以下這行可去除,其他雷同,可按需升級(jí) out/${TARGET_BOARD}/boot0.img:boot0 out/${TARGET_BOARD}/boot.img:kernel out/${TARGET_BOARD}/rootfs.img:rootfs #下面這行是給小容量方案預(yù)留的,目前注釋掉 #out/${TARGET_BOARD}/usr.img:usr )

說明: 指明打包swupdate 升級(jí)包所需的各個(gè)文件的位置。這些文件會(huì)被拷貝到out 目錄下,再生成swupdate OTA 包。

3.4.6 編譯OTA 包所需的子鏡像

編譯kernel 和rootfs。

make

編譯recovery 系統(tǒng)。

swupdate_make_recovery_img

編譯uboot。

muboot

打包,若需要升級(jí)boot0/uboot,則是必要步驟,打包會(huì)將boot0 和uboot 拷貝到out 目錄下,并對(duì)頭部參數(shù)等進(jìn)行修改。生成的固件也可用于測(cè)試。注:如果希

望生成的固件的recovery分區(qū)是有系統(tǒng)的,則需要先編譯recovery 系統(tǒng),再打包。

pack / pack -s

生成OTA 包。因?yàn)槲覀兪褂玫木褪莝w-subimgs.cfg,所以不同帶參數(shù)。

注意,如果方案目錄下存在sw-subimgs.cfg,則優(yōu)先用方案目錄下的。沒有方案特定配置才用generic 下的。如果需要升級(jí)boot0/uboot,需要配置好

sys_config.fex 中的storage_type參數(shù),swupdate_pack_swu 才能正確拷貝對(duì)應(yīng)的boot0/uboot。

swupdate_pack_swu

3.4.7 執(zhí)行OTA

3.4.7.1 準(zhǔn)備OTA 包

對(duì)于測(cè)試來說,直接推入。

adb push out//swupdate/.swu /mnt/UDISK

實(shí)際應(yīng)用時(shí), 可從先從網(wǎng)絡(luò)下載到本地, 再調(diào)用swupdate, 也可以直接傳入url 給swupdate。

3.4.7.2 調(diào)用swupdate

若使用原生的swupdate,則調(diào)用:

swupdate -i /mnt/UDISK/.swu -e stable,upgrade_recovery

但這樣不會(huì)在自啟動(dòng)的時(shí)候幫我們準(zhǔn)備好swupdate 所需的-e 參數(shù)。

我們可以使用輔助腳本:

swupdate_cmd.sh -i /mnt/UDISK/.swu -e stable,upgrade_recovery

3.5 AB 系統(tǒng)方案舉例

3.5.1 配置分區(qū)和env

在分區(qū)表中,將原有的boot 分區(qū)和rootfs 分區(qū),分區(qū)名改為bootA 和rootfsA。

將這兩個(gè)分區(qū)配置拷貝一份,即新增兩個(gè)分區(qū),并把名字改為bootB 和rootfsB。

這樣flash 中就存在A 系統(tǒng)(bootA+rootfsA) 和B 系統(tǒng)(bootB+rootfsB)。

一般是一個(gè)系統(tǒng)燒錄兩份。即分區(qū)表中的bootA 和bootB 都指定的boot.fex,rootfsA 和rootfsB 都指定的rootfs.fex。

在env 中,指定:

boot_partition=bootA root_partition=rootfsA

并配置boot_normal 命令,從$boot_partition 變量指定的分區(qū)加載系統(tǒng)。

3.5.2 配置主系統(tǒng)

lunch 選擇方案后, make menuconfig, 選上swupdate。

3.5.3 配置recovery 系統(tǒng)

AB 系統(tǒng)方案沒有使用recovery 系統(tǒng),無需配置和生成。

3.5.4 準(zhǔn)備sw-description

這里我們直接使用:

target/allwinner/generic/swupdate/sw-description-ab

內(nèi)容如下,中文部分是注釋,原文件中沒有。

/* 固定格式,最外層為software = { } */ software = { /* 版本號(hào)和描述*/ version = "0.1.0"; description = "Firmware update for Tina Project"; /* * 外層tag,stable, * 沒有特殊含義,就理解為一個(gè)字符串標(biāo)志即可。 * 可以修改,調(diào)用的時(shí)候傳入匹配的字符串即可。 */ stable = { /* * 內(nèi)層tag,now_A_next_B, * 當(dāng)調(diào)用swupdate xxx -e stable,now_A_next_B時(shí),就會(huì)匹配到這部分,執(zhí)行{}內(nèi)的動(dòng)作, * 可以修改,調(diào)用的時(shí)候傳入匹配的字符串即可。 */ /* now in systemA, we need to upgrade systemB(bootB, rootfsB) */ now_A_next_B = { /* 這部分是描述,當(dāng)前處于A系統(tǒng),需要更新B系統(tǒng),該執(zhí)行的動(dòng)作。執(zhí)行完后下次啟動(dòng)為B系統(tǒng)*/ images: ( /* 處理各個(gè)image */ { filename = "kernel"; /* 源文件是OTA包中的kernel文件*/ device = "/dev/by-name/bootB"; /* 要寫到/dev/by-name/bootB節(jié)點(diǎn)中, 這個(gè)節(jié)點(diǎn) 在tina上就對(duì)應(yīng)bootB分區(qū)*/ installed-directly = true; /* 流式升級(jí),即從網(wǎng)絡(luò)升級(jí)時(shí)邊下載邊寫入, 而不是先完 整下載到本地再寫入,避免占用額外的RAM或ROM */ }, { filename = "rootfs"; /* 同上,但處理rootfs,不贅述*/ device = "/dev/by-name/rootfsB"; installed-directly = true; }, { filename = "uboot"; /* 源文件是OTA包中的uboot文件*/ type = "awuboot"; /* type為awuboot,則swupdate會(huì)調(diào)用對(duì)應(yīng)的handler做處理*/ }, { filename = "boot0"; /* 源文件是OTA包中的boot0文件*/ type = "awboot0"; /* type為awuboot,則swupdate會(huì)調(diào)用對(duì)應(yīng)的handler做處理*/ } ); /* image處理完之后,需要設(shè)置一些標(biāo)志,切換狀態(tài)*/ bootenv: ( /* 處理bootenv,會(huì)修改uboot的env分區(qū)*/ { /* 設(shè)置env:swu_mode=upgrade_kernel, 這是為了記錄OTA進(jìn)度, 對(duì)于AB系統(tǒng)來說,此時(shí) 已經(jīng)升級(jí)完成,置空*/ name = "swu_mode"; value = ""; }, { /* 設(shè)置env:boot_partition=bootB, 這是為了切換系統(tǒng),下次uboot就會(huì)啟動(dòng)B系統(tǒng)( kernel位于bootB分區(qū)) */ name = "boot_partition"; value = "bootB"; }, { /* 設(shè)置env:root_partition=rootfsB, 這是為了切換系統(tǒng),下次uboot就會(huì)通過cmdline 指示掛載B系統(tǒng)的rootfs */ name = "root_partition"; value = "rootfsB"; }, { /* 兼容另外的切換方式,可以先不管*/ name = "systemAB_next"; value = "B"; }, { /* 設(shè)置env:swu_next=reboot, 這是為了跟外部腳本配合,指示外部腳本做reboot動(dòng)作*/ name = "swu_next"; value = "reboot"; } ); }; /* * 內(nèi)層tag,now_B_next_A, * 當(dāng)調(diào)用swupdate xxx -e stable,now_B_next_A時(shí),就會(huì)匹配到這部分,執(zhí)行{}內(nèi)的動(dòng)作, * 可以修改,調(diào)用的時(shí)候傳入匹配的字符串即可 */ /* now in systemB, we need to upgrade systemA(bootA, rootfsA) */ now_B_next_A = { /* 這里面就不贅述了, 跟上面基本一致,只是AB互換了*/ images: ( { filename = "kernel"; device = "/dev/by-name/bootA"; installed-directly = true; }, { filename = "rootfs"; device = "/dev/by-name/rootfsA"; installed-directly = true; }, { filename = "uboot"; type = "awuboot"; }, { filename = "boot0"; type = "awboot0"; } ); bootenv: ( { name = "swu_mode"; value = ""; }, { name = "boot_partition"; value = "bootA"; }, { name = "root_partition"; value = "rootfsA"; }, { name = "systemAB_next"; value = "A"; }, { name = "swu_next"; value = "reboot"; } ); }; }; /* 當(dāng)沒有匹配上面的tag,進(jìn)入對(duì)應(yīng)的處理流程時(shí),則運(yùn)行到此處。我們默認(rèn)清除掉一些狀態(tài)*/ /* when not call with -e xxx,xxx just clean */ bootenv: ( { name = "swu_param"; value = ""; }, { name = "swu_software"; value = ""; }, { name = "swu_mode"; value = ""; }, { name = "swu_version"; value = ""; } ); }

說明:

升級(jí)過程會(huì)進(jìn)行一次重啟。具體的: (1)升級(jí)kernel 和rootfs 到另一個(gè)系統(tǒng)所在分區(qū),升級(jí)uboot(uboot),boot0(boot0) 。設(shè)置boot_partition 為切換系統(tǒng)。 (2)重啟,進(jìn)入新系統(tǒng)。

3.5.5 準(zhǔn)備sw-subimgs.cfg

我們直接看下tina 默認(rèn)的:

target/allwinner/generic/swupdate/sw-subimgs-ab.cfg

內(nèi)容如下,中文部分是注釋,原文件中沒有。

swota_file_list=( #取得sw-description-ab, 重命名成sw-description, 放到OTA包中。 #注意第一行必須為sw-description target/allwinner/generic/swupdate/sw-description-ab:sw-description #取得uboot.img,重命名為uboot,放到OTA包中。以下雷同 #uboot.img和boot0.img是執(zhí)行swupdate_pack_swu時(shí)自動(dòng)拷貝得到的,需配置sys_config.fex中的 storage_type out/${TARGET_BOARD}/uboot.img:uboot #注:boot0沒有修改的話,以下這行可去除,其他雷同,可按需升級(jí) out/${TARGET_BOARD}/boot0.img:boot0 out/${TARGET_BOARD}/boot.img:kernel out/${TARGET_BOARD}/rootfs.img:rootfs )

說明: 指明打包swupdate 升級(jí)包所需的各個(gè)文件的位置。這些文件會(huì)被拷貝到out 目錄下,再生成 swupdate OTA 包。

3.5.6 編譯OTA 包所需的子鏡像

編譯kernel 和rootfs。

make

編譯uboot。

muboot

打包,若需要升級(jí)boot0/uboot,則是必要步驟,打包會(huì)將boot0 和uboot 拷貝到out 目錄下,并對(duì)頭部參數(shù)等進(jìn)行修改。生成的固件也可用于測(cè)試。

pack / pack -s

生成OTA 包。因?yàn)槲覀兪褂玫氖莝w-subimgs-ab.cfg,所以調(diào)用時(shí)帶參數(shù)-ab。

注意,如果方案目錄下存在sw-subimgs-ab.cfg,則優(yōu)先用方案目錄下的。沒有方案特定配置才用generic 下的。

swupdate_pack_swu -ab

3.5.7 執(zhí)行OTA

3.5.7.1 準(zhǔn)備OTA 包

對(duì)于測(cè)試來說,直接推入。

adb push out//swupdate/.swu /mnt/UDISK

實(shí)際應(yīng)用時(shí), 可從先從網(wǎng)絡(luò)下載到本地, 再調(diào)用swupdate, 也可以直接傳入url 給swupdate。

3.5.7.2 判斷AB 系統(tǒng)

對(duì)于AB 系統(tǒng)方案來說,必須判斷當(dāng)前所處系統(tǒng),才能知道需要升級(jí)哪個(gè)分區(qū)的數(shù)據(jù)。

判斷當(dāng)前是處于A 系統(tǒng)還是B 系統(tǒng)。

方式一:直接使用fw_printenv 讀取判斷當(dāng)前的boot_partition 和root_partition 的值。

3.5.7.3 調(diào)用swupdate

若使用原生的swupdate,則調(diào)用:

當(dāng)前處于A系統(tǒng): swupdate -i /mnt/UDISK/.swu -e stable,now_A_next_B 當(dāng)前處于B系統(tǒng): swupdate -i /mnt/UDISK/.swu -e stable,now_B_next_A

但這樣不會(huì)在自啟動(dòng)的時(shí)候幫我們準(zhǔn)備好swupdate 所需的-e 參數(shù)。

我們可以使用輔助腳本:

當(dāng)前處于A系統(tǒng): swupdate_cmd.sh -i /mnt/UDISK/.swu -e stable,now_A_next_B 當(dāng)前處于B系統(tǒng): swupdate_cmd.sh -i /mnt/UDISK/.swu -e stable,now_B_next_A

3.6 輔助腳本swupdate_cmd.sh

為什么需要輔助腳本?

因?yàn)槲覀冃枰獑?dòng)時(shí)能自動(dòng)調(diào)用swupdate,自動(dòng)傳遞合適的-e 參數(shù)給swupdate, 需要在合適的時(shí)候調(diào)用重啟。

具體可直接看下腳本內(nèi)容。

其基本思路是,當(dāng)帶參數(shù)調(diào)用時(shí),腳本從傳入的參數(shù)中,取出”-e xxx,yyy” 部分,將其余參數(shù)原樣保存為env 的swu_param 變量。

取出的”-e xxx,yyy” 中的xxx 保存到env 的swu_software 變量, yyy 保存為env 的swu_mode變量。

然后就取出變量,循環(huán)調(diào)用。

swupdate $swu_param -e "$swu_software,$swu_mode"

sw-description 中可以通過改變env 的swu_software 和swu_mode 變量,來影響下次的調(diào)用參數(shù)。

實(shí)際應(yīng)用時(shí),可不使用此腳本,直接在主應(yīng)用中,調(diào)用swupdate 即可。但要自行做好-e 參數(shù)的處理。

3.7 版本號(hào)

3.7.1 使用方式

在sw-descriptionwen 文件中,會(huì)配置一個(gè)版本號(hào)字符串,如:

software = { version = "1.0.0"; ... }

如果需要在升級(jí)時(shí)檢查版本號(hào),則可使用-N 參數(shù),傳入的參數(shù)代表小機(jī)端當(dāng)前的版本號(hào)。如果不需要,則不傳遞-N 參數(shù),忽略版本號(hào)即可。

swupdate 會(huì)進(jìn)行比較,如果OTA 包中sw-descriptionwen 文件配置的版本號(hào)小于當(dāng)前版本號(hào),則不允許升級(jí)。

如何在小機(jī)端保存,獲取,更新版本號(hào),需要自定義, swupdate 沒有規(guī)定具體的方式。

3.7.2 實(shí)現(xiàn)例子

應(yīng)用可以按自己的邏輯維護(hù)版本號(hào),不依賴系統(tǒng)env 等,只需按照swupate 要求傳遞參數(shù)即可。

此處提供一種依賴系統(tǒng)env 的實(shí)現(xiàn)方式供參考。

1.初始化設(shè)備端版本號(hào)。

首先需要定義設(shè)備端的版本號(hào)存放在哪,如何獲取。

本方法定義設(shè)備端的版本號(hào)保存于env 之中,用swu_version 記錄。則在SDK 中,需在env-x.x.cfg 中添加一行:

swu_version=1.0.0

表示此時(shí)版本為1.0.0,燒錄固件后可執(zhí)行fw_printenv 查看。

此步驟如果不做,則第一次燒錄固件后env 中不存在swu_version,調(diào)用swupdate 時(shí)也無法傳入獲得并版本號(hào),則第一次升級(jí)時(shí)不會(huì)檢查版本。

注:這是tina 自定義的,可修改。只要讀寫這個(gè)版本號(hào)的地方均配套修改即可。實(shí)際應(yīng)用時(shí)版本號(hào)可以存在任意分區(qū)中,或者存放在文件系統(tǒng)的文件中,或者硬編

碼在系統(tǒng)和應(yīng)用的二進(jìn)制中,swupdate 未做限制。

2.在sw-description 中,設(shè)置OTA 包版本號(hào)。

升級(jí)時(shí)如果檢查到OTA 包的sw-description 中的version,小于通過-N 參數(shù)傳入的版本號(hào),則不允許升級(jí)。

software = { version = "2.0.0"; ...

例如當(dāng)設(shè)備端的env 中設(shè)置了swu_version=2.0.0, 則調(diào)用swupdate_cmd.sh 時(shí),會(huì)自動(dòng)獲取此參數(shù)并在調(diào)用swupdate 時(shí)傳入-N 2.0.0。

此時(shí)若OTA 包中定義了version = “1.0.0” , 則此時(shí)升級(jí)會(huì)降低版本號(hào),拒絕升級(jí)。

此時(shí)若OTA 包中定義了version = “2.0.0” , 則此次升級(jí)不會(huì)降低版本號(hào),可以升級(jí)。

此時(shí)若OTA 包中定義了version = “3.0.0” , 則此次升級(jí)不會(huì)降低版本號(hào),可以升級(jí)。

注:這是swupdate 原生的OTA 包版本號(hào)規(guī)則,不是tina 自定義的。

3.更新設(shè)備端版本號(hào)。

本方式版本號(hào)定義在env 中,則升級(jí)kernel 和rootfs 分區(qū)不會(huì)自動(dòng)更新版本號(hào),需要主動(dòng)修改env。

若版本號(hào)是記錄于rootfs 的某個(gè)文件,則不必在sw_description 中添加這種操作,因?yàn)楦聄ootfs 時(shí)版本號(hào)就自然更新了。但缺點(diǎn)是版本號(hào)跟rootfs 綁定了,每

次OTA 必須升級(jí)rootfs 才能更新版本號(hào)。

添加一個(gè)設(shè)置version 代表swu_version 的env 操作, 在OTA 時(shí)自動(dòng)更新版本號(hào)。

software = { #表示這個(gè)OTA包的版本號(hào),給swupdate讀取檢查的。原生規(guī)定的。 version = "2.0.0"; ... bootenv: ( ... { #表示這個(gè)OTA包的版本號(hào),OTA時(shí)會(huì)寫入env分區(qū),用于在下次OTA時(shí)讀出作為-N參數(shù)的值。 Tina自定義的。 name = "swu_version"; value = "2.0.0"; } ... ); ... }

注意,這么做的話,更新版本時(shí)需要修改env 中的版本號(hào),以使得新的固件包擁有新的版本號(hào),以及更新sw-description 的兩個(gè)位置,一處是最上面的version =

xxx 的版本號(hào),一處是bootenv 操作中的版本號(hào),以使得OTA 包擁有新的版本號(hào),以及能在OTA 時(shí)寫入新版本號(hào)。

讀取設(shè)備端版本號(hào)傳給swupdate。

假如小機(jī)端是用腳本調(diào)用,則可用如下方式讀取并傳給swupdate:

swu_version=$(fw_printenv -n swu_version) swupdate ... -N $swu_version

更好的方式是判斷非空才傳入,如此可支持不在env 中提前配置好swu_version。

check_version_para="" [ x"$swu_version" != x"" ] && { echo "now version is $swu_version" check_version_para="-N $swu_version" } swupdate ... $check_version_para

注: 如果不使用版本號(hào),則不在env 中設(shè)置swu_version,也不在bootenv 中寫swu_version 即可。

如果sw_description 中的版本號(hào)一直保持v1.0.0,也總是能升級(jí)。

3.8 簽名校驗(yàn)

3.8.1 檢驗(yàn)原理

OTA 包中包含了sw-decsription 文件和各個(gè)具體的鏡像,如kernel,rootfs。

如果對(duì)整個(gè)OTA 包進(jìn)行完整校驗(yàn),則會(huì)對(duì)流式升級(jí)造成影響,要求必須把整個(gè)OTA 包下載下來,才能判斷出校驗(yàn)是否通過。

為了避免上述問題,swupdate 的校驗(yàn)是分鏡像的,首先從OTA 包最前面取出兩個(gè)文件,即swdescription和sw-description.sig,使用傳入的公鑰校驗(yàn)sw-

description,校驗(yàn)通過則認(rèn)為sw-description 可信,則說明其中描述的image 和sha256 也是可信的。

后續(xù)無需再使用公鑰,直接校驗(yàn)每個(gè)鏡像的sha256 即可。因此可以逐個(gè)鏡像處理,無需全部下載完畢再處理。

3.8.2 配置

swupdate 支持使用簽名校驗(yàn)功能,需要在編譯時(shí)選中對(duì)應(yīng)功能。

出于安全考慮,一旦使能了校驗(yàn),則swupdate 不再支持不使用簽名的更新調(diào)用。

make menuconfig ---> Allwinner ---> <*> swupdate ---> [*] Enable verification of signed images Signature verification algorithm (RSA PKCS#1.5) --->(選擇校驗(yàn)算法,此處以RSA為例)

注意,recovery 系統(tǒng)也需要對(duì)應(yīng)進(jìn)行配置,即:

make ota_menuconfig ---> ...(重復(fù)以上配置)

3.8.3 使用方法

在PC 端使用私鑰簽名OTA 包。

在小機(jī)端調(diào)用swupdate 時(shí),使用-k 參數(shù)傳入公鑰。

3.8.4 初始化key

Tina 封裝了一條命令,生成默認(rèn)的密鑰對(duì)。執(zhí)行:

swupdate_init_key

執(zhí)行后會(huì)使用默認(rèn)密碼生成密鑰對(duì)并拷貝到指定目錄:

密碼/私鑰/公鑰:

password:tina/target/allwinner/方案名/swupdate/swupdate_priv.password private key:tina/target/allwinner/方案名/swupdate/swupdate_priv.pem public key:tina/target/allwinner/方案名/swupdate/swupdate_public.pem 公鑰拷貝到base-files中,供使用procd-init的方案使用 public key:tina/target/allwinner/方案名/base-files/swupdate_public.pem 公鑰拷貝到busybox-init-base-files中,供使用busybox-init的方案使用 public key:tina/target/allwinner/方案名/busybox-init-base-files/swupdate_public.pem

此步驟僅為方便調(diào)試使用,只需要做一次。

用戶也可使用自己的密碼自行生成密鑰,生成密鑰的具體命令可參考build/envsetup.sh 中swupdate_init_key 的實(shí)現(xiàn):

local password="swupdate"; echo "$password" > swupdate_priv.password; echo "-------------------- init priv key --------------------"; openssl genrsa -aes256 -passout file:swupdate_priv.password -out swupdate_priv.pem; echo "-------------------- init public key --------------------"; openssl rsa -in swupdate_priv.pem -passin file:swupdate_priv.password -out swupdate_public.pem -outform PEM -pubout;

生成的密鑰如swupdate_init_key 一般放到tina/target/allwinner/方案名/swupdate/ 中,即可在打包OTA 包時(shí)自動(dòng)使用。

主要就是調(diào)用openssl 生成,私鑰拷貝到SDK 指定目錄,供生成OTA 包時(shí)使用。公鑰放到設(shè)備端,供設(shè)備端執(zhí)行OTA 時(shí)使用。

密鑰的作用是校驗(yàn)OTA 包,意味著拿到密鑰的人即可生成可通過校驗(yàn)的OTA 包,因此正式產(chǎn)品中一般密鑰只掌握在少數(shù)人手中,并采取適當(dāng)措施避免泄漏或丟失。

一種可參考的實(shí)踐方式是,正式密鑰做好備份,并僅部署在有權(quán)限管控的服務(wù)器上,只能代碼入庫后通過自動(dòng)構(gòu)建生成OTA 包,普通工程師無法拿到密鑰自行本地

生成用于正式產(chǎn)品的OTA包。

3.8.5 修改sw-description

如上文所述,每個(gè)image 在使用時(shí)會(huì)校驗(yàn)sha256,因此需要在為每個(gè)更新文件在swdesctiption中添加sha256 屬性,指定sha256 的值供更新過程校驗(yàn)。

有獨(dú)立鏡像的文件才需要sha256 屬性,例如images 中配置的文件。而bootenv 等直接寫在sw-description 中的,則無需sha256 屬性。

目前腳本支持自動(dòng)在生成OTA 包時(shí),更新sha256 的值。但需要在sw-description 中,手工添加:

sha256 = @文件名

如:

$ git diff sw-description diff --git a/allwinner/cowbell-perf1/configs/sw-description b/allwinner/cowbell-perf1/ configs/sw-description index ed04b64..467ac3b 100644 --- a/allwinner/cowbell-perf1/configs/sw-description +++ b/allwinner/cowbell-perf1/configs/sw-description @@ -9,14 +9,17 @@ software = { filename = "boot_initramfs_recovery.img" device = "/dev/by-name/recovery"; + sha256 = "@boot_initramfs_recovery.img" }, { filename = "boot_package.fex" type = "awuboot"; + sha256 = "@boot_package.fex" }, { filename = "boot0_nand.fex" type = "awboot0"; + sha256 = "@boot0_nand.fex" } ); @@ -34,10 +37,12 @@ software = { filename = "boot.img"; device = "/dev/by-name/boot"; + sha256 = "@boot.img" }, { filename = "rootfs.img"; device = "/dev/by-name/rootfs"; + sha256 = "@rootfs.img" } ); bootenv: (

在打包OTA 包時(shí),腳本自動(dòng)算出sha256 的值,并替換到上述位置,再完成OTA 包的生成。

可參考:

target/allwinner/generic/swupdate/sw-description-sign target/allwinner/generic/swupdate/sw-subimgs-sign.cfg 注: 調(diào)用swupdate_pack_swu 則會(huì)使用sw-subimgs.cfg,其中默認(rèn)指定了使用sw-description做為最終的sw-description。 調(diào)用swupdate_pack_swu -sign則會(huì)使用sw-subimgs-sign.cfg,其中默認(rèn)指定了使用sw-description-sign做為 最終的sw-description。 即關(guān)鍵還是看使用哪份sw-subimgs.cfg,以及sw-subimgs.cfg中如何指定。

3.8.6 添加sw-description.sig

簽名的OTA 包,需要生成簽名文件sw-description.sig,并使其在OTA 包中,緊隨在swdescription后面。

目前腳本中自動(dòng)處理。

3.8.7 生成OTA 包

方法不變,腳本中會(huì)檢測(cè)defconfig 的配置,并自動(dòng)完成簽名等動(dòng)作。

3.8.8 將公鑰放置到小機(jī)端

目前腳本中生成key 的時(shí)候,自動(dòng)拷貝了。如需手工處理,可參考如下方式。

對(duì)于procd-init:

cdevice mkdir -p ./base-files cp swupdate_public.pem ./base-files/etc/

對(duì)于busybox-init

cdevice mkdir -p ./busybox-init-base-files/ cp swupdate_public.pem ./busybox-init-base-files/etc/

3.8.9 在小機(jī)端調(diào)用

在原本的命令基礎(chǔ)上,加上-k /etc/swupdate_public.pem 即可, 如:

swupdate_cmd.sh -v -i /mnt/UDISK/tina-cowbell-perf1.swu -k /etc/swupdate_public.pem

3.9 壓縮

swupdate 支持對(duì)鏡像先解壓,再寫入目標(biāo)位置,當(dāng)前支持gzip 和zstd 兩種壓縮算法。

3.9.1 配置

使用gzip 壓縮無需配置,使用zstd 則需選上

make menuconfig --> Allwinner ---> <*> swupdate --> [*] Zstd compression support

3.9.2 生成壓縮鏡像

如果希望每次打包固件自動(dòng)生成,則可修改scripts/pack_img.sh, 在function do_pack_tina()函數(shù)的最后加上壓縮的動(dòng)作。

生成gz鏡像: gzip -k -f boot.fex gzip -k -f rootfs.fex gzip -k -f recovery.fex #如果使用AB方案,則無需recovery 生成lzma鏡像: zstd -k -f boot.fex -T0 zstd -k -f rootfs.fex -T0 zstd -k -f recovery.fex -T0

對(duì)于lzma,若需要調(diào)整壓縮率,可指定0-19 的數(shù)字(數(shù)字越大,壓縮率越高,耗時(shí)越長(zhǎng)),如

zstd -19 -k -f boot.fex -T0 zstd -19 -k -f rootfs.fex -T0 zstd -19 -k -f recovery.fex -T0

如果不希望每次打包固件多耗時(shí)間,則需自行在生成OTA 包之前,使用上述命令制作好壓縮鏡像。原始的boot.fex,rootfs.fex, recovery.fex 在out/方案/image/目錄下。

3.9.3 sw-subimgs.cfg 配置壓縮鏡像

以rootfs 為例,將原本未壓縮的版本

out/${TARGET_BOARD}/rootfs.img:rootfs

改成壓縮的

out/${TARGET_BOARD}/image/rootfs.fex.gz:rootfs.gz

out/${TARGET_BOARD}/image/rootfs.fex.zst:rootfs.zst

注:為了方便差分包的處理,此處約定壓縮鏡像需以.gz 或.zst 結(jié)尾,生成差分項(xiàng)的腳本會(huì)檢查后綴名,并自動(dòng)解壓。

3.9.4 sw-description 配置壓縮鏡像

以rootfs 為例,將原本未壓縮的版本

{ filename = "rootfs"; device = "/dev/by-name/rootfs"; installed-directly = true; sha256 = "@rootfs"; },

換成

{ filename = "rootfs.gz"; device = "/dev/by-name/rootfs"; installed-directly = true; sha256 = "@rootfs.gz"; compressed = "zlib"; },

{ filename = "rootfs.zst"; device = "/dev/by-name/rootfsB"; installed-directly = true; sha256 = "@rootfs.zst"; compressed = "zstd"; },

3.10 調(diào)用OTA

swupdate_cmd.sh , 用于給swupdate 傳入相關(guān)參數(shù),切換更新狀態(tài),以及不斷重試。

3.10.1 進(jìn)度條

swupdate 提供了progress 程序,該程序會(huì)在后臺(tái)運(yùn)行,從socket 獲取進(jìn)度信息,打印進(jìn)度條到串口。

具體方案可參考其實(shí)現(xiàn)(在swupdate 源碼中搜索progress),自行在應(yīng)用中獲取進(jìn)度,通過屏 幕等其他方式進(jìn)行指示。

3.10.2 重啟

1.調(diào)用swupdate 的時(shí)候加上-p reboot , 則swupdate 更新完畢后,會(huì)執(zhí)行reboot。

2.swupdate_cmd.sh 支持檢測(cè)env 中的swu_next 變量,如果為reboot,則腳本中執(zhí)行reboot??稍趕w-description 中設(shè)置此變量。

3.如果調(diào)用progress 的時(shí)候加上-r 參數(shù),則progress 會(huì)在檢測(cè)到更新完成后,執(zhí)行reboot。

3.10.3 本地升級(jí)示例

將生成的OTA 包推送到小機(jī)端,如放在/mnt/UDISK 目錄下。

PC 端執(zhí)行:

adb push out/cowbell-perf1/swupdate/tina-cowbell-perf1.swu /mnt/UDISK

小機(jī)端執(zhí)行(不帶簽名校驗(yàn)版本):

swupdate_cmd.sh -i /mnt/UDISK/tina-cowbell-perf1.swu -e stable,upgrade_recovery

小機(jī)端執(zhí)行(帶簽名校驗(yàn)版本):

swupdate_cmd.sh -i /mnt/UDISK/tina-cowbell-perf1.swu -k /etc/swupdate_public.pem -e stable,upgrade_recovery

3.10.4 網(wǎng)絡(luò)升級(jí)示例

啟動(dòng)服務(wù)器:

cd out/cowbell-perf1/swupdate/ sudo python -m SimpleHTTPServer 80 #啟動(dòng)一個(gè)服務(wù)器

小機(jī)端命令,使用-d -uxxx,xxx 為url。

例如(不帶簽名校驗(yàn)版本):

swupdate_cmd.sh -d -uhttp://192.168.35.112/tina-cowbell-perf1.swu -e stable,upgrade_recovery

例如(帶簽名校驗(yàn)版本):

swupdate_cmd.sh -d -uhttp://192.168.35.112/tina-cowbell-perf1.swu -k /etc/swupdate_public.pem -e stable,upgrade_recovery

注:需依賴外部程序,提供自動(dòng)聯(lián)網(wǎng)支持。OTA 本身不處理聯(lián)網(wǎng)。

3.10.5 錯(cuò)誤處理

如何判斷swupdate 升級(jí)出錯(cuò)?

1.調(diào)用swupdate 時(shí)獲得并判斷返回值是否為0。

2.讀取env 變量recovery_status。根據(jù)swupdate 官方文檔,swupdate 開始執(zhí)行時(shí),會(huì)設(shè)置recovery_status=“progress”,升級(jí)完成會(huì)清除這個(gè)變量,升級(jí)失敗則設(shè)置recovery_status=“failed”。

3.11 裁剪

swupdate 本身是可配置的, 不需要某些功能時(shí),可將其裁剪掉。

make menuconfig ---> Allwinner ---> <*> swupdate --->

例如,不需要使用swupdate 來從網(wǎng)絡(luò)下載OTA 包的話,則可將

[*] Enable image downloading

取消掉。 不需要更新boot0/uboot 的話,則將

Image Handlers ---> [*] allwinner boot0/uboot

取消掉

3.12 調(diào)試

3.12.1 直接調(diào)用swupdate

目前swupdate_cmd.sh 主要有兩個(gè)作用:

1.自啟動(dòng),無限重試。

2.在主系統(tǒng)和recovery 系統(tǒng)中,傳入不同的-e 參數(shù)給swupdate。

出問題時(shí),可以不使用swupdate_cmd.sh,手工直接調(diào)用swupdate,在后面加上合適的-e 參數(shù),觀察輸出log。如:

swupdate -v -i xxx.swu -e stable,boot swupdate -v -i xxx.swu -e stable,recovery

3.12.2 手工切換系統(tǒng)

按上述env 的配置,啟動(dòng)的系統(tǒng),是由boot_partition 變量控制的。

注意,需要/var/lock 目錄存在且可寫。

切換到主系統(tǒng):

fw_setenv boot_partition boot reboot

切換到recovery 系統(tǒng):

fw_setenv boot_partition recovery reboot

觀察當(dāng)前變量:

fw_printenv

3.12.3 更新boot0/uboot

目前更新boot0,uboot 實(shí)際功能是由另一個(gè)軟件包ota-burnboot 完成的,swupdate 只是準(zhǔn)備數(shù)據(jù),并調(diào)用ota-burnboot 提供的動(dòng)態(tài)庫。

如果更新失敗,先嘗試手工使用ota-burnboot0 xxx 和ota-burnuboot xxx 能否正常更新。以確定是ota-burnboot 的問題,還是swupdate 的問題。

3.12.4 解壓OTA 包

swupdate 的OTA 包,本質(zhì)上是一個(gè)cpio 格式的包,直接使用通用的cpio 解包命令即可。

cpio -idv < xxx.swu

3.12.5 校驗(yàn)OTA 包

當(dāng)使能了簽名校驗(yàn),會(huì)對(duì)sw-description 簽名生成sw-description.sig,如果校驗(yàn)失敗,可以在PC 端手工驗(yàn)證下:

使用RSA 時(shí), build/envsetup.sh 中調(diào)用的命令是:

openssl dgst -sha256 -sign "$priv_key_file" $password_para "$SWU_DIR/sw-description" > " $SWU_DIR/sw-description.sig"

則對(duì)應(yīng)的密鑰驗(yàn)證簽名命令為:

openssl dgst -prverify swupdate_priv.pem -sha256 -signature sw-description.sig swdescription

公鑰驗(yàn)證簽名的命令為:

openssl dgst -verify swupdate_public.pem -sha256 -signature sw-description.sig swdescription

3.13 測(cè)試固件示例

3.13.1 生成方式

一般而言,測(cè)試需要兩個(gè)有差異的OTA 包,如,uboot 和kernel 的log 有差異,rootfs 的文件有差異。

這樣方法測(cè)試人員根據(jù)log 判斷是否升級(jí)成功。

3.13.1.1 準(zhǔn)備工作

如果需要網(wǎng)絡(luò)更新,OTA 不負(fù)責(zé)聯(lián)網(wǎng),所以需要選上wifimanager-daemon。

Allwinner ---> <*> wifimanager ---> [*] Enable wifimanager daemon support ---> <*> wifimanager-daemon-demo..................... Tina wifimanager daemon demo

3.13.1.2 生成固件1 和OTA 包1

重新編譯boot,使得編譯時(shí)間更新:

mboot

創(chuàng)建文件以標(biāo)記rootfs:

cd target/allwinner/cowbell-ailabs_c1c/base-files rm -f OTA1 OTA2 echo OTA1 > OTA1

重新編譯recovery 系統(tǒng):

swupdate_make_recovery_img

重新編譯打包,使得編譯時(shí)間更新:

mp -j32

生成OTA 包1:

swupdate_pack_swu

得到產(chǎn)物:

cp out/cowbell-perf1/tina_cowbell-perf1_uart0.img tina_cowbell-perf1_uart0_OTA1.img cp out/cowbell-perf1/swupdate/tina-cowbell-perf1.swu tina-cowbell-perf1_OTA1.swu

3.13.1.3 生成固件2 和OTA 包2

重新編譯uboot,使得編譯時(shí)間更新:

muboot

創(chuàng)建文件以標(biāo)記rootfs:

cd target/allwinner/cowbell-ailabs_c1c/base-files rm -f OTA1 OTA2 echo OTA2 > OTA2

重新編譯recovery 系統(tǒng):

swupdate_make_recovery_img

重新編譯打包,使得編譯時(shí)間更新:

mp -j32

生成OTA 包2:

swupdate_pack_swu

得到產(chǎn)物:

cp out/cowbell-perf1/tina_cowbell-perf1_uart0.img tina_cowbell-perf1_uart0_OTA2.img cp out/cowbell-perf1/swupdate/tina-cowbell-perf1.swu tina-cowbell-perf1_OTA2.swu

3.13.2 使用方式

任意選擇一個(gè)OTA 固件燒錄后,可在此基礎(chǔ)上進(jìn)行本地升級(jí)或網(wǎng)絡(luò)升級(jí)。

3.13.2.1 本地升級(jí)方式

PC 端執(zhí)行:

adb push out/astar-parrot/swupdate/tina-cowbell-perf1_OTA1.swu /mnt/UDISK

小機(jī)端執(zhí)行:

swupdate_cmd.sh -i /mnt/UDISK/tina-cowbell-perf1_OTA1.swu

3.13.2.2 網(wǎng)絡(luò)升級(jí)方式

PC 端搭建服務(wù)器:

sudo python -m SimpleHTTPServer 80

小機(jī)端聯(lián)網(wǎng):

wifi_connect_ap_test SSID 密碼

小機(jī)端執(zhí)行:

swupdate_cmd.sh -d -uhttp://192.168.xxx.xxx/tina-cowbell-perf1_OTA1.swu

注明:?jiǎn)?dòng)后會(huì)自動(dòng)聯(lián)網(wǎng),連網(wǎng)后等待OTA 后臺(tái)腳本嘗試更新。中途掉電重啟后,正常會(huì)在啟動(dòng)后幾十秒內(nèi),成功聯(lián)網(wǎng)并開始繼續(xù)更新。

3.13.2.3 升級(jí)過程

升級(jí)過程會(huì)進(jìn)行兩次重啟。具體的: (1)升級(jí)recovery 分區(qū)(boot_initramfs_recovery.img),uboot(boot_package.fex),boot0(boot0_nand.fex)。 (2)重啟,進(jìn)入recovery 系統(tǒng)。 (3)升級(jí)內(nèi)核(boot,img) 和rootfs(rootfs.img)。 (4)重啟,進(jìn)入主系統(tǒng),升級(jí)完成。

3.13.2.4 判斷升級(jí)

從log 中的時(shí)間和rootfs 文件可以判斷當(dāng)前運(yùn)行的版本。

例如:

OTA_1: boot0:[66]HELLO! BOOT0 is starting Dec 29 2018 16:15:59! uboot:U-Boot 2018.05-00015-g5068c23-dirty (Dec 29 2018 - 16:15:41 +0800) Allwinner Technology kernel:[ 0.000000] Linux version 4.9.118 (zhuangqiubin@Exdroid5) (gcc version 6.4.1 ( OpenWrt/Linaro GCC 6.4-2017.11 2017-11) ) #189 SMP Sat Dec 29 08:13:38 UTC 2018 (注,進(jìn)入控制臺(tái)cat /proc/version 也可看到) rootfs:ls查看下,在根目錄下有一個(gè)文件OTA1 OTA_2: boot0: [66]HELLO! BOOT0 is starting Dec 29 2018 16:17:35! uboot: U-Boot 2018.05-00015-g5068c23-dirty (Dec 29 2018 - 16:17:17 +0800) Allwinner Technology kernel:[ 0.000000] Linux version 4.9.118 (zhuangqiubin@Exdroid5) (gcc version 6.4.1 ( OpenWrt/Linaro GCC 6.4-2017.11 2017-11) ) #190 SMP Sat Dec 29 08:18:33 UTC 2018(注,進(jìn)入控制臺(tái)cat /proc/version 也可看到) rootfs:ls查看下,在根目錄下有一個(gè)文件OTA2

3.14 升級(jí)定制分區(qū)

如果定制了一個(gè)分區(qū),并需要對(duì)此分區(qū)進(jìn)行OTA,則需要:

1.確認(rèn)需不需要備份。

2.將分區(qū)文件加入OTA 包。

3.確定升級(jí)策略,在sw-description 中增加對(duì)此分區(qū)的處理。

3.14.1 備份

在OTA 過程隨時(shí)可能掉電,如果掉電時(shí)正在升級(jí)分區(qū)mypart ,則重啟后mypart 的數(shù)據(jù)是不完整的。

是否需要備份主要取決于mypart 所保存的文件是否影響繼續(xù)進(jìn)行OTA。

例如mypart 中保存的是開機(jī)音樂,被損壞的結(jié)果只是開機(jī)無聲音,但開機(jī)后能正常繼續(xù)OTA,則無需備份。

例如mypart 中保存的是應(yīng)用,且OTA 中途掉電后重啟,需要應(yīng)用負(fù)責(zé)聯(lián)網(wǎng)從網(wǎng)絡(luò)重新下載OTA 包,則需要備份,否則無法繼續(xù)OTA,設(shè)備就無法恢復(fù)了。

例如mypart 中保存的是dsp,啟動(dòng)過程沒有有效的dsp 鏡像會(huì)無法啟動(dòng),則需要備份,否則無法啟動(dòng)也就無法繼續(xù)OTA,設(shè)備就無法恢復(fù)了。

3.14.2 無需備份

假設(shè)分區(qū)表中定義了:

[partition] name = mypart size = 512 downloadfile = "mypart.fex" user_type = 0x8000

文件放在:

out/${TARGET_BOARD}/image/mypart.fex

則在sw-subimg.cfg 中增加一行(注意要放到sw-description 之后,因?yàn)閟w-description 必須是第一個(gè)文件),將mypart.fex 打包到OTA 包中,重命名為mypart:

out/${TARGET_BOARD}/image/mypart.fex:mypart

在sw-description 中增加升級(jí)動(dòng)作的定義。例如可以在升級(jí)rootfs 之后,升級(jí)該分區(qū):

software = { ... stable = { ... upgrade_kernel = { images: ( ... { filename = "rootfs"; device = "/dev/by-name/rootfs"; installed-directly = true; }, { filename = "mypart"; device = "/dev/by-name/mypart"; installed-directly = true; } ... ); ...

3.14.3 需要備份

在分區(qū)表中定義好兩個(gè)分區(qū),這樣升級(jí)過程掉電,總有一份是完整的。

[partition] name = mypart size = 512 downloadfile = "mypart.fex" user_type = 0x8000 [partition] name = mypart-r size = 512 downloadfile = "mypart.fex" user_type = 0x8000

文件放在:

out/${TARGET_BOARD}/image/mypart.fex

則在sw-subimg.cfg 中增加一行(注意要放到sw-description 之后,因?yàn)閟w-description 必

須是第一個(gè)文件),將mypart.fex 打包到OTA 包中,重命名為mypart:

out/${TARGET_BOARD}/image/mypart.fex:mypart

有兩個(gè)分區(qū),則需要條件決定使用哪一個(gè),可考慮在env 中定義一個(gè)變量:

mypart_partition=mypart

使用mypart 時(shí),要先讀取env 的mypart_partition 的值來決定要使用哪個(gè)分區(qū)。

在sw-description 中,定義好要升級(jí)的分區(qū)和bootenv,保證每次升級(jí)那個(gè)未在使用的分區(qū)。

這樣即使掉電也無妨。

software = { ... stable = { upgrade_recovery = { images: { filename = "recovery"; device = "/dev/by-name/recovery"; installed-directly = true; }, /* 更新mypart-r, 此時(shí)掉電,mypart分區(qū)是完整的*/ { filename = "mypart-r"; device = "/dev/by-name/mypart-r"; installed-directly = true; } ); bootenv: ( { name = "swu_mode"; value = "upgrade_kernel"; }, { name = "boot_partition"; value = "recovery"; }, /* 設(shè)置這個(gè)env,指示下次啟動(dòng),即啟動(dòng)到recovery分區(qū)時(shí),配套使用mypart-r */ { name = "mypart_partition"; value = "mypart-r"; }, { name = "swu_next"; value = "reboot"; } ); }; upgrade_kernel = { images: ( { filename = "kernel"; device = "/dev/by-name/boot"; installed-directly = true; }, { filename = "rootfs"; device = "/dev/by-name/rootfs"; installed-directly = true; }, /* 更新mypart, 此時(shí)掉電,mypart分區(qū)還是完整的*/ { filename = "mypart-r"; device = "/dev/by-name/mypart-r"; installed-directly = true; } ); bootenv: ( { name = "swu_mode"; value = "upgrade_usr"; }, /* 設(shè)置這個(gè)env,指示下次啟動(dòng),即啟動(dòng)到正常系統(tǒng)時(shí),使用mypart */ { name = "mypart_partition"; value = "mypart"; }, { name = "boot_partition"; value = "boot"; } ); }; ...

3.15 handler 說明

此處只對(duì)一些handler 做簡(jiǎn)介。

具體的handler 的用法,請(qǐng)參考swupdate 官方文檔說明。

3.15.1 awboot

3.15.1.1 nand/emmc

全志拓展的handler,用于支持升級(jí)全志boot0 和uboot,實(shí)質(zhì)上會(huì)調(diào)用外部的ota-burnboot包完成升級(jí)。

目前只支持nand/emmc,詳見ota-burnboot 章節(jié)。

使用方式:

選上handler 支持:

make menuconfig ---> Allwinner ---> <*> swupdate ---> Image Handlers --> [*] allwinner boot0/uboot

注意,recovery 系統(tǒng)也需要對(duì)應(yīng)進(jìn)行配置,即:

make ota_menuconfig ---> ...(重復(fù)以上配置)

在sw-description 中指定type 即可:

{ filename = "uboot"; /* 源文件是OTA包中的uboot文件*/ type = "awuboot"; /* type為awuboot,則swupdate會(huì)調(diào)用對(duì)應(yīng)的handler做處理*/ }, { filename = "boot0"; /* 源文件是OTA包中的boot0文件*/ type = "awboot0"; /* type為awuboot,則swupdate會(huì)調(diào)用對(duì)應(yīng)的handler做處理*/ }

3.15.1.2 nor

對(duì)于nor 方案,升級(jí)boot0/uboot 有掉電風(fēng)險(xiǎn)。如確需升級(jí),可直接配置合適偏移即可,不使用awboot handler。

例如已知boot0 存放在偏移為0 處,uboot 存放在偏移為24k 處,則配置:

{ filename = "boot0"; device = "/dev/mtdblock0"; installed-directly = true; }, { filename = "uboot"; device = "/dev/mtdblock0"; offset = "24k" installed-directly = true; }

3.15.2 readback

用于支持在sw-description 中配置sha256,在升級(jí)后讀出數(shù)據(jù)進(jìn)行校驗(yàn)。

一種應(yīng)用場(chǎng)景是,在AB 系統(tǒng)差分升級(jí)時(shí),應(yīng)用差分包后讀出校驗(yàn),以確認(rèn)差分得到的結(jié)果是對(duì)的,再切換系統(tǒng)。

需選上對(duì)應(yīng)handler。

make menuconfig/make ota_menuconfig --> Allwinner --> swupdate --> <*> Allow to add sha256 hash to each image make menuconfig/make ota_menuconfig --> Allwinner --> swupdate --> Image Handlers --> [*] readback

3.15.2.1 示例

target/allwinner/generic/swupdate/sw-description-readback target/allwinner/generic/swupdate/sw-subimgs-readback.cfg

3.15.3 ubi

用于ubi 方案。 需先選上MTD 支持:

make menuconfig/make ota_menuconfig --> swupdate --> Swupdate Settings ---> General Configuration ---> [*] MTD support

再選上對(duì)應(yīng)handler:

make menuconfig/make ota_menuconfig --> swupdate --> Image Handlers --> [*] ubivol

3.15.3.1 示例

請(qǐng)參考:

target/allwinner/generic/swupdate/sw-subimgs-ubi.cfg target/allwinner/generic/swupdate/sw-description-ubi

3.15.4 rdiff

rdiff handle 用于差分包升級(jí)。

需選上對(duì)應(yīng)handler:

make menuconfig/make ota_menuconfig --> swupdate --> Image Handlers --> [*] rdiff #若使用AB系統(tǒng)方案,則無recovery系統(tǒng),則make ota_menuconfig的配置可不做。

3.15.4.1 特性

https://librsync.github.io/page_rdiff.html 中指出

rdiff cannot update files in place: the output file must not be the same as the input file.

即不支持原地更新,即應(yīng)用差分包將A0 更新成A1,需要有足夠空間存儲(chǔ)A0 和A1,不能直接對(duì)A0 進(jìn)行改動(dòng)。

rdiff does not currently check that the delta is being applied to the correct file. If a delta is applied to the wrong basis file, the results will be garbage.

不校驗(yàn)原文件,如果將差分包應(yīng)用于錯(cuò)誤的文件,則會(huì)得到無效的輸出文件,但不會(huì)報(bào)錯(cuò)。

The basis file must allow random access. This means it must be a regular file rather than apipe or socket.

原文件必須支持隨機(jī)訪問,因此不能從管道或socket 中獲取原文件。 更多介紹請(qǐng)參考:https://librsync.github.io/

3.15.4.2 示例

首先需要將方案修改為AB 系統(tǒng)的方案,請(qǐng)參考上文的“AB 系統(tǒng)方案舉例”。

swupdate 的配置文件請(qǐng)參考:

target/allwinner/generic/swupdate/sw-description-ab-rdiff target/allwinner/generic/swupdate/sw-subimgs-ab-rdiff.cfg

差分文件的生成使用rdiff:

$ rdiff -h Usage: rdiff [OPTIONS] signature [BASIS [SIGNATURE]] [OPTIONS] delta SIGNATURE [NEWFILE [DELTA]] [OPTIONS] patch BASIS [DELTA [NEWFILE]]

tina 封裝了一條命令,用于解出兩個(gè)swu 包并生成各個(gè)子鏡像的差分文件。

一種參考的差分包生成方式是,先按普通的升級(jí)方式生成整包。

假設(shè)舊固件對(duì)應(yīng)V1.swu,新固件對(duì)應(yīng)V2.swu,則可使用:

swupdate_make_delta V1.swu V2.swu

生成差分文件。

再將生成的差分文件,用于生成差分的OTA 包。

例如:

make && pack #生成V1固件 swupdate_pack_swu -ab #得到out/r328s2-perf1/swupdate/tina-r328s2-perf1-ab.swu cp out/r328s2-perf1/swupdate/tina-r328s2-perf1-ab.swu V1.swu #保存V1的OTA包 #進(jìn)行一些修改 make && pack #生成V2固件 swupdate_pack_swu -ab #得到out/r328s2-perf1/swupdate/tina-r328s2-perf1-ab.swu cp out/r328s2-perf1/swupdate/tina-r328s2-perf1-ab.swu V2.swu #保存V2的OTA包 swupdate_make_delta V1.swu V2.swu #生成差分鏡像 swupdate_pack_swu -ab-rdiff #生成差分OTA包,這一步用到了剛剛生成的差分鏡像

3.15.4.3 開銷問題

差分升級(jí)的主要好處在于節(jié)省傳輸?shù)奈募笮?。而不是?jié)省ram 和rom 的占用。

設(shè)備端在進(jìn)行差分升級(jí)時(shí),需要使用版本匹配的舊版本鏡像,加上差分包,生成新版本鏡像。

rsync 不支持原地更新,必須有額外的空間保存新生成的鏡像。

從掉電安全的角度考慮,在新版本鏡像完整保存到flash 之前,舊版本鏡像不能破壞,否則一旦中途掉電,將無法再次使用舊鏡像+ 差分包生成新鏡像,只能聯(lián)網(wǎng)

下載完整的OTA 包。

以上限制,導(dǎo)致flash 必須在舊鏡像之外,有足夠flash 空間用于存放新的鏡像。

對(duì)于recovery 方案,原本的:

從OTA包獲取新recovery寫入recovery分區(qū)--> reboot --> 從OTA包獲取新kernel寫入boot分區(qū)--> 從OTA包獲取新rootfs升級(jí)rootfs分區(qū)--> reboot

就需要變成:

從OTA包獲取recovery差分包,讀recovery分區(qū),生成新recovery暫存到文件系統(tǒng)中--> 從文件系統(tǒng)獲取新recovery寫入recovery分區(qū)--> reboot --> ...

總體較為麻煩,且需要文件系統(tǒng)足夠大。 對(duì)于AB 方案,原本的:

從OTA包獲取新kernel寫入bootB分區(qū)--> 從OTA包獲取新rootfs寫入rootfsB分區(qū)--> reboot

就需要變成:

從OTA包獲取kernel差分包,讀出bootA分區(qū),合并生成新kernel寫入bootB分區(qū)--> 從OTA包獲取rootfs差分包,讀出rootfsA分區(qū),合并生成新rootfs寫入bootB分區(qū)--> reboot

不需要依賴額外的文件系統(tǒng)空間。

因此,若希望節(jié)省ram/rom 占用,差分包并非解決的辦法。若希望使用差分包,建議配合AB 系統(tǒng)使用。

3.15.4.4 管理問題

差分包的一個(gè)麻煩問題在于,差分包必須跟設(shè)備端的版本匹配。而出廠之后的設(shè)備,可能存在多種版本。

例如出廠為V1,當(dāng)前最新為V4,則設(shè)備可能處于V1,V2,V3。此時(shí)若使用整包升級(jí),則無需區(qū)分。

若使用差分升級(jí),一種策略是為每個(gè)舊版本生成一個(gè)差分包,則需要制作三個(gè)差分包V1_4,V2_4,V3_4,并在OTA 時(shí)先判斷設(shè)備端和云端版本,再使用對(duì)應(yīng)的差

分包。

另一種策略是,只為上一個(gè)版本生成差分包V3_4,并額外準(zhǔn)備一個(gè)整包。在OTA 時(shí)先判斷設(shè)備端版本和云端版本,若可相差一個(gè)版本則使用差分包,若跨版本則

使用整包。不管哪一種,都需要應(yīng)用做出額外的判斷。這一點(diǎn)需要主應(yīng)用和云端服務(wù)器做好處理。

3.15.4.5 校驗(yàn)問題

目前社區(qū)支持的rdiff 本身并不包含較好的校驗(yàn)機(jī)制,即應(yīng)用一個(gè)版本不對(duì)的差分包,也能跑完升級(jí)流程。這樣一旦出錯(cuò),就會(huì)導(dǎo)致機(jī)器變磚。

一種可考慮的方式是搭配readback 使用,即在應(yīng)用差分包,寫入目標(biāo)分區(qū)之后,將更新后的目標(biāo)分區(qū)數(shù)據(jù)讀出,校驗(yàn)其sha256 是否符合預(yù)期,校驗(yàn)成功才切換系

統(tǒng),校驗(yàn)失敗則報(bào)錯(cuò)。

可參考

target/allwinner/generic/swupdate/sw-description-ab-rdiff-sign target/allwinner/generic/swupdate/sw-subimgs-ab-rdiff-sign.cfg

其中增加了readback 的處理。

具體的,sw-subimgs-xxx.cfg 中可以配置swota_copy_file_list,指定一些文件只拷貝到swupdate 目錄,不打包到最終的OTA 包(swu 文件)中。因?yàn)樵谶@個(gè)場(chǎng)

景下,我們需要原始的kernel, rootfs 等文件來計(jì)算sha256,但并不需要將其加入最終的OTA 包中。

3.15.4.6 跟ubi 的配合問題

swupdate 官方目前沒有支持rdiff 用于ubi 卷。

目前采用增加預(yù)處理腳本的方式來兼容,即在執(zhí)行rdiff handler 之前,先調(diào)用腳本使用ubiupdatevol創(chuàng)建一個(gè)可用于升級(jí)目標(biāo)ubi 卷的fifo。隨后rdiff handler 即

可將此fifo 當(dāng)作目標(biāo)裸設(shè)備,無需特殊處理ubi 卷。在后處理腳本中,再通過填0 的方式,結(jié)束所有的ubiupdatevol。

具體可參考如下文件夾中的配置和腳本:

target/allwinner/r329-evb5/swupdate

前提仍然是配置好AB 系統(tǒng),使用方式:

# 編譯系統(tǒng),得到要燒錄的固件,記為V1 make && pack # 生成OTA包,此OTA包的各個(gè)分區(qū)鏡像跟V1固件的鏡像一致 swupdate_pack_swu -ab cp out/r329-evb5/swupdate/tina-r329-evb5-ab.swu tina-r329-evb5-ab_V1.swu # 進(jìn)行修改,編譯出V2的系統(tǒng) make && pack # 生成OTA包,此OTA包的各個(gè)分區(qū)鏡像跟V2固件的鏡像一致 swupdate_pack_swu -ab cp out/r329-evb5/swupdate/tina-r329-evb5-ab.swu tina-r329-evb5-ab_V2.swu # 此時(shí)tina-r329-evb5-ab_V2.swu 可用于正常的OTA升級(jí) # 生成各個(gè)鏡像的差分文件 swupdate_make_delta ./tina-r329-evb5-ab_V1.swu ./tina-r329-evb5-ab_V2.swu # 基于上一步得到的差分文件,生成差分OTA包 swupdate_pack_swu -ab-rdiff

4 Tina misc-upgrade 介紹(建議改用swupdate)

4.1 方案選擇

misc-upgrade 只支持recovery 系統(tǒng)方案。

由于在實(shí)際應(yīng)用中,存儲(chǔ)操作系統(tǒng)和持久文件的存儲(chǔ)介質(zhì)(如nand、emmc、spinor)大小各異,在OTA 中需要單獨(dú)在存儲(chǔ)介質(zhì)上開辟recovery 分區(qū),以防備在

更新中意外斷電,造成系統(tǒng)更新失敗無法重啟的問題。

所以在選擇OTA 方案時(shí)一定要考慮到recovery 分區(qū)大小對(duì)分區(qū)規(guī)劃的影響,避免在小容量時(shí)recovery 分區(qū)太大導(dǎo)致分區(qū)規(guī)劃難題。

綜上因素,我們?cè)赥ina 上針對(duì)大容量和小容量設(shè)計(jì)了不同的方案。

4.1.1 小容量方案

小容量介質(zhì)一般指存儲(chǔ)介質(zhì)容量小于32M(一般為spi nor)。

在命令行中進(jìn)入Tina 根目錄,執(zhí)行命令進(jìn)入配置主界面:

source build/envsetup.sh (見詳注1) lunch (見詳注2) make menuconfig (見詳注3)

詳注: 1 加載環(huán)境變量及tina提供的命令 2 輸入編號(hào),選擇方案 3 進(jìn)入內(nèi)核配置主界面(對(duì)一個(gè)shell而言,前兩個(gè)命令只需要執(zhí)行一次)

配置路徑:

Target Image └─> *** Image Options *** [*] For storage less than 32M, enable this when using ota

選中該配置項(xiàng)后,rootfs 的/usr 會(huì)被分拆出一部分生成usr.squashfs(usr.img),并建立軟鏈接usr.fex。通過配置分區(qū)表將usr.fex 放在extend 分區(qū),開機(jī)后自動(dòng)

掛載到usr 目錄。這種設(shè)置的目的是可與recovery 鏡像(boot_initramfs)復(fù)用該分區(qū),以此起到節(jié)省存儲(chǔ)空間的作用。

因此小容量方案中,并無單獨(dú)的recovery 分區(qū),而是在OTA 升級(jí)時(shí)與extend 分區(qū)復(fù)用。

為了達(dá)到啟動(dòng)后自動(dòng)掛載extend 分區(qū)的效果。需要進(jìn)行配置。

對(duì)于busybox-init,默認(rèn)在pseudo_init 中會(huì)嘗試掛載usr。如果發(fā)現(xiàn)沒有正常掛載,請(qǐng)檢查/pseudo_init 中的mount_usr。

對(duì)于procd-init,可在

target/allwinner//base-files/etc/config/fstab

配置文件中,增加:

config 'mount' option target '/usr' option device '/dev/by-name/extend' option options 'ro,sync' option enabled '1'

4.1.2 大容量方案

大容量介質(zhì)一般指存儲(chǔ)介質(zhì)容量大于32M(一般是nand、emmc)。

對(duì)于大容量方案,不建議選中小容量方案中所述配置項(xiàng),即不需要usr.img 和extend 分區(qū),而只需要添加recovery 分區(qū),這樣在OTA 升級(jí)時(shí)會(huì)省去很多麻煩。

4.1.3 misc-upgrade

不管是小容量還是大容量,都要在make 之前選中應(yīng)用包misc-upgrade:

make menuconfig └─> Allwinner └─> <*> misc-upgrade...... read and write the misc partition

misc-upgrade 包主要功能是從指定服務(wù)器下載更新鏡像到本地,然后升級(jí)相應(yīng)分區(qū),期間會(huì)向misc 分區(qū)寫入升級(jí)階段的標(biāo)志,出現(xiàn)意外無法重啟時(shí)uboot 或內(nèi)核

(如果能夠啟動(dòng))可以根據(jù)misc 分區(qū)的狀態(tài)標(biāo)志進(jìn)行下一步的決策。

4.1.4 OTA 的升級(jí)流程

4.1.4.1 基本步驟

Tina3.0 及之前版本處理流程:

1. 備份busybox等資源到ram中, 使得OTA過程不依賴rootfs 2. 設(shè)置開始OTA的標(biāo)志,upgrade_pre 3. 將recovery系統(tǒng)寫入recovery分區(qū) 4. 設(shè)置標(biāo)志boot-recovery 5. 更新boot和rootfs分區(qū) 6. 設(shè)置標(biāo)志upgrade_post 7. 對(duì)于小容量方案,更新usr分區(qū) 8. 設(shè)置標(biāo)志upgrade_end 9. 重啟,重啟后為新系統(tǒng)

最新版本處理流程:

1. 設(shè)置開始OTA的標(biāo)志,upgrade_pre 2. 將recovery系統(tǒng)寫入recovery分區(qū) 3. 設(shè)置標(biāo)志boot-recovery 4. 主動(dòng)重啟,重啟后進(jìn)入recovery系統(tǒng) 5. 更新boot和rootfs分區(qū) 6. 設(shè)置標(biāo)志upgrade_boot0 7. 如果存在boot0鏡像,則更新boot0 8. 設(shè)置標(biāo)志upgrade_uboot 9. 如果存在uboot鏡像,則更新uboot 10. 設(shè)置標(biāo)志upgrade_post 11. 對(duì)于小容量方案,更新usr分區(qū) 12. 設(shè)置標(biāo)志upgrade_end 13. 重啟,重啟后為新系統(tǒng)

4.1.4.2 中途掉電

OTA 中途掉電后,下次啟動(dòng)會(huì)根據(jù)標(biāo)志,繼續(xù)完成OTA。

當(dāng)設(shè)置upgrade_pre 標(biāo)志之后掉電,重啟后仍是舊系統(tǒng),從該標(biāo)志之后的步驟開始執(zhí)行。

當(dāng)設(shè)置boot-recovery 標(biāo)志之后掉電,重啟時(shí),uboot 判斷到這個(gè)標(biāo)志,并直接啟動(dòng)recovery系統(tǒng),啟動(dòng)后,從該標(biāo)志之后的步驟開始執(zhí)行。

當(dāng)設(shè)置upgrade_post 標(biāo)志之后掉電,重啟時(shí)后為新系統(tǒng),從該標(biāo)志之后的步驟開始執(zhí)行。

4.2 分區(qū)處理

4.2.1 分區(qū)定義

?

表4-1: misc-upgrade 升級(jí)分區(qū)說明表

?

升級(jí)分區(qū)
boot 分區(qū) 基礎(chǔ)系統(tǒng)鏡像分區(qū),即/lib,/bin,/etc,/sbin 等非/usr,非掛載其他分 區(qū)的路徑,wifi 支持環(huán)境,alsa 支持環(huán)境、OTA 環(huán)境。
extend 分區(qū) 擴(kuò)展系統(tǒng)鏡像分區(qū),即/usr 應(yīng)用分區(qū),僅小容量方案有。
recovery 分區(qū)存放恢復(fù)系統(tǒng)鏡像,僅大容量方案有。
private 分區(qū) 存儲(chǔ)SN 號(hào)分區(qū)。
misc 分區(qū) 系統(tǒng)狀態(tài)、刷機(jī)狀態(tài)分區(qū)。
UDISK 分區(qū) 用戶數(shù)據(jù)分區(qū),一般掛載在/mnt/UDISK。
overlayfs 分區(qū) 存儲(chǔ)overlayfs 覆蓋數(shù)據(jù)。

4.2.2 分區(qū)大小配置

4.2.2.1 配置boot 分區(qū)大小

boot 分區(qū)鏡像的大小依賴內(nèi)核配置,必須小于等于sys_partition.fex/sys_partition_nor.fex中定義的boot 分區(qū)大小。

boot 分區(qū)鏡像大小設(shè)定:

make menuconfig └─> Target Images └─> *** Image Options *** (4) Boot (SD Card) filesystem partition size (in MB)

boot 分區(qū)大小設(shè)定:

[partition] name =boot size =8192 downloadfile ="boot.fex" user_type =0x8000

對(duì)于大容量方案,需要在sys_partition.fex 中添加recovery 分區(qū):

recovery 分區(qū)說明 如果啟用了OTA 升級(jí),需要去掉下面recovery 分區(qū)的注釋以提供恢復(fù)分區(qū)存儲(chǔ)恢復(fù)系統(tǒng)鏡像, 默認(rèn)以boot_initramfs.img 作為recovery.fex: [partition] name =recovery size =32768 downloadfile ="recovery.fex" user_type =0x8000

其中recovery.fex 是生成的boot_initramfs.img 軟鏈接而成。

4.2.2.2 rootfs 分區(qū)的大小

rootfs 分區(qū)不需要通過make menuconfig 去設(shè)定,直接根據(jù)鏡像大小修改分區(qū)文件即可。

4.2.2.2.1 小容量對(duì)于一些小容量flash 的方案(如16M),需在/bin 下存放聯(lián)網(wǎng)邏輯程序、

版本控制程序、下載鏡像程序、播報(bào)語音程序以及語音文件(這些文件在編譯時(shí)應(yīng)該install 到/bin 或者/lib 下),可以在固件編譯完后,查看rootfs.img 的大小再?zèng)Q

定sys_partition.fex 中rootfs 分區(qū)的大小。

4.2.2.2.2 大容量對(duì)于大容量flash 的方案(如128M 以上,或者有足夠的flash 空間存相

關(guān)鏡像),不需要小容量中那些OTA 額外的程序,直接查看rootfs.img 的大小設(shè)定分區(qū)文件即可。

4.2.2.3 extend 分區(qū)的大小

extend 分區(qū)用于小容量方案下boot_initramfs.img 和usr.img 的復(fù)用,其大小需要考慮多個(gè)方面: 1 . 編譯后usr.img 的大小 2 . make_ota_image 后initramfs 鏡像的大小 因此,extend 分區(qū)略大于boot_initramfs.img 和usr.img 兩個(gè)的最大值,并把extend 分區(qū)的大小值設(shè)置為initramfs 鏡像的大?。?/p>

make menuconfig └─> Target Images └─> *** Image Options *** (8) Boot-Recovery initramfs filesystem partition size (in MB)

4.2.2.4 其他分區(qū)

如private 、misc 等使用默認(rèn)的大小即可。

4.2.2.5 UDISK 分區(qū)

sys_partition.fex 中不指定UDISK 分區(qū)大小,則剩下的空間全部自動(dòng)分配進(jìn)入U(xiǎn)DISK 分區(qū)。

需要注意的是,因?yàn)镺TA 過程會(huì)在里面寫一些中間文件,所以一定要留取一定空間給UDISK 分區(qū),至少可以格式化掛載,而小容量flash 的方案,也要保證有256K~512K 的空間。

4.2.2.6 其他說明

在OTA 升級(jí)過程中并不能修改上述分區(qū)的大小,因此應(yīng)在滿足分區(qū)大小條件限制( 如3.2.1-3.2.3) 的情況下盡可能留有足夠的空余空間,以滿足OTA 升級(jí)添加內(nèi)容

的需求。

修改分區(qū)大小時(shí),盡量對(duì)齊到所用存儲(chǔ)介質(zhì)的塊大小。

對(duì)于大容量,使用recovery 分區(qū),對(duì)應(yīng)的,其env 定義中,boot_recovery 命令需定義為從recovery 分區(qū)啟動(dòng)系統(tǒng)。對(duì)于小容量,使用extend 分區(qū),對(duì)應(yīng)的,其

env 定義中,boot_recovery 命令需定義為從extend 分區(qū)啟動(dòng)系統(tǒng)。

4.3 misc-upgrade 升級(jí)

4.3.1 misc-upgrade 構(gòu)成

misc-upgrade 是Tina 下的一個(gè)應(yīng)用,其路徑為:

tina/package/allwinner//misc-upgrade

Makefile 符合tina 安裝包的書寫規(guī)范。

misc-upgrade 目錄結(jié)構(gòu)如下:

├── aw_fstab.init #小容量方案掛載用。 ├── aw_reboot.sh ├── aw_upgrade_autorun.init #自啟動(dòng)腳本。 ├── aw_upgrade_image.sh ├── aw_upgrade_lite.sh ├── aw_upgrade_log.sh ├── aw_upgrade_normal.sh #大容量方案。 ├── aw_upgrade_plus.sh ├── aw_upgrade_process.sh #小容量方案。 ├── aw_upgrade_utils.sh ├── aw_upgrade_vendor_default.sh ├── Makefile ├── readme.txt └── tools #編譯出write_misc和read_misc應(yīng)用。 ├── Makefile ├── misc_message.c ├── misc_message.h ├── read_misc.c └── write_misc.c

4.3.2 OTA 鏡像包編譯

在命令行中進(jìn)入Tina 根目錄,執(zhí)行命令進(jìn)入配置主界面(環(huán)境配置):

source build/envsetup.sh ( 詳見1 ) lunch ( 詳見2 ) make ota_menuconfig (可選) ( 詳見3 ) 詳注: 1 加載環(huán)境變量及tina 提供的命令。 2 輸入編號(hào),選擇方案。 3 進(jìn)入OTA config 配置界面。直接保存退出即可。 此步驟可選,目的是解決開發(fā)過程中defconfig_ota 未能及時(shí)更新而可能引發(fā)的編譯問題。

編譯命令:

make_ota_image ( 詳見1 ) make_ota_image --force ( 詳見2 ) 詳注: 1 在新版本代碼已經(jīng)成功編譯出燒錄固件的環(huán)境的基礎(chǔ)上,打包OTA 鏡像。 2 重新編譯新版本代碼,然后再打包OTA 鏡像。 注:不同介質(zhì)使用的boot0/uboot鏡像不同, make_ota_image需要sys_config.fex中的storage_type配置明確指出介質(zhì)類型, 才能取得正確的boot0.img和uboot.img。 具體可直接查看build/envsetup.sh中make_ota_image的實(shí)現(xiàn)。

執(zhí)行make_ota_image 之前,可通過make ota_menuconfig 對(duì)ota 的恢復(fù)系統(tǒng)鏡像

boot_initramfs.img 進(jìn)行配置,可根據(jù)實(shí)際情況,配置ota 恢復(fù)系統(tǒng)包含的功能。

如以下配置支持ramdisk 并選用xz 壓縮cpio :

make ota_menuconfig └─> target Images └─> [*] ramdisk └─> --- ramdisk └─> Compression (xz) --->

OTA 鏡像包路徑為:tina/out/xxx/ota/

目錄結(jié)構(gòu)如下:

├── boot0_sys #boot0升級(jí)文件。 │ ├── boot0.img │ └── boot0.img.md5 ├── boot0_sys.tar.gz #boot0升級(jí)文件的壓縮包。 ├── package_sys #某定制版OTA腳本使用,不在本文檔描述范圍。 │ ├── boot0.img │ ├── boot0.img.md5 │ ├── boot.img │ ├── boot.img.md5 │ ├── ota.tar │ ├── recovery.img │ ├── recovery.img.md5 │ ├── rootfs.img │ ├── rootfs.img.md5 │ ├── uboot.img │ └── uboot.img.md5 ├── ramdisk_sys #recovery系統(tǒng)升級(jí)文件。 │ ├── boot_initramfs.img │ └── boot_initramfs.img.md5 ├── ramdisk_sys.tar.gz #recovery系統(tǒng)升級(jí)壓縮包。 ├── target_sys #kernel和rootfs升級(jí)文件。 │ ├── boot.img │ ├── boot.img.md5 │ ├── rootfs.img │ └── rootfs.img.md5 ├── target_sys.tar.gz #kernel和rootfs升級(jí)壓縮包。 ├── uboot_sys #uboot升級(jí)文件。 │ ├── uboot.img │ └── uboot.img.md5 └── uboot_sys.tar.gz #uboot升級(jí)壓縮包。

其中” .img.md5 “是” .img “的校驗(yàn)值文件。

升級(jí)腳本不帶-n 參數(shù),則使用壓縮包,帶-n 則直接使用不壓縮的升級(jí)文件。

4.3.3 小機(jī)端OTA 升級(jí)命令

必選參數(shù):-f -p 二選一。

aw_upgrade_process.sh -f 升級(jí)完整系統(tǒng)(內(nèi)核分區(qū)、rootfs 分區(qū)、extend 分區(qū))。

aw_upgrade_process.sh -p 升級(jí)應(yīng)用分區(qū)( extend 分區(qū))。

可選參數(shù):-l , -d -u, -n。

注:對(duì)于大容量,用aw_upgrade_normal.sh 替代aw_upgrade_process.sh ,且一般用-f參數(shù)而不用-p。

4.3.3.1 大容量flash 方案

可以使用本地鏡像測(cè)試,如主程序下載校驗(yàn)好鏡像后,存在/mnt/UDISK/misc-upgrade 中,調(diào)用如下命令。

OTA 升級(jí)期間掉電,重啟后升級(jí)程序也能自動(dòng)完成燒寫,不需要依賴聯(lián)網(wǎng)重新下載鏡像。

4.3.3.1.1 -l 選項(xiàng)-l < 路徑>

如:

aw_upgrade_normal.sh -f -l /mnt/UDISK/misc-upgrade

( 注:mnt 前的根目錄“/” 最好帶上,misc-upgrade 后不要帶“/”) ( -l 參數(shù),默認(rèn)使用壓縮鏡像包)。

不使用-n 參數(shù)的方案需要部署上服務(wù)器上的鏡像是:

? recovery 系統(tǒng)和主系統(tǒng)(必選):ramdisk_sys.tar.gz 、target_sys.tar.gz。 ? uboot 和boot0(可選, 調(diào)用腳本時(shí)鏡像不存在則自動(dòng)跳過):uboot_sys.tar.gz,boot0_sys.tar.gz。

4.3.3.1.2 -n 選項(xiàng)如:

aw_upgrade_normal.sh -f -n -l /mnt/UDISK/misc-upgrade

一般情況下不使用-n 選項(xiàng),而是下載ramdisk_sys.tar.gz 、target_sys.tar.gz 及可選的uboot_sys.tar.gz、boot0_sys.tar.gz。

但對(duì)于某些ram 較小的平臺(tái),如R6 spinand 的情況,flash 的容量足夠放下大容量的OTA 包,但升級(jí)過程可能因?yàn)閞am 不足而失敗。

對(duì)于這種情況,可以選擇下載未壓縮的數(shù)據(jù),即上述xxx.tar.gz 解壓出來的所有內(nèi)容。

將多個(gè)分區(qū)數(shù)據(jù)文件下載到/mnt/UDISK/misc-upgrade 中,調(diào)用上述命令。

使用-n 參數(shù)的方案需要部署上服務(wù)器上的鏡像是: ? recovery 系統(tǒng)和主系統(tǒng)(必選):boot_initramfs.img 、boot.img 、rootfs.img 及其對(duì)應(yīng)的md5 后綴的校驗(yàn)文件。 ? uboot 和boot0(可選,調(diào)用腳本時(shí)鏡像不存在則自動(dòng)跳過):uboot.img、boot0.img 及其對(duì)應(yīng)的md5 后綴的校驗(yàn)文件。

4.3.3.2 小容量flash 方案

4.3.3.2.1 -l 選項(xiàng)原始的設(shè)計(jì)是用于網(wǎng)絡(luò)升級(jí),不能使用-l 參數(shù),升級(jí)區(qū)間出錯(cuò)重啟后,需

要聯(lián)網(wǎng)下載程序獲取鏡像。 后續(xù)考慮存在小容量設(shè)備插SD 卡升級(jí)的情況,支持了-l 參數(shù),命令類似上述的大容量方案,不贅述。

4.3.3.2.2 -d -u -n 選項(xiàng)

-d arg1 -u arg2

同時(shí)使用,-d 參數(shù)為可以ping 通的OTA 服務(wù)器的地址、-u 參數(shù)為鏡像的下載地址。

-n

-n 一些小ddr 的方案(如剩余可使用內(nèi)存在20m 以下的方案),可以使用這個(gè)參數(shù),shell 會(huì)直接下載不壓縮的4 個(gè)img 文件,這樣子設(shè)備下載后不需要tar 解壓,減少內(nèi)存使用。

如:

aw_upgrade_process -f -d 192.168.1.140 -u http://192.168.1.140/

升級(jí)shell 會(huì)先ping -d 參數(shù)( ping 192.168.1.140 ),ping 通過后,會(huì)根據(jù)升級(jí)命令和系統(tǒng)當(dāng)前場(chǎng)景請(qǐng)求下載: 無-n 參數(shù):

http://192.168.1.140/ramdisk_sys.tar.gz http://192.168.1.140/target_sys.tar.gz http://192.168.1.140/usr_sys.tar.gz

有-n 參數(shù):

http://192.168.1.140/boot_initramfs.img http://192.168.1.140/boot.img http://192.168.1.140/rootfs.img http://192.168.1.140/usr.img

使用-n 參數(shù)的方案需要部署上服務(wù)器上的鏡像是:boot_initramfs.img 、boot.img 、rootfs.img 、usr.img 及其對(duì)應(yīng)的md5 后綴的校驗(yàn)文件。

不使用-n 參數(shù)的方案需要部署上服務(wù)器上的鏡像是:ramdisk_sys.tar.gz 、target_sys.tar.gz、usr_sys.tar.gz。

注:若由misc-upgrade 自行下載鏡像,當(dāng)前實(shí)現(xiàn)暫不支持可選的boot0/uboot 鏡像,即不會(huì)自動(dòng)從服務(wù)器下載升級(jí)boot0/uboot。

4.4 腳本接口說明

對(duì)于小容量flash 的方案,沒有空間存儲(chǔ)鏡像,相關(guān)鏡像只會(huì)存在ram 中,斷電就會(huì)丟失。假如升級(jí)過程斷電,需要在重啟后重新下載鏡像。

aw_upgrade_vendor.sh 設(shè)計(jì)為各個(gè)廠家實(shí)現(xiàn)的鉤子,SDK 上只是個(gè)demo 可以隨意修改。

4.4.1 實(shí)現(xiàn)聯(lián)網(wǎng)邏輯

check_network_vendor(){ return 0 聯(lián)網(wǎng)成功(如:可以ping 通OTA 鏡像服務(wù)器)。 return 1 聯(lián)網(wǎng)失敗。 }

4.4.2 請(qǐng)求下載目標(biāo)鏡像

$1 : ramdisk_sys.tar.gz $2 : /tmp

download_image_vendor(){ # $1 image name $2 DIR $@ others rm -rf $2/$1 echo "wget $ADDR/$1" wget $ADDR/$1 -P $2 }

4.4.3 開始燒寫分區(qū)狀態(tài)

aw_upgrade_process.sh -p 主動(dòng)升級(jí)應(yīng)用分區(qū)的模式下,返回0 開始寫分區(qū)1 不寫分區(qū)。 aw_upgrade_process.sh -f 不理會(huì)這個(gè)返回值。 upgrade_start_vendor(){ # $1 mode: upgrade_pre,boot-recovery,upgrade_post #return 0 -> start upgrade; 1 -> no upgrade #reutrn value only work in nornal mode #nornal mode: $NORMAL_MODE echo upgrade_start_vendor $1 return 0 }

4.4.4 寫分區(qū)完成

upgrade_finish_vendor(){ #set version or others reboot -f }

4.4.5 -f (-n) 調(diào)用順序

1 . check_network_vendor -> 2 . upgrade_start_vendor -> 3 . download_image_vendor (ramdisk_sys.tar.gz, -n 為boot_initramfs.img)-> 4 .內(nèi)部燒寫、清除鏡像邏輯(不讓已經(jīng)使用鏡像占用內(nèi)存) -> 5 . download_image_vendor(target_sys.tar.gz, -n 為boot.img rootfs.img) -> 6 .內(nèi)部燒寫、清除鏡像邏輯(不讓已經(jīng)使用鏡像占用內(nèi)存) -> 7 . download_image_vendor(usr_sys.tar.gz, -n 為usr.img) -> 8 .內(nèi)部燒寫、清除鏡像邏輯(不讓已經(jīng)使用鏡像占用內(nèi)存) -> 9 . upgrade_finish_vendor

4.4.6 -p 調(diào)用順序

1 . check_network_vendor -> 2 . download_image_vendor (usr_sys.tar.gz) -> 3 . upgrade_start_vendor -> 4 . 檢測(cè)返回值,燒寫-> 5 . upgrade_finish_vendor

4.5 相關(guān)系統(tǒng)狀態(tài)讀寫

相關(guān)的信息存儲(chǔ)在misc 分區(qū),OTA 升級(jí)不會(huì)清除這個(gè)分區(qū)(重新燒寫鏡像會(huì)擦除)。

讀:

read_misc [command] [status] [version]

其中:

command 表示升級(jí)的系統(tǒng)狀態(tài)( shell 腳本處理使用)。 status 自由使用,表示用戶自定義狀態(tài)。 version 自由使用,表示用戶自定義狀態(tài)。

寫:

write_misc [ -c command ] [ -s status ] [ -v version ]

其中:

-c 不能隨意修改,只能由aw-upgrade shell 修改。 -s -v 自定義使用。

4.6 OTA 配置

4.6.1 recovery 系統(tǒng)生成

一般來說,默認(rèn)方案目錄下會(huì)有一份defconfig_ota 配置文件,該文件用于編譯生成一個(gè)帶ramdisk 的kernel ,即boot_initramfs.img ,作為OTA 期間燒寫到

recovery 分區(qū)或extend 分區(qū)的備份系統(tǒng)。

用戶可以基于原有的defconfig_ota 進(jìn)行配置,也可以自行拷貝defconfig 為新的defconfig_ota ,然后進(jìn)行適當(dāng)修改和配置。

執(zhí)行make ota_menuconfig 可進(jìn)行OTA 配置。

選上recovery 后綴,避免編譯recovery 系統(tǒng)時(shí),影響到主系統(tǒng)。

make ota_menuconfig ---> Target Images ---> [*] customize image name ---> Boot Image(kernel) name suffix (boot_recovery.img/boot_initramfs_recovery.img) ---> Rootfs Image name suffix (rootfs_recovery.img)

如果方案進(jìn)行了較多的修改,建議刪除原本的defconfig_ota ,然后拷貝defconfig 為新的defconfig_ota ,再進(jìn)行配置。

如上文所述,必須選上misc-upgrade 包,以及ramdisk 選項(xiàng),保留wifi 功能。其他選項(xiàng)可以關(guān)掉,以對(duì)生成的boot_initramfs.img 進(jìn)行裁剪。

4.6.2 recovery 系統(tǒng)切換

4.6.2.1 切換方式1:基于misc 分區(qū)

對(duì)于存在misc 分區(qū)的方案,可以在misc 分區(qū)中設(shè)置boot-recovery 標(biāo)志。啟動(dòng)時(shí),uboot 會(huì)檢測(cè)misc 分區(qū),如果為boot-recovery,則執(zhí)行env 中配置的

boot_recovery 命令啟動(dòng)內(nèi)核。否則執(zhí)行boot_normal 命令啟動(dòng)內(nèi)核。

因此,env 中需要正確配置boot_normal 和boot_recovery。類似:

boot_normal=sunxi_flash read 40007800 boot;bootm 40007800 boot_recovery=sunxi_flash read 40007800 extend;bootm 40007800

對(duì)于大容量方案boot_recovery 配置為recovey 分區(qū)啟動(dòng),對(duì)于小容量方案,boot_recovery配置為從extend 分區(qū)啟動(dòng)。

OTA 過程需要正確設(shè)置misc 分區(qū)的值。

4.6.2.2 切換方式2:基于env 分區(qū)

可以去除misc 分區(qū),直接基于env 進(jìn)行系統(tǒng)切換。OTA 過程需修改env 分區(qū)中的值。

一般是將env 的boot_normal 配置為從$boot_partition 分區(qū)啟動(dòng),即將要使用的分區(qū)抽離成一個(gè)變量。

類似:

boot_partition=boot boot_normal=sunxi_flash read 40007800 ${boot_partition};bootm 40007800

env 中默認(rèn)boot_partition=boot。需要切換到recovery 系統(tǒng)時(shí),在用戶空間直接設(shè)置env,設(shè)置boot_partition=recovery。需要切換回主系統(tǒng)時(shí),設(shè)置

boot_recovery=boot。

OTA 過程需要正確設(shè)置env 中的值。

4.7 對(duì)overlayfs 的處理

Tina 默認(rèn)使用overlayfs ,則用戶對(duì)原rootfs 的修改會(huì)記錄在rootfs_data 分區(qū)中。而OTA更新的是rootfs 分區(qū),默認(rèn)不會(huì)修改rootfs 分區(qū)。則用戶對(duì)rootfs 文件

的增加,刪除,修改操作都會(huì)保留,假如原本的rootfs 中有文件A ,用戶將其修改為A1 ,而OTA 更新將該文件修改為B ,則最終看到的仍然是A1 。這是由

overlayfs 的特性決定的,上層目錄的文件會(huì)屏蔽下層目錄。

如果希望OTA 之后,以O(shè)TA 更新的文件為準(zhǔn),移除所有用戶的修改。則可以在OTA 之后,重新格式化rootfs_data 分區(qū)。

4.8 對(duì)busybox-init 的處理

4.8.1 upgrade_etc 標(biāo)志(不再使用)

有些平臺(tái)使用了busybox-init ,以R6 為例子: R6 方案將啟動(dòng)方式從procd 修改為busybox-init ,不再使用procd 和overlayfs ,由此帶來一系列變化。

OTA 腳本通過1 號(hào)進(jìn)程的名字來判斷啟動(dòng)方式。并根據(jù)結(jié)果。在后續(xù)腳本中做區(qū)別處理。

對(duì)于busybox-init ,在第一次啟動(dòng)之后,會(huì)將etc 的文件拷貝到rootfs_data 分區(qū)中,并在后續(xù)掛載該分區(qū)作為etc 目錄。OTA 的過程不會(huì)更新rootfs_data 分區(qū)。

為了支持更新etc 目錄,增加了一個(gè)系統(tǒng)狀態(tài),upgrade_etc ,并在原本設(shè)置upgrade_end 的地方,改為設(shè)置成upgrade_etc 。而busybox-init 的啟動(dòng)腳本會(huì)判斷

此標(biāo)志,如果啟動(dòng)是標(biāo)志為upgrade_etc,則進(jìn)行etc 分區(qū)文件的更新,更新后設(shè)置系統(tǒng)狀態(tài)為upgrade_end 。

主系統(tǒng)指定了啟動(dòng)腳本init=/pseudo_init. 對(duì)于OTA 使用的recovery 系統(tǒng)也需要指定啟動(dòng)腳本,若所使用的方案未配置,可自行修改env ,在cmdline 中傳遞

rdinit=/pseudo_init 進(jìn)行指定。若文件系統(tǒng)中已經(jīng)有rdinit 文件(例如是一個(gè)到pesudo_init 的軟鏈接),則可使用rdinit=/rdinit。

4.8.2 etc_need_update 文件

rootfs_data 有兩種可能的用法

1.保存rootfs /etc 的副本,掛載到/etc,以支持/etc 可寫

2.用作overlayfs,以支持全目錄可寫,類似procd 方案 對(duì)于早期版本,僅支持1。對(duì)于當(dāng)前最新版本,/pseudo_init 的最上方可以配置,當(dāng)配置MOUNT_ETC=1, MOUNT_OVERLAY=0 時(shí),即為1,跟早期版本相同,此處只討論上述的1。 其行為如下:

燒錄后第一次啟動(dòng),rootfs_data 分區(qū)為空,則/pesudo_init 會(huì)格式化rootfs_data,將/etc文件拷貝一份到rootfs_data 的文件系統(tǒng),將rootfs_data 掛載為/etc,對(duì)用戶來說看到的/etc 就是rootfs_data 中的

第二次啟動(dòng),rootfs_data 中存在有效的文件系統(tǒng),直接掛載為/etc,對(duì)用戶來說看到的/etc就是rootfs_data 中的

此時(shí)若直接更新rootfs 分區(qū)中的rootfs,重啟,用戶看到的/etc 仍為rootfs_data 中的,不會(huì)改變

若創(chuàng)建/etc/etc_need_update 文件(OTA 之后應(yīng)該創(chuàng)建它),則下次啟動(dòng)/pseudo_init 腳本會(huì)將rootfs 分區(qū)中的/etc 進(jìn)行一次同步

同步/etc 的具體行為: 5.1. 將rootfs_data 掛載到/mnt 5.2. 將rootfs 分區(qū)的/etc 拷貝到/tmp/etc 5.3. 將rootfs_data 中不希望被覆蓋的文件,拷貝到/tmp/etc。例如wpa_supplocant.conf。如果有其他特殊文件不希望被OTA 覆蓋,可參考/pseudo_init 中的wpa_supplicant 的處理方法,修改/pseudo_init。 5.4. 將/tmp/etc 的內(nèi)容,拷貝回/mnt/etc(即rootfs_data 分區(qū)) 5.5. 創(chuàng)建標(biāo)志文件etc_complete,刪除標(biāo)志文件etc_need_update。若在此步驟完成前掉電,則下次啟動(dòng)會(huì)從步驟1 重新同步etc 5.6 將rootfs_data 的掛載點(diǎn)從/mnt 改為/etc, 繼續(xù)啟動(dòng)

4.9 常見問題

4.9.1 OTA 時(shí)出現(xiàn)SQUASHFS ERROR

此問題是由于Tina3.0 及更早版本的OTA ,在更新rootfs 分區(qū)時(shí),只是將busybox 等備份到ram 中,rootfs,分區(qū)尚處于掛載狀態(tài),此時(shí)如果有進(jìn)程訪問rootfs ,

則會(huì)出現(xiàn)錯(cuò)誤。

解決方式:

OTA 之前,關(guān)閉其他進(jìn)程,避免有進(jìn)程訪問rootfs 。如果確有進(jìn)程需要保留,將其依賴的資源提前備份到ram 中(相關(guān)代碼可參考OTA 腳本中的prepare_env 函數(shù))。

參照最新版本的做法,在更新完recovery 分區(qū)后,主動(dòng)reboot ,進(jìn)入recovery 系統(tǒng),在recovery 系統(tǒng)中更新boot 和rootfs 分區(qū)。

參考原生openwrt 的做法,在內(nèi)存中構(gòu)建ram 文件系統(tǒng)后,執(zhí)行切換根文件系統(tǒng)的操作,再進(jìn)行更新。

4.9.2 編譯OTA 包之后,正常編譯出錯(cuò)

出現(xiàn)編譯問題,可能是由于defconfig 被替換了。

請(qǐng)檢查下target 倉庫中方案對(duì)應(yīng)目錄的defconfig 和defconfig_ota 的狀況。當(dāng)前的OTA 包編譯過程,實(shí)質(zhì)上是備份defconfig ,使用defconfig_ota 替換defconfig

,執(zhí)行make ,最終還原defconfig。

如果此過程中斷,則defconfig 未被還原,會(huì)導(dǎo)致下次正常編譯出問題。

解決方式:

還原方案目錄下的defconfig 文件。

建議make menuconfig 和make ota_menuconfig 之后,及時(shí)在target 倉庫下將修改提交入git 倉庫中,避免修改丟失,方便在必要時(shí)進(jìn)行還原。

(此問題為Tina3.0 之前的問題,最新版本沒有此問題。)

4.9.3 是否可更新boot0/uboot

misc-upgrade 原設(shè)計(jì)流程中未包含此功能

當(dāng)前版本中,本地升級(jí)支持可選地更新boot0/uboot(存在鏡像則更新,不存在則跳過),網(wǎng)絡(luò)升級(jí)暫未支持。

具體升級(jí)功能由ota-burnboot 軟件包支持,細(xì)節(jié)請(qǐng)參考相關(guān)章節(jié)。

判斷是否支持的方式:搜索腳本中是否有地方調(diào)用了ota-burnboot0 和ota-burnuboot。

5 Tina upgrade app 介紹(建議改用swupdate)

5.1 功能簡(jiǎn)介

以前Tina 只有misc-upgrade,為了特殊需求,創(chuàng)建了本腳本。現(xiàn)在建議直接使用swupdate。

有些客戶,需要單獨(dú)更新應(yīng)用程序。一種解決方式是,將應(yīng)用程序單獨(dú)放到一個(gè)分區(qū)中,并在啟動(dòng)時(shí)掛載該分區(qū)。為了保證更新過程掉電重啟,仍有可用的應(yīng)用程

序,可設(shè)置兩個(gè)應(yīng)用分區(qū),并配合環(huán)境變量等選擇掛載。

5.2 應(yīng)用源碼

需修改應(yīng)用源碼的Makefile,將應(yīng)用涉及文件,全部安裝到/mnt/app 路徑。

如果應(yīng)用是二進(jìn)制形式,則請(qǐng)放到:

target/allwinner/xxx/busybox-init-base-files/mnt/app

5.3 menuconfig 設(shè)置

選中:

make menuconfig ---> Target Images ---> [*] Separate /mnt/app from rootfs

使得/mnt/app 目錄, 從rootfs 中分離出來。打包的時(shí)候, 會(huì)被制作成一個(gè)單獨(dú)的文件app.fex。 選中:

make menuconfig ---> Allwinner ---> <*> tina-app-upgrade

選中后,可使用

/sbin/aw_upgrade_dual_app.sh

進(jìn)行OTA。

5.4 分區(qū)設(shè)置

增加兩個(gè)分區(qū),名字固定為app 和app_sub,downloadfile 固定為app.fex,size 根據(jù)實(shí)際情況調(diào)整。

[partition] name = app size = 51200 downloadfile = "app.fex" user_type = 0x8000 [partition] name = app_sub size = 51200 downloadfile = "app.fex" user_type = 0x8000

5.5 env 設(shè)置

對(duì)于tina3.5.0 及之前版本,位于:

target/allwinner/${board}/configs/env-xxx.cfg

對(duì)于tina3.5.1 及之后版本,位于:

device/config/chips/${chip}/configs/${board}/linux/env-xxx.cfg

增加配置:

appAB=A #set applimit=0 to disable appcount check applimit=0 appcount=0

其中appAB 指定要啟動(dòng)時(shí)要掛載哪個(gè)分區(qū):

appAB=A 掛載/dev/by-name/app到/mnt/app appAB=B 掛載/dev/by-name/app到/mnt/app

applimit 和appcount 用于支持應(yīng)用的自動(dòng)回退功能。

5.6 自動(dòng)回退

applimit=0 時(shí),沒有任何作用。

applimit 非0 時(shí),會(huì)在每次啟動(dòng),遞增appcount 值,并檢測(cè)appcount 是否大于applimit,若大于,則切換掛載另一個(gè)app 分區(qū)。

例如,當(dāng)前掛載/dev/by-name/app,設(shè)置applimit=2,appcount=0。

則每次啟動(dòng),appcount 加一,兩次啟動(dòng)后,appcount =2,再次重啟,appcount+1=3>applimit,超過限制,自動(dòng)改成掛載/dev/by-name/app_sub。

這個(gè)功能主要是要解決,更新了一個(gè)有問題的應(yīng)用,導(dǎo)致無法正常啟動(dòng)應(yīng)用的問題。例如:

當(dāng)前處于app,OTA 更新了一個(gè)有問題的新應(yīng)用到app_sub 分區(qū),重啟,重啟后無法正常啟動(dòng)app_sub 中的新應(yīng)用。則applimit 次重啟后,會(huì)自動(dòng)改回使用app

分區(qū)中,舊的可用的應(yīng)用。 使用此功能,需要應(yīng)用在正常啟動(dòng)后,主動(dòng)使用 fw_setenv appcount 0 清空計(jì)數(shù)值,避免累積到applimit 切換分區(qū)。

5.7 OTA 步驟

5.7.1 生成OTA 包

tina 目錄下,執(zhí)行

make_ota_package_for_dual_app

生成OTA 包

out/xxx/ota_dual_app/app_ota.tar

5.7.2 下載OTA 包

通過網(wǎng)絡(luò)或ADB 等方式,將app_ota.tar 放到小機(jī)端/mnt/UDISK/app_ota.tar。

5.7.3 執(zhí)行OTA

執(zhí)行腳本:

aw_upgrade_dual_app.sh

5.8 調(diào)試

生成OTA 包的函數(shù),位于:

build/envsetup.sh function make_ota_package_for_dual_app()

可從生成的tar 文件中,將app.fex 解出來:

tar -xf out/xxx/ota_dual_app/app_ota.tar

解壓得到的app.fex,是一個(gè)ext4 文件系統(tǒng),可在linux 主機(jī),或推送到小機(jī)端,掛載,查看文件系統(tǒng)中的內(nèi)容:

mkdir app mount app.fex app ls aaa

6 其他功能

6.1 在用戶空間操作env

Tina 中支持了uboot-envtools 軟件包。

make menuconfig --> Utilities ---> <*> uboot-envtools

選上后即可在用戶空間使用fw_printenv 和fw_setenv 來讀寫env 分區(qū)的變量。

6.2 AB 系統(tǒng)切換

6.2.1 uboot 原生啟動(dòng)計(jì)數(shù)機(jī)制

uboot 原生支持了啟動(dòng)計(jì)數(shù)功能。該功能主要涉及三個(gè)變量。

upgrade_available=0/1 #總開關(guān),設(shè)置1才會(huì)進(jìn)行bootcount++及檢查切換,設(shè)為0則表示關(guān)閉此功能 bootcount=N #啟動(dòng)計(jì)數(shù),若upgrade_available=1,則每次啟動(dòng)bootcount++,并用于跟bootlimit比較 bootlimit=5 #配置判定啟動(dòng)失敗的閾值

即編譯支持該功能后,當(dāng)upgrade_available=1,則uboot 會(huì)維護(hù)一個(gè)bootcount 計(jì)數(shù)值,每次啟動(dòng)自動(dòng)加一,并判斷bootcount 是否超過bootlimit。如果未超

過,則正常啟動(dòng),執(zhí)行env中配置的bootcmd 命令。如果超過,則執(zhí)行env 中的altbootcmd 命令。

支持此功能后,啟動(dòng)腳本或主應(yīng)用需要在合適的時(shí)機(jī)清除bootcount 計(jì)數(shù)值,表示已經(jīng)正常啟動(dòng)。

配置:

使能:配置CONFIG_BOOTCOUNT_LIMIT 選擇bootcount存放位置, 如存放在env分區(qū)(掉電不丟失):配置CONFIG_BOOTCOUNT_ENV 如存放在RTC寄存器(掉電丟失):配置CONFIG_BOOTCOUNT_RTC 如需存放在其他位置可自行拓展

在用戶空間可配置upgrade_available 的值對(duì)此功能進(jìn)行動(dòng)態(tài)開關(guān)。例如可在OTA 之前打開,確認(rèn)OTA 成功后關(guān)閉。也可一直保持打開。在用戶空間,需要清空

bootcount,否則多次重啟就會(huì)導(dǎo)致bootcount 超過bootlimit。

6.2.2 全志定制系統(tǒng)切換

全志自己添加了CONFIG_SUNXI_SWITCH_SYSTEM 功能進(jìn)行系統(tǒng)切換。目前尚未大量使用,供參考。

對(duì)上接口:

在flash 的env 分區(qū)中設(shè)置了2 個(gè)標(biāo)志變量systemAB_now,systemAB_next。systemAB_now:由uboot 階段進(jìn)行設(shè)置, 該標(biāo)志位系統(tǒng)應(yīng)用只讀不能寫(通過工具

fw_printenv,或其他工具)。systemAB_next:無論是uboot 還是系統(tǒng)應(yīng)用都可讀可寫(一般uboot 不會(huì)主動(dòng)修改,除非系統(tǒng)已經(jīng)損壞需要切換)初始值一般設(shè)

置為

systemAB_next=A #表示下次啟動(dòng)A系統(tǒng) systemAB_now=A #表示當(dāng)前為A系統(tǒng),不設(shè)置也可以,uboot會(huì)自動(dòng)設(shè)置

當(dāng)前系統(tǒng)應(yīng)用可以通過systemAB_now 標(biāo)志識(shí)別當(dāng)前系統(tǒng)是A 系統(tǒng)還是B 系統(tǒng), 系統(tǒng)應(yīng)用可以把標(biāo)志變量systemAB_next=A/B 寫到env 分區(qū)里, 然后重啟. 重啟后

uboot 會(huì)去檢查systemAB_next 這個(gè)標(biāo)志, 如果標(biāo)志是systemAB_next=A,uboot 會(huì)啟動(dòng)A 系統(tǒng), 如果是systemAB_next=B,uboot 會(huì)啟動(dòng)B 系統(tǒng)。同時(shí)uboot 會(huì)根

據(jù)本次systemAB_next 的值設(shè)置systemAB_now 供系統(tǒng)讀取。

底層設(shè)置:

對(duì)上接口定義的是systemA/B,以系統(tǒng)為單位。目前的系統(tǒng)組成定義為包含kernel 和rootfs 分區(qū)??紤]不同方案,分區(qū)名可能不同,因此支持用環(huán)境變量指定具體

分區(qū)名,而不是hardcode為某個(gè)分區(qū)名。

systemA=boot A系統(tǒng)kernel分區(qū)名 rootfsA=rootfs A系統(tǒng)rootfs分區(qū)名 systemB=boot_B B系統(tǒng)kernel分區(qū)名 rootfsB=rootfs_B B系統(tǒng)rootfs分區(qū)名

底層實(shí)現(xiàn): 此機(jī)制會(huì)動(dòng)態(tài)修改boot_partition 和root_partition 的值。具體boot_partition 和root_partition 變量的作用,請(qǐng)參考本文檔其他章節(jié)的介紹。

7 注意事項(xiàng)

7.1 Q & A

Q:系統(tǒng)的哪些部分是可以升級(jí)的? A:kernel 和rootfs 是可以升級(jí)的,但為了掉電安全,需要搭配一個(gè)recovery 系統(tǒng)或者做AB 系統(tǒng)。對(duì)于nand 和emmc 來說,boot0/uboot 存在備份,可以升

級(jí)。對(duì)于nor來說,boot0/uboot 沒有備份,不能升級(jí)?;蛘哒f升級(jí)有風(fēng)險(xiǎn),中途掉電會(huì)導(dǎo)致無法啟動(dòng)。boot0/uboot 的升級(jí)具體可參考本文檔中的ota-burnboot

部分。對(duì)于swupdate 升級(jí)方案,可以自行在sw-description 中配置策略,升級(jí)自己的定制分區(qū)和文件,但務(wù)必考慮升級(jí)中途掉電的情況,必要的話需要做備份和

恢復(fù)機(jī)制。

Q:系統(tǒng)的哪些部分是不能升級(jí)的? A:分區(qū)表是不可升級(jí)的,因?yàn)楦膭?dòng)分區(qū)表后,具體分區(qū)對(duì)應(yīng)的數(shù)據(jù)也要遷移。建議在量產(chǎn)前規(guī)劃好分區(qū),為每個(gè)可能升級(jí)的分區(qū)預(yù)留部分空間,防止后續(xù)升級(jí)空

間不足。nor 方案的boot0/uboot 是不可升級(jí)的,因?yàn)闆]有備份。其余不確定是否能夠升級(jí)的,請(qǐng)向開發(fā)人員確認(rèn)。

Q:dts/sys_config 如何升級(jí)? A:默認(rèn)dts 和sys_config,會(huì)跟uboot 綁定生成一個(gè)bin 文件。因此升級(jí)uboot 實(shí)質(zhì)上是升級(jí)了uboot+dts/sys_config。

Q:能否單獨(dú)升級(jí)dts? A:目前默認(rèn)跟uboot 綁定,需要跟開發(fā)人員確認(rèn)如何將dts 獨(dú)立出來,放到獨(dú)立分區(qū)或者跟kernele 綁定到一起。如果是dts 位于獨(dú)立分區(qū),那么就需要修改配

置,將dts 放置到OTA 包中,OTA 時(shí)寫入到對(duì)應(yīng)分區(qū)。

Q:升級(jí)過程掉電重啟后,是從斷點(diǎn)繼續(xù)升級(jí)還是從頭升級(jí)? A:從頭開始升級(jí),例如定義了在recovery 系統(tǒng)中升級(jí)boot 分區(qū)和rootfs 分區(qū),則在升級(jí)boot 或rootfs 過程中斷電,重啟后均是從boot 重新開始升級(jí)。

8 升級(jí)失敗問題排查

凡是遇到升級(jí)失敗問題先看串口log,如果不行再看/mnt/UDISK/swupdate.log 文件

8.1 分區(qū)比鏡像文件小引起的失敗

log 大概如下。找error 的地方,可以看到recovery 分區(qū)比其鏡像小,所以報(bào)錯(cuò)。

[ERROR] : SWUPDATE failed [0] ERROR handlers/ubivol_handler.c : update_volume : 171 : " recovery" will not fit volume "recovery"

解決方法: 增加對(duì)應(yīng)方案tina/device/config/chips/< 芯片編號(hào)>/configs/< 方案>/sys_partition.fex 文件的對(duì)應(yīng)分區(qū)的大小

8.2 校驗(yàn)失敗

差分有嚴(yán)格的版本控制,當(dāng)出現(xiàn)checksum 有問題時(shí),基本可以歸類為這種問題。

解決方法:重新燒錄固件,制作差分包

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11182

    瀏覽量

    208519
  • 無線網(wǎng)絡(luò)
    +關(guān)注

    關(guān)注

    6

    文章

    1417

    瀏覽量

    65808
  • OTA
    OTA
    +關(guān)注

    關(guān)注

    7

    文章

    561

    瀏覽量

    35068
  • 開發(fā)指南
    +關(guān)注

    關(guān)注

    0

    文章

    34

    瀏覽量

    7519
  • Tina
    +關(guān)注

    關(guān)注

    2

    文章

    45

    瀏覽量

    16933
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Tina_Linux系統(tǒng)裁剪開發(fā)指南

    Tina_Linux系統(tǒng)裁剪開發(fā)指南1 概述2 Tina系統(tǒng)裁剪簡(jiǎn)介2.1 boot0裁剪2.2 uboot裁剪2.3 內(nèi)核裁剪2.3.1 刪除不使用的功能2.3.2 刪除不使用的驅(qū)動(dòng)2.3.3
    的頭像 發(fā)表于 03-06 09:52 ?1457次閱讀

    EAC0945 linux開發(fā)指南

    EAC0945 linux開發(fā)指南
    發(fā)表于 09-28 12:40

    EAC0945 linux開發(fā)指南

    `EAC0945 linux開發(fā)指南`
    發(fā)表于 10-31 12:18

    Rockchip Linux SDK uboot logo開發(fā)指南

    arm嵌入式vs-rk3399 板卡uboot logo 開發(fā)指南概述:本文檔主要介紹 rockchip linux sdk uboot logo 顯示的相關(guān)功能、配置以及開發(fā)過程中的注意事項(xiàng)。適用于 rockhip
    發(fā)表于 10-09 08:12

    Tiny6410 Linux開發(fā)指南詳解

    Tiny6410 Linux 開發(fā)指南
    發(fā)表于 07-08 17:12 ?210次下載
    Tiny6410 <b class='flag-5'>Linux</b><b class='flag-5'>開發(fā)指南</b>詳解

    A64開發(fā)板LCD開發(fā)指南

    A64開發(fā)板LCD開發(fā)指南,驅(qū)動(dòng)開發(fā)指南
    發(fā)表于 06-21 17:02 ?0次下載

    彩光燈開發(fā)指南

    彩光燈開發(fā)指南
    發(fā)表于 12-29 20:15 ?0次下載

    Linux的平臺(tái)下Mini210S裸機(jī)程序開發(fā)指南

    Linux的平臺(tái)下Mini210S裸機(jī)程序開發(fā)指南
    發(fā)表于 10-29 10:52 ?59次下載
    <b class='flag-5'>Linux</b>的平臺(tái)下Mini210S裸機(jī)程序<b class='flag-5'>開發(fā)指南</b>

    Rockchip Linux SDK的開發(fā)指南的詳細(xì)資料說明

    本文檔的主要內(nèi)容詳細(xì)介紹的是Rockchip Linux SDK的開發(fā)指南的詳細(xì)資料說明。
    發(fā)表于 01-10 17:17 ?74次下載
    Rockchip <b class='flag-5'>Linux</b> SDK的<b class='flag-5'>開發(fā)指南</b>的詳細(xì)資料說明

    Tina_Linux_系統(tǒng)軟件開發(fā)指南

    Tina_Linux_系統(tǒng)軟件開發(fā)指南
    的頭像 發(fā)表于 03-02 15:25 ?1719次閱讀
    <b class='flag-5'>Tina_Linux</b>_系統(tǒng)軟件<b class='flag-5'>開發(fā)指南</b>

    Tina Linux配置開發(fā)指南

    Tina Linux配置開發(fā)指南
    的頭像 發(fā)表于 03-02 15:28 ?1.6w次閱讀
    <b class='flag-5'>Tina</b> <b class='flag-5'>Linux</b>配置<b class='flag-5'>開發(fā)指南</b>

    Linux NOR開發(fā)指南

    Linux NOR開發(fā)指南
    的頭像 發(fā)表于 03-06 09:55 ?889次閱讀
    <b class='flag-5'>Linux</b> NOR<b class='flag-5'>開發(fā)指南</b>

    Tina Linux圖形系統(tǒng)開發(fā)指南

    本文檔將介紹 Allwinner Tina Linux 中已經(jīng)移植好的窗口系統(tǒng),以及怎么使用,包括 MiniGUI、QT5、EFL、GTK+(WebkitGtk、Midori)、DirectFB、Wayland,整體結(jié)構(gòu) 。
    的頭像 發(fā)表于 03-06 11:00 ?2982次閱讀
    <b class='flag-5'>Tina</b> <b class='flag-5'>Linux</b>圖形系統(tǒng)<b class='flag-5'>開發(fā)指南</b>

    Tina Linux音頻開發(fā)指南

    介紹Tina平臺(tái)音頻模塊的使用方法。
    的頭像 發(fā)表于 03-06 11:02 ?6075次閱讀
    <b class='flag-5'>Tina</b> <b class='flag-5'>Linux</b>音頻<b class='flag-5'>開發(fā)指南</b>

    Tina Linux PMU開發(fā)指南

    介紹使用Tina PMU 驅(qū)動(dòng)的使用方法。
    的頭像 發(fā)表于 03-06 11:05 ?1964次閱讀
    <b class='flag-5'>Tina</b> <b class='flag-5'>Linux</b> PMU<b class='flag-5'>開發(fā)指南</b>