1. 程式人生 > >【swupdate文件 三】SWUpdate: 嵌入式系統的軟體升級

【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解析器。

image_format

可以使用外部解析器,改變對映象的接受規則,以擴充套件支援新的映象型別,指明它們需要如何安裝。實際上,解析器就是檢索必須安裝哪些單個的映象以及如何安裝。

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

如果它正常工作,則開始頁面應該顯示如下圖所示。

website

如果下載了正確的映象,SWUpdate將開始處理接收到的映象。所有通知都被髮送回瀏覽器。SWUpdate提供了一種機制,可以將安裝進度傳送給接收方。實際上,SWUpdate接受一個物件列表,這些物件在應用程式中註冊了自身,在呼叫notify()函式時就會通知它們。
這也允許自行編寫處理程式通知上層錯誤條件或簡單地返回狀態。這使得可以簡單地新增一個自己的接收器,以實現以自定義的方式顯示結果:在LCD上顯示(如果裝置上有的話),或者通過網路傳送 回另一個裝置。

傳送回瀏覽器的通知示例如下圖所示:

webprogress

軟體集合可以通過傳遞 --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 的格式為 , 它允許在sw-description檔案中找到一個規則 的子集。有了這個選項就可以使用多重規則了 一種常見用法是在雙拷貝模式下。例如: -e “stable, copy1” ==> install on copy1 -e “stable, copy2” ==> install on copy2
-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_PATHCONFIG_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