基于Bootloader的可靠嵌入式軟件遠(yuǎn)程更新機(jī)制
1 隨著嵌入式系統(tǒng)在各個(gè)領(lǐng)域的廣泛應(yīng)用,嵌入式軟件的維護(hù)變得日益重要[1]。嵌入式系統(tǒng)投入實(shí)際環(huán)境中運(yùn)行后,一部分在軟件開(kāi)發(fā)過(guò)程中無(wú)法充分測(cè)試的錯(cuò)誤便會(huì)暴露出來(lái);在嵌入式系統(tǒng)的運(yùn)行期內(nèi),用戶也往往會(huì)對(duì)嵌入式軟件提出新的功能要求和性能要求。因此,嵌入式軟件的更新逐漸成為嵌入式系統(tǒng)實(shí)際應(yīng)用的一個(gè)重要問(wèn)題。當(dāng)嵌入式系統(tǒng)安裝數(shù)量較多,或安裝位置不方便的情況下,采用人工更新方式會(huì)花費(fèi)較大的人力和物力。遠(yuǎn)程自動(dòng)更新則在嵌入式系統(tǒng)中設(shè)計(jì)一個(gè)有線或無(wú)線的通信接口,在異地采用遠(yuǎn)程通信的方式實(shí)現(xiàn)嵌入式軟件的自動(dòng)更新。該方式能有效地降低嵌入式軟件的更新和維護(hù)成本,因此受到了廣泛的關(guān)注。當(dāng)前對(duì)嵌入式軟件遠(yuǎn)程自更新技術(shù)的研究主要停留在更新方法的設(shè)計(jì)上,對(duì)如何確保更新過(guò)程的可靠性還沒(méi)有深入的研究。更新的可靠性主要受兩個(gè)方面的影響:一是更新數(shù)據(jù)遠(yuǎn)程傳輸?shù)?a class="contentlabel" href="http://2s4d.com/news/listbylabel/label/可靠">可靠性;另一方面是系統(tǒng)更新后啟動(dòng)的可靠性。在采用嵌入式Linux、Windows CE等較為復(fù)雜的操作系統(tǒng)時(shí),一般設(shè)計(jì)一個(gè)獨(dú)立的bootloader程序[2][3],對(duì)系統(tǒng)進(jìn)行初始化并引導(dǎo)嵌入式操作系統(tǒng)。這種結(jié)構(gòu)的嵌入式系統(tǒng)的啟動(dòng)與bootloader緊密相關(guān)。本文針對(duì)采用bootloader的嵌入式系統(tǒng),提出了一種高可靠的嵌入式軟件遠(yuǎn)程自動(dòng)更新機(jī)制,并以基于ARM微處理器[4]、嵌入式Linux操作系統(tǒng)[5]和無(wú)線通信接口的嵌入式系統(tǒng)為例進(jìn)行了軟硬件設(shè)計(jì)。然后將更新機(jī)制應(yīng)用到實(shí)際系統(tǒng)中進(jìn)行測(cè)試,最后給出了本文的結(jié)論。
本文引用地址:http://2s4d.com/article/152617.htm2 更新系統(tǒng)的總體結(jié)構(gòu)
本部分以ARM和嵌入式Linux操作系統(tǒng)為例,介紹遠(yuǎn)程自更新系統(tǒng)的整體結(jié)構(gòu)。支持遠(yuǎn)程自更新的嵌入式系統(tǒng)可以劃分為前端運(yùn)行模塊和后臺(tái)控制模塊兩部分。前端運(yùn)行模塊采用基于ARM9核心的S3C2410微處理器,最高主頻可達(dá)200Mhz,配有8M的RAM和32M的FLASH存儲(chǔ)器,運(yùn)行ARM-Linux嵌入式操作系統(tǒng),具有獨(dú)立設(shè)計(jì)的bootloader程序。后臺(tái)控制模塊用于實(shí)現(xiàn)對(duì)前端運(yùn)行模塊的遠(yuǎn)程異地控制,是系統(tǒng)的控制核心。前端運(yùn)行模塊通過(guò)無(wú)線模塊BCM860接入到CDMA2000-1X無(wú)線通信系統(tǒng),繼而連接到Internet。CDMA2000-1X是第2.5代移動(dòng)通信系統(tǒng),支持較高速率的數(shù)據(jù)分組業(yè)務(wù)。后臺(tái)控制模塊采用有線方式直接與Internet相連接,與前臺(tái)運(yùn)行模塊之間進(jìn)行標(biāo)準(zhǔn)的基于TCP/IP協(xié)議的通信。狀態(tài)信息、控制信息和更新文件都在這一數(shù)據(jù)鏈路上進(jìn)行傳輸。
圖1 系統(tǒng)結(jié)構(gòu)
3 更新系統(tǒng)的軟件設(shè)計(jì)
3.1 Flash存儲(chǔ)器的布局
傳統(tǒng)的采用Linux的嵌入式系統(tǒng)的FLASH存儲(chǔ)器的布局如圖2(a)所示。為了敘述方便,我們將Linux內(nèi)核和文件系統(tǒng)合并稱(chēng)為L(zhǎng)inux鏡像文件。系統(tǒng)進(jìn)行軟件更新時(shí),先把新鏡像文件下載到內(nèi)存中,然后燒寫(xiě)到FLASH的鏡像文件存儲(chǔ)區(qū),覆蓋舊的鏡像文件。該方法沒(méi)有考慮更新過(guò)程中可能遇到的干擾。如果在更新中因?yàn)橥话l(fā)的干擾出現(xiàn)更新數(shù)據(jù)錯(cuò)誤或燒寫(xiě)錯(cuò)誤,就可能導(dǎo)致軟件更新后bootloader無(wú)法啟動(dòng)新的鏡像文件,前端模塊無(wú)法運(yùn)行,并失去了與后臺(tái)控制中心的聯(lián)系,成為“孤立系統(tǒng)”。這種情況發(fā)生后只能到前端系統(tǒng)的安裝地點(diǎn)進(jìn)行人工處理,從而導(dǎo)致花費(fèi)較大的代價(jià)。
圖2 (a) 傳統(tǒng)的FLASH布局 (b) 自更新系統(tǒng)的FLASH布局
為了提高軟件更新的可靠性,本機(jī)制對(duì)FLASH存儲(chǔ)器的布局進(jìn)行了重新設(shè)計(jì),如圖2(b)所示。Bootloader存儲(chǔ)區(qū)后面設(shè)計(jì)了3個(gè)鏡像文件存儲(chǔ)區(qū)。其中一個(gè)存儲(chǔ)區(qū)用于存放當(dāng)前要啟動(dòng)的最新的鏡像文件,稱(chēng)為當(dāng)前區(qū);另一個(gè)存儲(chǔ)區(qū)用于存放上一版本的鏡像文件,稱(chēng)為前版本區(qū);剩下一個(gè)存儲(chǔ)區(qū)用于存放最初版本的鏡像文件,稱(chēng)為初版本區(qū)。當(dāng)前區(qū)和前版本區(qū)位于前兩個(gè)存儲(chǔ)區(qū),隨著軟件的更新而動(dòng)態(tài)交替變化。每次進(jìn)行軟件更新,把新的鏡像文件寫(xiě)入前版本區(qū),這樣當(dāng)前區(qū)就變成了前版本區(qū),前版本區(qū)則變成了當(dāng)前區(qū)。初版本區(qū)固定在第三個(gè)分區(qū),所存放的鏡像文件是嵌入式系統(tǒng)投入運(yùn)行時(shí)的最初程序,每次的軟件更新都不更改該存儲(chǔ)區(qū)的內(nèi)容。此外,在FLASH的高地址處設(shè)計(jì)一個(gè)參數(shù)存儲(chǔ)區(qū),用于存放需要固化的系統(tǒng)配置參數(shù)。更新程序需要用到啟動(dòng)點(diǎn)和更新位兩個(gè)配置參數(shù)。啟動(dòng)點(diǎn)用來(lái)指示bootloader需要從哪個(gè)存儲(chǔ)區(qū)加載鏡像文件,更新位用來(lái)指示系統(tǒng)進(jìn)行軟件更新的狀態(tài)。
3.2 更新任務(wù)的設(shè)計(jì)
在嵌入式Linux系統(tǒng)中,將更新該任務(wù)設(shè)計(jì)成一個(gè)阻塞在更新信號(hào)量上的進(jìn)程。系統(tǒng)每次啟動(dòng)后,更新進(jìn)程首先向后臺(tái)控制模塊報(bào)告當(dāng)前的軟件版本號(hào),隨后檢查FLASH上的更新位,然后進(jìn)入阻塞狀態(tài)。當(dāng)系統(tǒng)收到控制模塊發(fā)來(lái)的更新指令后,釋放更新信號(hào)量,更新進(jìn)程開(kāi)始進(jìn)行軟件更新。更新進(jìn)程采用TCP協(xié)議接收控制模塊發(fā)來(lái)的新程序鏡像文件??紤]到無(wú)線數(shù)據(jù)傳輸?shù)奶攸c(diǎn),為了增強(qiáng)傳輸可靠性,在應(yīng)用層設(shè)計(jì)一套具有校驗(yàn)、確認(rèn)和重傳功能的收發(fā)協(xié)議,以保證新鏡像文件的數(shù)據(jù)能夠準(zhǔn)確無(wú)誤的通過(guò)Internet和移動(dòng)通信系統(tǒng)傳輸?shù)角岸四K的內(nèi)存中。當(dāng)新鏡像文件下載完畢后,更新進(jìn)程先判斷前版本區(qū)在FLASH上的位置,然后調(diào)用FLASH的讀寫(xiě)函數(shù)將新鏡像文件寫(xiě)入前版本存儲(chǔ)區(qū)中。寫(xiě)完后將更新位置1,并更改啟動(dòng)點(diǎn)。如果當(dāng)前運(yùn)行的程序版本為最初版本,則將新鏡像文件同時(shí)寫(xiě)入前兩個(gè)存儲(chǔ)區(qū)。更新進(jìn)程的程序流程如圖3所示。
圖3 更新進(jìn)程流程圖
圖4 異常處理流程圖
3.3 更新后的啟動(dòng)流程
前端運(yùn)行模塊具有獨(dú)立的bootloader,并固化在FLASH存儲(chǔ)器的低地址處,系統(tǒng)啟動(dòng)后總是能夠進(jìn)入bootloader。Bootloader通過(guò)讀取參數(shù)存儲(chǔ)區(qū)的啟動(dòng)點(diǎn)參數(shù)來(lái)引導(dǎo)3個(gè)程序存儲(chǔ)區(qū)的某一個(gè)鏡像文件。在正常情況下,啟動(dòng)點(diǎn)參數(shù)總是指向當(dāng)前區(qū)。當(dāng)軟件更新后,啟動(dòng)點(diǎn)也隨之在存儲(chǔ)區(qū)1和存儲(chǔ)區(qū)2之間交替切換,指向新鏡像文件的存儲(chǔ)區(qū)。這樣,當(dāng)更新進(jìn)程重新啟動(dòng)前端模塊后,bootloader便會(huì)引導(dǎo)新的鏡像文件。
為了增強(qiáng)軟件更新后系統(tǒng)啟動(dòng)的可靠性,本機(jī)制利用ARM體系的異常來(lái)處理啟動(dòng)時(shí)的出錯(cuò)情況。在ARM體系結(jié)構(gòu)中有7種異常,與啟動(dòng)過(guò)程密切相關(guān)的異常有未定義指令、指令預(yù)取中止和數(shù)據(jù)訪問(wèn)中止3種。通過(guò)設(shè)計(jì)異常處理程序來(lái)加載備份存儲(chǔ)區(qū)的鏡像文件。當(dāng)bootloader引導(dǎo)新鏡像文件失敗后,進(jìn)入異常處理函數(shù),在此函數(shù)中將啟動(dòng)點(diǎn)更改為指向前版本區(qū),并把更新位置為2,表示已經(jīng)更改過(guò)兩次啟動(dòng)點(diǎn)。重啟系統(tǒng)后bootloader便會(huì)恢復(fù)引導(dǎo)上一版本的程序鏡像文件。由于軟件更新時(shí)只是在相鄰的存儲(chǔ)區(qū)寫(xiě)入了新鏡像文件,并未對(duì)上一版本程序的存儲(chǔ)區(qū)進(jìn)行任何操作,而且上一版本程序是更新前已經(jīng)正常啟動(dòng)運(yùn)行過(guò)的程序,所以一般情況下上一版本程序應(yīng)該能夠正常引導(dǎo)成功。如果由于意外干擾導(dǎo)致上一版本程序仍然無(wú)法啟動(dòng)成功,此時(shí)將再次進(jìn)入異常處理程函數(shù)。在函數(shù)中先讀取更新位的值,如果更新位為2則將啟動(dòng)點(diǎn)指向初版本區(qū),并把更新位置為3。重啟系統(tǒng)后bootloader便會(huì)引導(dǎo)最初版本的程序鏡像文件。最初版本的鏡像文件在前端模塊安裝后從未更改過(guò),并在安裝前進(jìn)行過(guò)驗(yàn)證測(cè)試,具有非常高的可靠性。當(dāng)新版本程序和上一版本程序都無(wú)法啟動(dòng)成功時(shí),系統(tǒng)嘗試啟動(dòng)最初版本的鏡像文件,以保證系統(tǒng)基本功能的正常運(yùn)行,并確保前端模塊與后臺(tái)控制模塊之間不會(huì)失去聯(lián)系。后臺(tái)控制模塊根據(jù)前端模塊啟動(dòng)后報(bào)告的版本號(hào)來(lái)獲知軟件更新的信息并采取相應(yīng)的措施。在異常處理函數(shù)中讀取啟動(dòng)點(diǎn)值的時(shí)候,如果讀取值異?;蜃x取出錯(cuò),則對(duì)啟動(dòng)點(diǎn)進(jìn)行修復(fù),異常處理函數(shù)的流程如圖4所示。通過(guò)利用啟動(dòng)點(diǎn)、更新位和異常處理程序,當(dāng)軟件更新過(guò)程中遇到了干擾和錯(cuò)誤時(shí),本機(jī)制能夠依次選擇啟動(dòng)兩個(gè)備份的軟件版本,有效地提高了軟件更新的可靠性,防止了“孤立系統(tǒng)”的出現(xiàn)。
4 測(cè)試結(jié)果
linux操作系統(tǒng)文章專(zhuān)題:linux操作系統(tǒng)詳解(linux不再難懂)
評(píng)論