李龍杰,李競擇,李澤銀
(中國兵器裝備集團自動化研究所有限公司,四川綿陽 621000)
傳統(tǒng)的嵌入式linux系統(tǒng)升級過程中,首次升級通常使用串口或者專用燒寫設(shè)備將bootloader 燒寫至目標(biāo)板的flash中作為基礎(chǔ)程序,然后通過該基礎(chǔ)程序?qū)?nèi)核以及文件系統(tǒng)升級,該過程均通過網(wǎng)絡(luò)下載至內(nèi)存中,然后燒寫至flash 完成。在首次flash 成功燒寫映像后,后續(xù)對所有映像的升級均可在bootloader 或linux 系統(tǒng)下使用網(wǎng)絡(luò)下載命令結(jié)合flash 擦寫命令共同完成。
上述無論是在bootloader 還是linux 系統(tǒng)下,升級任何程序都會經(jīng)歷網(wǎng)絡(luò)下載、擦除flash 分區(qū)、寫映像到flash 分區(qū)的過程。這種升級方式首先由于是手動單步完成,需要升級人員對操作命令以及對系統(tǒng)分區(qū)(擦寫固定地址及大小的)熟悉,這增加了升級難度,特別是有需求升級多映像多分區(qū)時,極易出錯。其次網(wǎng)絡(luò)下載映像后,沒有任何校驗檢查映像是否損壞就直接寫入分區(qū),若映像下載過程中損壞或者出錯,則會直接導(dǎo)致升級后設(shè)備不可用的風(fēng)險,特別是升級bootloader 出錯時,將導(dǎo)致設(shè)備無法啟動,風(fēng)險極大。最后,在bootloader 和linux 系統(tǒng)下保留了這些升級必要的flash 擦寫命令,將給系統(tǒng)帶來極大的安全隱患,如系統(tǒng)維護人員誤操作擦除或?qū)懭肓薴lash某區(qū)塊,誤操作系統(tǒng)所在分區(qū)將導(dǎo)致系統(tǒng)無法啟動,誤操作文件系統(tǒng)所在分區(qū)將導(dǎo)致文件丟失,造成系統(tǒng)運行異常,更有甚者將遭到商務(wù)競爭對手進入設(shè)備后對設(shè)備的破壞或惡意升級。本文將結(jié)合某工程中使用的uboot 作為bootloader 以及l(fā)inux2.6 內(nèi)核作為參考,介紹了一種將手動升級過程進行整合且裁剪系統(tǒng)級相關(guān)升級命令的方法,成功解決了手動單步執(zhí)行繁雜易出錯、升級映像可靠性不明確、安全性較低的問題。
嵌入式linux 系統(tǒng)軟件部分主要包含bootloader、linux 內(nèi)核、文件系統(tǒng)[1]。bootloader 是嵌入式板卡CPU上電后執(zhí)行的第一段代碼,通常CPU會根據(jù)配置在啟動引腳上的電平組合方式?jīng)Q定從NAND FLASH、NOR FLASH 還是網(wǎng)絡(luò)等啟動。bootloader 的主要功能是完成基本硬件初始化(如內(nèi)存、調(diào)試串口、網(wǎng)絡(luò)等外設(shè))、鏡像的搬移(將bootloder、內(nèi)核、文件系統(tǒng)拷貝至內(nèi)存中),并跳轉(zhuǎn)到內(nèi)核處執(zhí)行。內(nèi)核是操作系統(tǒng)核心,負責(zé)系統(tǒng)的進程管理、內(nèi)存管理、文件系統(tǒng)、網(wǎng)絡(luò)功能、硬件驅(qū)動、安全機制等[2]??筛鶕?jù)自身需要定制編譯的內(nèi)核運行更快具有更少更簡化的代碼[3]。文件系統(tǒng)定義了文件組成方式、存儲方式以及查找方式等。Linux常見的文件系統(tǒng)包括磁盤的文件系統(tǒng),如ext2、ext3、ext4、XFS、JFS、NTFS 等,閃存文件系統(tǒng),如JFFS2、YAFFS等,特殊用途的文件系統(tǒng),如sysfs、tmpfs、squashfs 等。嵌入式linux系統(tǒng)啟動過程如圖1所示。
圖1 Linux啟動過程
當(dāng)前目標(biāo)板提供了128MB的NAND FLASH,筆者將系統(tǒng)劃分為6個分區(qū),分區(qū)名以及功能如表1。
表1 系統(tǒng)分區(qū)情況
該方案將系統(tǒng)設(shè)計為雙分區(qū)系統(tǒng),mtd0存儲的是uboot 鏡像,mtd1存儲uboot 運行過程中使用的環(huán)境變量,其中,mtd2 和mtd3 兩個分區(qū)互為工作區(qū)和備份區(qū),增強設(shè)備可靠性,一般升級過程中僅升級備份區(qū),升級完成后,備份區(qū)切換為工作區(qū),工作區(qū)切換為備份區(qū)。mtd5分區(qū)存儲設(shè)備硬件形態(tài)關(guān)鍵數(shù)據(jù),軟件通過建立硬件抽象層識別和操作這些硬件,對上層軟件屏蔽了硬件形態(tài)差異,實現(xiàn)多形態(tài)硬件兼容。
針對上述分區(qū)設(shè)計情況,筆者首先實現(xiàn)了一個自編寫命令行打包工具,該工具將所有需要升級的映像打包為一個映像,該映像奠定了一鍵安全升級的基礎(chǔ)。映像包含一個頭,記錄了文件所包含的固件類型、大小、位置、校驗和、廠商信息、版本信息等內(nèi)容,如下所示:
在uboot 和linux 系統(tǒng)下分別實現(xiàn)一個升級命令,該升級命令實現(xiàn)了映像的下載、校驗、識別、flash 擦除、flash寫入、分區(qū)切換功能,可實現(xiàn)映像的一鍵下載及升級。同時,筆者裁剪掉了uboot 和linux 系統(tǒng)下的flash相關(guān)操作命令以及ftp、tftp下載命令,所有的升級映像下載均在自編寫升級命令中用代碼實現(xiàn)。
自編寫程序打包工具是一個在linux虛擬機上運行的命令行工具,名稱為”fw_pack”,使用方法如圖2所示。
該工具根據(jù)傳入的命令參數(shù)將升級固件uboot、uImage、rootfs 等打包為一個大的映像文件,該文件包含如前面描述的一個文件頭。打包并發(fā)布固件時,僅支持五類文件,如表2所示。
圖2 打包工具用法
表2 文件類型
根據(jù)需要升級的內(nèi)容添加或裁減命令行參數(shù),可打包成不同的映像。如需打包fw_all.bin,首先將uboot、uImage、rootfs 拷貝至打包工具所在目錄,然后執(zhí)行命令“fw_pack-t 4-u uboot.bin-k uImage-r rootfs.bin”,命令執(zhí)行后,將根據(jù)傳入的參數(shù)把所有文件信息填充到映像頭對應(yīng)域,然后將合并成一個bin文件,合并后的文件計算MD5校驗和并填充在映像頭的ucMd5Sum域。最后在命令行工具所在目錄輸出對應(yīng)的fw_all.bin。打包后,fw_all.bin文件映像結(jié)構(gòu)如表3所示(這里假定所有文件大小均為1Mbytes):
表3 映像結(jié)構(gòu)說明
在uboot 和linux 系統(tǒng)下分別實現(xiàn)一個升級命令,名稱為upgrade,使用用法如圖3所示。
圖3 升級命令
執(zhí)行升級命令后,升級程序根據(jù)傳入?yún)?shù)從對應(yīng)的ftp 服務(wù)器上下載指定文件名的映像,下載成功后將對映像的廠商以及校驗和進行合法性檢查,通過后寫入映像包含的內(nèi)容到參數(shù)指定分區(qū)。升級成功后根據(jù)傳入?yún)?shù)決定是否重啟設(shè)備,若需重啟,則立即重啟設(shè)備。升級過程如圖4所示。
由上述過程可以看出,無論需要升級系統(tǒng)哪些內(nèi)容,只有一個升級文件,且升級過程全由程序代碼邏輯控制,無任何人為干擾因素,提高了升級過程的自動化水平。并且在升級時對升級映像進行廠商合法性校驗以及對整個影響進行校驗和檢驗,當(dāng)且僅當(dāng)兩層校驗通過時才開始升級操作,提高了升級過程的安全性,防止設(shè)備開發(fā)或維護人員的誤操作或來自競爭對手的惡意升級。實現(xiàn)升級程序后,將uboot 下和系統(tǒng)下關(guān)于flash 的所有操作命令以及程序下載命令全部刪除,即該升級工具是實現(xiàn)升級功能的唯一通道。
如表1所示,系統(tǒng)采用雙分區(qū)系統(tǒng),且兩個分區(qū)互為工作區(qū)和備份區(qū),uboot 默認情況下將引導(dǎo)啟動工作區(qū)系統(tǒng),如果工作區(qū)系統(tǒng)損壞,則引導(dǎo)啟動備份區(qū)系統(tǒng)。那么uboot 如何檢測到工作區(qū)系統(tǒng)損壞?通常情況下,uboot 在將flash中的linux 內(nèi)核和根文件系統(tǒng)加載到內(nèi)存后,跳轉(zhuǎn)執(zhí)行內(nèi)核前,將計算一次內(nèi)核校驗和,校驗通過則啟動內(nèi)核,校驗不通過則放棄啟動[4]。這就為雙分區(qū)系統(tǒng)設(shè)計提供了可能,但這樣的設(shè)計顯然有問題,當(dāng)存儲根文件系統(tǒng)的flash區(qū)域存在壞塊或根文件系統(tǒng)遭遇破壞時,系統(tǒng)啟動時無法成功掛載根文件系統(tǒng),導(dǎo)致設(shè)備無法啟動。在使用本方案設(shè)置的系統(tǒng)中,將增加對根文件系統(tǒng)的校驗,內(nèi)核的校驗和可由mkimage生成,但根文件系統(tǒng)的校驗則沒有對應(yīng)工具可生成。因此,通過自編寫根文件生成工具在根文件系統(tǒng)文件前加上固定幀頭,幀頭中就存儲了根文件系統(tǒng)的校驗和,當(dāng)且僅當(dāng)內(nèi)核和根文件系統(tǒng)均校驗通過后,啟動內(nèi)核,uboot 引導(dǎo)啟動過程如圖5所示。
圖4 升級過程
圖5 uboot引導(dǎo)過程
筆者根據(jù)使用場景以及本升級方法重點解決的問題設(shè)計了以下幾種測試案例,案例中均使用fw_all.bin同時升級雙分區(qū)的方式進行:
1)升級映像不做任何修改,觀察是否成功升級。
2)更改升級映像廠商名為0x12345678,觀察是否成功升級
3) 更改升級映像校驗和為0xFFFFFFFF,觀察是否成功升級。
測試結(jié)果見表4。
表4 測試結(jié)果
本文介紹了一種在uboot 以及l(fā)inux 系統(tǒng)下,將所有系統(tǒng)升級內(nèi)容、升級過程進行整合,并結(jié)合裁剪系統(tǒng)級相關(guān)升級命令的方式,達到一鍵升級、安全升級的目的[5]。該方法增加了升級過程的自動化程度及安全性,可大大提高設(shè)備維護人員對設(shè)備的升級效率,更能防止競爭對手對設(shè)備的惡意升級。同時本系統(tǒng)設(shè)計為雙分區(qū)系統(tǒng),增加了設(shè)備的使用壽命以及遠程升級的安全性。該方法具有普遍適用性,可供其他嵌入式開發(fā)者參考使用。