【swupdate文件 三】SWUpdate: 嵌入式系統的軟體升級
SWUpdate: 嵌入式系統的軟體升級
概述
本專案被認為有助於從儲存媒體或網路更新嵌入式系統。但是,它應該主要作為一個框架來考慮,在這個框架中可以方便地嚮應用程式新增更多的協議或安裝程式(在SWUpdate中稱為處理程式)。
一個用例是從外部本地媒體(如USB-Pen或sd卡)進行更新。在這種情況下,更新是在沒有操作員干預的情況下完成的:它被認為是“一鍵更新”,軟體在復位時啟動,只需按下一個鍵(或者以任何目標可以識別的方式),自動進行所有檢查。最後,更新過程只向操作員報告狀態(成功或失敗)。
輸出可以使用幀緩衝裝置顯示在LCD上,也可以定向到序列通訊埠上(Linux控制檯)。
它通常用於單拷貝方案中,在initrd中執行(用Yocto提供的配方生成)。但是,通過使用軟體集合( collections ),可以在雙拷貝方案中使用它。
如果啟動了遠端更新,SWUpdate將啟動嵌入式web伺服器並等待請求。操作者必須上傳一個合適的映像,然後SWUpdate會進行檢查並安裝。所有輸出都通過AJAX通知的方式通知操作人員的瀏覽器。
功能
總體概覽
- 安裝在嵌入式介質上(eMMC、SD、Raw NAND、NOR、SPI-NOR flash)
- 檢查映象是否可用。映象以指定的格式(cpio)構建,它必須包含一個描述檔案,以描述必須更新的軟體。
- SWUpdate被認為可以更新裝置上的UBI卷(主要用於NAND,但不限於NAND)和映象。傳遞整個映象仍然用於對SD卡上的分割槽或MTD分割槽進行更新。
- 新分割槽模式。這與UBI容量有關。SWUpdate可以重新建立UBI卷,調整它們的大小並複製新軟體。一個名為“data”的特殊UBI卷在重新分割槽時,用於儲存和恢復資料,以保持好使用者資料。
- 使用zlib庫支援壓縮映象。支援tarball (tgz檔案)。
- 支援帶分割槽的USB-pen或未分割槽盤(主要用於Windows)。
- 支援更新檔案系統中的單個檔案。必須明確描述該檔案所在的檔案系統位置。
- 支援影象中單個元件的校驗和
- 使用結構化語言來描述映象。 這是使用 libconfig庫作為預設解析器完成的,它使用一種類似json的描述。
- 使用自定義的方式來描述映象。可以使用Lua語言編寫自己的解析器。examples目錄中提供了一個使用Lua中的XML描述的示例。
- 支援設定/刪除U-Boot變數
- 支援設定/擦除 GRUB環境塊變數
- 支援設定/刪除 EFI Boot Guard
- 使用嵌入式web伺服器的網路安裝程式(在Lua許可下的版本中選擇了Mongoose伺服器)。可以使用不同的web伺服器。
- 多種獲取軟體的介面 : - 本地儲存: USB, SD, UART,..
- OTA / 遠端 : - 整合的網路伺服器
- 從遠端伺服器拉取(HTTP, HTTPS, ..)
- 使用後端。SWUpdate是開放的,可以與後端伺服器進行通訊,以推出軟體更新。當前版本支援Hawkbit伺服器,但可以新增其他後端。
- 可以配置為檢查軟體和硬體之間的相容性。軟體映像必須包含條目,宣告這個軟體可在什麼版本硬體上執行。如果沒有通過相容性驗證,SWUpdate將拒絕安裝。
- 支援映象提取。製造商用一個映像包含用於多個裝置的軟體。這簡化了製造商的管理,並降低了單一軟體產品的管理成本。SWUpdate以流的形式接收軟體,不進行臨時儲存,並只提取需要安裝的裝置元件。
- 允許自定義處理器,通過自定義協議安裝FPGA韌體,微控制器韌體。
- 使用“make menuconfig”啟用/禁用特性。(Kbuild繼承自busybox專案)
- 映象在安裝之前經過身份認證和校驗
- 掉電安全
交付單一映象
主要概念是製造商提供單個大影象。所有單個的映象都被打包在一起(選擇cpio是因為它的簡單性和可流式處理),同時打包的還有另一個檔案(sw-description),該檔案包含每個獨立映象的元資訊。
sw-description的格式是可定製的:可以將SWUpdate配置為使用其內部解析器(基於libconfig),或者在呼叫外部的lua解析器。
可以使用外部解析器,改變對映象的接受規則,以擴充套件支援新的映象型別,指明它們需要如何安裝。實際上,解析器就是檢索必須安裝哪些單個的映象以及如何安裝。
SWUpdate使用“處理程式”來安裝單個映象:有用於將映象安裝到UBI卷或SD卡、CFI快閃記憶體等的處理程式。如果需要特殊的安裝程式,那麼也可以很容易地新增自己的處理程式。
例如,我們可以考慮一個帶有主處理器和一個或幾個微控制器的專案。為了簡單起見,我們假設主處理器使用專用協議通過UARTS與微控制器通訊。微控制器上的軟體可以使用專用協議進行更新。
可以擴充套件swuodate,編寫一個處理程式,實現專用協議的一部分來對微控制器進行升級。解析器必須識別哪個映象必須用新的處理程式來安裝,隨後SWUpdate將在安裝過程中呼叫該處理程式。
流式更新功能
SWUpdate被認為能夠將接收到的映象直接流式更新到目標中,而不需要任何臨時副本。實際上,單個安裝程式(處理程式)會接收一個檔案描述符作為輸入,該檔案描述符設定在必須安裝的影象的開始處。
該特性可以基於映象進行設定,這意味著使用者可以決定映象的哪些部分應該流式處理。如果沒有流式處理(請參見installed-direct標誌),檔案將臨時提取到環境變數 TMPDIR
指向的目錄中,如果沒有 設定 TMPDIR
,則預設使用 /tmp
。當然,使用流式處理,則不可能在安裝之前檢查整個交付的軟體。臨時副本僅在從網路更新時使用。 當映像儲存在外部儲存上時,不需要該副本。
完全流式更新映象
在遠端更新的情況下,SWUpdate從流中提取相關影象,並將它們複製 到環境變數TMPDIR
(如果未設定,則複製到 /tmp
)指向的目錄中,然後呼叫處理程式。這確保只有在所有部件都存在且正確時才會啟動更新。
但是,在一些資源較少的系統上,用於複製映象的RAM空間可能不足,例如,如果必須更新附加SD卡上的檔案系統的話。在這種情況下,如果影象能由相應的處理程式直接作為流安裝,而不需要臨時副本的話,則會很有幫助。並非所有處理程式都支援直接流式更新目標。零拷貝流是通過在單個映象像的描述中設定“installed-directly”標誌來啟用的。
配置和構建
需求
編譯SWUpdate只需要依賴幾個庫。
- mtd-utils: mtd-utils在內部生成libmtd和libubi。它們通常不匯出也不安裝,但是SWUpdate將連結它們,以便重用相同的功能來升級MTD和UBI卷。
- openssl: web伺服器需要。
- Lua: liblua和開發標頭檔案。
- libz和libcrypto總是需要被連結。
- libconfig: 被預設解析器使用。
- libarchive (可選的)用於存檔處理程式。
- libjson (可選的)用於JSON解析器和Hawkbit。
- libubootenv (可選的) 如果啟用了對U-Boot的支援則需要。
- libebgenv (可選的) 如果啟用了對EFI Boot Guard的支援則需要。
- libcurl 用於網路通訊。
新的處理程式可以向需求列表中新增一些其他的庫
-當出現構建錯誤時,檢查是否需要所有的處理程式,然後刪除其中不需要的部分。
在Yocto中進行構建
提供了一個 metasswupdate 層.它包含了mtd-utils和生成Lua所需的更改。
使用meta-SWUpdate只需一些簡單的步驟。
首先,克隆 meta-swupdate.
git clone https://github.com/sbabic/meta-swupdate.git
像往常一樣向 bblayer.conf 新增 meta-swupdate。 你還需要將 meta-oe 新增到list中。
在meta-swupdate中,有一個配方,用於生成帶有swupdate的initrd救援系統。
使用:
MACHINE=<your machine> bitbake swupdate-image
你將在 tmp/deploy/<your machine> 目錄中找到生成的結果。
如何安裝和啟動initrd是跟具體目標強相關的 - 請查閱你的引導載入程式的文件。
libubootenv呢 ?
這是構建SWUpdate時常見的問題。SWUpdate依賴於這個庫,它是從U-Boot原始碼生成的。
這個庫允許安全地修改U-Boot環境變數。如果不使用U-Boot作為引導載入程式,則不需要它。
如果無法SWUpdate正常連結,則你使用的是舊版本的U-Boot(你至少需要2016.05以上的版本)。
如果是這樣,你可以為包u-boot-fw-utils新增自己的配方,以新增這個庫的程式碼。
重要的是,包u-boot-fw-utils是用相同的引導載入程式原始碼和相同的機器構建的。
事實上,裝置可以使用一份直接連結到uboot中的預設環境變數,而不需要儲存在儲存器上。
SWUpdate應該知道這一點,因為它不能讀取這份環境變數:預設的這份環境變數也必須被連結到SWUpdate中。這是在libubootenv內部完成的。
如果構建的時候選擇了不同的機器,SWUpdate將在第一次嘗試更改環境變數時破壞環境變數。實際上,使用了錯誤的預設環境後,你的板子將不能再次被引導啟動。
配置SWUpdate
SWUpdate可以通過“make menuconfig”配置。使用內部解析器和禁用web伺服器可以達到較小的記憶體佔用。每個選項都有描述其用法的小幫助說明。 在預設配置中,許多選項已經被啟用。
要配置選項請執行:
make menuconfig
構建
- 要進行交叉編譯,請在執行make之前設定CC和CXX變數。 也可以使用make menuconfig將交叉編譯器字首設定為選項。
- 生成程式碼
make
結果是一個二進位制檔案“swupdate”。第二個構建的二進位制檔案是"process",但這並非嚴格要求的。這是一個示例,演示如何構建自己的SWUpdate介面來在HMI上顯示進度條或任何你想要的東西。具體到這個示例,則是簡單地在控制檯列印更新的當前狀態。
在Yocto構建系統中,:
bitbake swupdate
這將進行包的構建
bitbake swupdate-image
這將構建一個救援映象。 結果是一個可以由引導載入程式直接載入的Ramdisk。要在雙拷貝模式下使用SWUpdate的話,則將包swupdate放到你的rootfs中。檢查你的映象配方檔案,並簡單地將其新增到安裝包的列表中。
例如,如果我們想將它新增到標準的“core-image-full-cmdline”映象中,我們可以新增一個
recipes-extended/images/core-image-full-cmdline.bbappend
IMAGE_INSTALL += " \
swupdate \
swupdate-www \
"
swupdate-www是一個帶有網站的軟體包,你可以用自己的logo、模板和風格進行定製。
編譯一個debian包
SWUpdate被認為是用於嵌入式系統的,在嵌入式發行版中構建是首要的情況。但是除了最常用的嵌入式構建系統Yocto或Buildroot之外,在某些情況下還會使用標準的Linux發行版。不僅如此,發行版包還允許為了測試目的在Linux PC上執行SWUpdate,而不必與依賴項做鬥爭。使用debhelper工具,可以生成debian包。
編譯一個debian包的步驟
./debian/rules clean
./debian/rules build
fakeroot debian/rules binary
結果是一個儲存在父目錄中的“deb”包。
對源包簽名的替代方法
你可以使用dpkg-buildpackage:
dpkg-buildpackage -us -uc
debsign -k <keyId>
執行SWUpdate
執行一次swupdate可以期望得到什麼
SWUpdate的執行主要包括以下步驟:
- 檢查介質(usb pen)
- 檢查映象檔案。副檔名必須是.swu
- 從映象中提取sw-description並驗證它,它解析sw-description,在RAM中建立關於必須執行的活動的原始描述。
- 讀取cpio歸檔檔案並驗證每個檔案的校驗和,如果歸檔檔案未完全通過驗證,SWUpdate將停止執行。
- 檢查硬體-軟體相容性,如果有的話,從硬體中讀取硬體修改,並與sw-description中的表做匹配。
- 檢查在sw-description中描述的所有元件是否真的在cpio歸檔中。
- 如果需要,修改分割槽。這包含UBI卷的大小調整,而不是MTD分割槽的大小調整。一個名為“data”的卷被用於在調整大小時儲存和恢復資料。
- 執行預執行指令碼
- 遍歷所有映象並呼叫相應的處理程式以便在目標上安裝。
- 執行安裝後腳本
- 如果在sw-description中指定了更改,則更新引導載入程式環境變數。
- 向操作人員報告狀態(stdout)
有一個步驟失敗,則會停止整個過程並報告錯誤。
執行SWUpdate從檔案中獲取映象:
swupdate -i <filename>
帶著嵌入式伺服器啟動:
swupdate -w "<web server options>"
web伺服器主要的重要引數是"document-root"和"port"。
swupdate -w "--document-root ./www --port 8080"
嵌入式web伺服器取自Mongoose專案。
檢索所有選項列表:
swupdate -h
這個完整使用隨著程式碼交付的也沒。當然,它們可以定製和替換。網站使用AJAX與SWUpdate進行通訊,並向操作人員顯示更新的進度。
web伺服器的預設埠是8080。你可以從如下網址連線到目標裝置:
http://<target_ip>:8080
如果它正常工作,則開始頁面應該顯示如下圖所示。
如果下載了正確的映象,SWUpdate將開始處理接收到的映象。所有通知都被髮送回瀏覽器。SWUpdate提供了一種機制,可以將安裝進度傳送給接收方。實際上,SWUpdate接受一個物件列表,這些物件在應用程式中註冊了自身,在呼叫notify()函式時就會通知它們。
這也允許自行編寫處理程式通知上層錯誤條件或簡單地返回狀態。這使得可以簡單地新增一個自己的接收器,以實現以自定義的方式顯示結果:在LCD上顯示(如果裝置上有的話),或者通過網路傳送 回另一個裝置。
傳送回瀏覽器的通知示例如下圖所示:
軟體集合可以通過傳遞 --select 命令列選項來指定。 假設 sw-description檔案包含一個名為 stable 的集合, 加上 alt 的安裝位置,則可以這樣呼叫SWUpdate
swupdate --select stable,alt
命令列引數
Parameter | Type | 描述 |
---|---|---|
-f
|
string | 要使用的SWUpdate配置檔案 |
-b
|
string | 只有當選上CONFIG_UBIATTACH時才有效, 它在SWUpdate搜尋UBI卷時將MTDs列入黑名單。 示例:MTD0-1中的U-BOOT和環境變數 swupdate -b “0 1” |
-e
|
string | sel 的格式為
|
-h | 使用幫助 | |
-k | string | 選中 CONFIG_SIGNED 時可用 指定公鑰檔案 |
-l
|
int | 設定log級別 |
-L | 將log輸出到 syslog(local) | |
-i
|
string | 使用本地.swu檔案執行SWUpdate |
-n | 在模擬(dry-run)模式下執行SWUpdate | |
-N | string | 傳入當前安裝的軟體版本。這將用於檢查 新軟體版本一起檢查,禁止升級到舊版本。 版本號由4個數字組成: major.minor.rev.build 每個欄位都要在0..65535的範圍內 |
-o
|
string | 將流(SWU)儲存到一個檔案中 |
-v | 啟用詳細的輸出資訊 | |
-w
|
string | 啟動內部webserver並將命令列字串傳遞給它 |
-u
|
string | 啟動內部suricatta客戶端守護程序, 並將命令列字串傳遞給它 詳見suricatta的文件 |
-H
|
string | 設定板名和硬體版本 |
-c | 這個選項將檢查 *.swu 檔案的內部。 它確保sw-description中引用的檔案是存在的。 使用方法: swupdate -c -i
|
|
-p | string | 執行安裝後命令 |
-d
|
string | 選中 CONFIG_DOWNLOAD 時可用 啟動內部下載程式客戶端, 並將命令列字串傳遞給它。 請參閱下載程式的內部命令列引數 |
-u
|
string | 這是提取新軟體的URL。 URL是指向有效.swu映象的連結 |
-r
|
integer | 下載失敗前重試的次數。使用“-r 0”,則 SWUpdate在載入到有效軟體之前不會停止 |
-t
|
integer | 判斷下載連線丟失的超時時間 |
-a
|
string | 傳送用於基本身份驗證的使用者名稱和密碼 |
systemd整合
SWUpdate 具有可選的systemd支援,是由編譯配置開關 CONFIG_SYSTEMD
控制的。如果啟用,SWUpdate將向systemd傳送關於啟動完成的訊號,並可以可選地使用systemd的socket-based activation功能。
一個systemd服務單元檔案的示例 /etc/systemd/system/swupdate.service
以suricatta守護程序模式啟動SWUpdate,可能看起來像以下的樣子:
[Unit]
Description=SWUpdate daemon
Documentation=https://github.com/sbabic/swupdate
Documentation=https://sbabic.github.io/swupdate
[Service]
Type=notify
ExecStart=/usr/bin/swupdate -u '-t default -u http://localhost -i 25'
[Install]
WantedBy=multi-user.target
通過 systemctl start swupdate.service
進行啟動, SWUpdate在啟動時(重新)建立套接字。為了使用socket-based activation,還必須附帶一個systemd套接字單元檔案 /etc/systemd/system/swupdate.socket
:
[Unit]
Description=SWUpdate socket listener
Documentation=https://github.com/sbabic/swupdate
Documentation=https://sbabic.github.io/swupdate
[Socket]
ListenStream=/tmp/sockinstctrl
ListenStream=/tmp/swupdateprog
[Install]
WantedBy=sockets.target
在 swupdate.socket
被啟動後, systemd建立套接字檔案,並在SWupdate啟動時將它們交給SWUpdate. 例如,當與 /tmp/swupdateprog
對話時,systemd啟動 swupdate.service
並移交套接字檔案。 在以systemctl start swupdate.service
"常規"啟動SWupdate時也會傳遞Socket檔案。
注意,兩個 ListenStream=
指令中的套接字路徑 必須與SWUpdate配置中的CONFIG_SOCKET_CTRL_PATH
和 CONFIG_SOCKET_PROGRESS_PATH
中的套接字路徑匹配。 這裡描述了預設套接字路徑配置。
引導啟動程式的修改
SWUpdate 包含了核心和一個根檔案系統(映象),這必須由一個引導載入程式來啟動。如果使用U-Boot, 可以實現以下機制:
- U-Boot檢查是否需要進行軟體更新(檢查gpio、序列控制檯等)。
- 指令碼“altbootcmd”設定啟動SWUpdate的規則
- 當需要SWUpdate時, U-boot執行指令碼"altbootcmd"
更改U-Boot環境變數是安全的嗎?是的,但是必須正確配置U-Boot。Uboot支援雙備份環境變數,這可以使得更新器件掉電是安全的。板子的配置檔案必須定義CONFIG_ENV_OFFSET_REDUND或CONFIG_ENV_ADDR_REDUND。查閱U-Boot文件瞭解這些常量的作用以及如何使用它們。
還有一些可選的增強可以整合到U-boot中,以使系統更安全。其中我會建議的最重要的一個,是新增啟動技術支援到uboot中(文件在uboot的docs路徑下)。這講允許U-Boot追蹤對成功啟動應用的嘗試。如果啟動計數超過了限制,則可以自動啟動SWupdate,以替代損壞了的軟體。
GRUB預設情況下不像U-Boot那樣支援環境變數的雙副本。這意味著,在環境塊更新期間斷電時,環境塊有可能損壞。
為了最小化風險,我們沒有直接修改原始環境塊。而是將變數寫入臨時檔案,並在操作成功後呼叫rename指令。
構建一個單個的映象
cpio由於其簡單性而被用作容器。由此可以很簡單地生成映象。描述映象的檔案(預設是"sw-description",但是名稱是可以配置的)必須是cpio歸檔中的第一個檔案。 要生成映象,可以使用以下指令碼:
CONTAINER_VER="1.0"
PRODUCT_NAME="my-software"
FILES="sw-description image1.ubifs \
image2.gz.u-boot uImage.bin myfile sdcard.img"
for i in $FILES;do
echo $i;done | cpio -ov -H crc > ${PRODUCT_NAME}_${CONTAINER_VER}.swu
單個的子影象可以在cpio容器中按任意順序放置,除了sw-description,它必須是第一個子映象。要檢查生成的映象,可以執行以下命令:
swupdate -c -i my-software_1.0.swu
對複合映象的支援
在Yocto中可以自動生成單個映象。 meta-swupdate使用swupdate類擴充套件了類。配方應該繼承它,並新增自己的sw-description檔案來生成映象。
本文地址 https://www.cnblogs.com/zqb-all/p/10128215.html
譯自 swupdate 文件 https://sbabic.github.io/swupdate/swupdate.html
有更新會在github上釋出 https://zqb-all.github.io/swupdate/swupdate.html