基于VxWorks的bootrom代碼改進(jìn)
關(guān)鍵詞:VxWorks bootrom BSP makefile
1 問題的提出
VxWorks是Wind River公司開發(fā)的一種嵌入式操作系統(tǒng),具有強(qiáng)大的功能和友好的用戶界面。VxWorks軟件應(yīng)用非常廣泛,不僅應(yīng)用在網(wǎng)絡(luò)設(shè)備、家用電器當(dāng)中,而且還應(yīng)用在航天、導(dǎo)彈等高端領(lǐng)域。在網(wǎng)絡(luò)設(shè)備應(yīng)用領(lǐng)域中,通常利用VxWorks來開發(fā)bootrom代碼、BSP(Boadr Support Packet)代碼以及上層的網(wǎng)絡(luò)協(xié)議代碼。
通常,Bootrom軟件有以下功能:①通過串口下載操作系統(tǒng)映像;②通過串口升級(jí)自身映像;③通過串口下載系統(tǒng)配置文件、系統(tǒng)信息文件;④加載操作系統(tǒng)映像,使其正常啟動(dòng);⑤其它的輔助功能,如地址內(nèi)容查看功能、址內(nèi)容修改功能和bootrom菜單顯示信息控制的功能等。對(duì)于通常的bootrom代碼編譯,大多數(shù)用戶選擇使用GNU make的DOS命令來進(jìn)行。因?yàn)槿绻鸼ootrom不提供網(wǎng)口功能的話,單純的CPU驅(qū)動(dòng)部分代碼量是不大的;但如果提供網(wǎng)口功能的話,代碼量相對(duì)較大,文件之間的內(nèi)在關(guān)系比較復(fù)雜,因此,系統(tǒng)使用GNU make的DOS命令來編譯生成bootrom就顯得有點(diǎn)麻煩。Makefile文件主要是由“目標(biāo)”(target)、“依賴性”(dependencies)和“動(dòng)作”組成的一系列規(guī)則,而VxWorks提供的GNU make工具就是根據(jù)Makefile指定的規(guī)則來編譯和鏈接程序的。Makefile基本結(jié)構(gòu)雖然簡(jiǎn)單,但正確、靈活地運(yùn)用這些規(guī)則并不是那么輕松的事情。即使根據(jù)GNU Makefile規(guī)則書寫出適當(dāng)?shù)腗akefile文件,但隨著代碼的改變,Makefile還需要經(jīng)常修改,這就增加了BSP開發(fā)人員的負(fù)擔(dān)。而且,對(duì)于交換產(chǎn)品而言,其成本控制是非常嚴(yán)格的。對(duì)于存放bootrom軟件的Flash來說,通常要求大小為512KB,這樣就需要考慮到容量的限制。
因此,必須使用新的方法來簡(jiǎn)化bootrom代碼編譯,而且要在保證提供網(wǎng)口功能的情況下,系統(tǒng)提供的bootrom軟件小于512KB。
2 實(shí)現(xiàn)方法
2.1 通過建立工程生成bootrom映像
采用建立工程的方式可以有效地解決這個(gè)問題。首先依據(jù)bootrom中的BSP代碼來新建一個(gè)工程,然后將網(wǎng)中驅(qū)動(dòng)代碼加入到建好的工程中。這樣就可以通過編譯工程實(shí)現(xiàn)帶有網(wǎng)口下載功能的bootrom軟件。但對(duì)于VxWorks嵌入式系統(tǒng)而言,它有自己一套規(guī)范,求bootrom軟件在加電后必須從romInit()函數(shù)開始運(yùn)行,而建立工程所得的入口函數(shù)為sysInit()。因此需要增加一個(gè)系統(tǒng)殼代碼,這個(gè)殼代碼所要完成的任務(wù)就是加載bootrom工程的映像,并從romInit()開始執(zhí)行bootrom代碼。通過建立工程來調(diào)試bootrom代碼有以下優(yōu)點(diǎn)。
(1)責(zé)任分明
開發(fā)產(chǎn)品是一個(gè)復(fù)雜的工程,需要多人合作完成。對(duì)于CPU子系統(tǒng)和網(wǎng)口驅(qū)動(dòng)系統(tǒng)這兩塊內(nèi)容來說,更需要責(zé)任明確。通過建立工程來調(diào)試代碼,可以準(zhǔn)確地定位錯(cuò)誤文件和函數(shù)的位置。是BSP代碼出現(xiàn)問題,還是網(wǎng)口驅(qū)動(dòng)代碼出現(xiàn)問題,可以一目了然,做到責(zé)任明確。
(2)提高效率
通過建立工程可以節(jié)省書寫Makefile文件時(shí)間,并可以讓VxWorks軟件的友好圖形界面這優(yōu)點(diǎn)得到更好的體現(xiàn)。另外,建立工程也可以減少文件編譯排錯(cuò)的難度,方便工程文件的調(diào)試以及功能的驗(yàn)證,從而大大提高工作效率,加快工作進(jìn)度。
2.2 編寫殼代碼并實(shí)現(xiàn)加載
建立工程生成映像文件的入口函數(shù)為sysInit(),而VxWorks規(guī)范中要求系統(tǒng)加電后要從romInit()函數(shù)開始運(yùn)行。因此,需要設(shè)計(jì)一個(gè)方案來加載編譯工程得到的映像,而且要具備初始化CPU和SDRAM存儲(chǔ)空間的功能。
首先,系統(tǒng)從romInit()函數(shù)中開始運(yùn)行,完成CPU和SDRAM初始化,跳轉(zhuǎn)到函數(shù)romStart()運(yùn)行。然后,加載第二份bootrom代碼到系統(tǒng)的低地址處,運(yùn)行殼代碼中的sysInit()函數(shù),并調(diào)用自己構(gòu)造的解壓函數(shù)usrInit(),將壓縮后的工程映像文件解壓縮到系統(tǒng)高地址處,之后系統(tǒng)繼續(xù)運(yùn)行解壓后的bootrom代碼。此時(shí),系統(tǒng)開始運(yùn)行sysInit()函數(shù),調(diào)用VxWorks系統(tǒng)中的usrInit()函數(shù),開始初始化系統(tǒng)硬件、內(nèi)核以及其它外圍設(shè)備。
殼函數(shù)usrInit()代碼如下:
void usrInit(void){
volatile FUNCPTR absEntry;
if(inflate((UCHAR*)ROM_OFFSET(_binArrayStart),
(UCHAR *)(RAM_LOW_ADRS),&_binArrayEndbinArrayStart)!=OK)
return;
absEntry=(FUNCPTR)(RAM_LOW_ADRS);
(absEntry)();
}
其中RAM_LOW_ADRS為系統(tǒng)低地址,是操作系統(tǒng)運(yùn)行的起始地址,但bootrom可以利用低地址來實(shí)現(xiàn)在系統(tǒng)高地址的運(yùn)行。宏ROM_OFFSET用于準(zhǔn)確定位函數(shù)地址,因?yàn)閎ootrom中運(yùn)行的代碼要求以相對(duì)地址方式來尋址,而不能以絕對(duì)地址方式尋址。_binArrayStart為壓縮后二進(jìn)制代碼的開始符,_binArrayEnd為壓縮后二進(jìn)制代碼的結(jié)束符。Inflate()是VxWorks軟件的解壓縮函數(shù),用于解壓縮由deflate()壓縮函數(shù)壓縮的二進(jìn)制文件映像。同時(shí),需要將下述代碼添加到編譯規(guī)則文件rules.vxWorks中的相應(yīng)部分:
$(CC)-c $(CFLAGS)$(BSP_DIR)/unzip.c-o$(BSP_DIR)/unzip.o
$(LD)$(LDFLAGS)-e sysInit -Ttext $(RAM_LOW_ADRS)o
unzip_obj.o sysALib.o $(BSP_DIR)/unzip.o $(LIBS)flex.z.o
其中,unzip.c中包含構(gòu)造的殼函數(shù)usrInit()。SysInit()為解壓軟件入口函數(shù)。上述語(yǔ)句的功能:第一行完成殼文件的編譯,第二、三行完成殼目標(biāo)代碼與第二份bootrom代碼的鏈接。這樣,一個(gè)具有解壓功能的殼函數(shù)就被鏈接到第二份bootrom映像中了。
圖1、圖2是修改前的系統(tǒng)運(yùn)行方式與修改后系統(tǒng)運(yùn)行方式比較。
通過這兩種方式的比較可以看出,修改前系統(tǒng)運(yùn)行式與修改后的運(yùn)行方式有下面兩點(diǎn)差異;①第一份bootrom啟動(dòng)后,前者存在解壓縮自射映像的操作,而后者沒有;②對(duì)于第二份bootrom,前者沒有殼代碼,而后者有。
2.3 縮減文件長(zhǎng)度
通常第一份bootrom代碼只有兩個(gè)文件,一個(gè)是包含CPU和SDRAM初始化文件romInit.s,另外就是包含romStart()函數(shù)的bootInit.c文件。另外,根據(jù)需要還可以添加提供串口輪詢顯示功能的文件。對(duì)于第一份bootrom代碼,通常只有10KB左右(這是針對(duì)系統(tǒng)修改后的方式),而對(duì)于包含殼函數(shù)代碼的,通過建立工程并編譯而生成的第二份bootrom比較大,通常為570KB左右。(注意:這幾個(gè)數(shù)值是通過特定的產(chǎn)品來得出的結(jié)論,并不應(yīng)用于所有產(chǎn)品,但遇到類似的情況可以借鑒處理。)而其后面的一部分完全是0,可以考慮去掉這些0,但不能影響軟件的功能。經(jīng)過測(cè)試得出結(jié)論:去掉后面的0對(duì)系統(tǒng)功能和性能沒有任何影響。
通過文件的操作來實(shí)現(xiàn)兩份bootrom合并,合并后的大小要求小于或等于512KB。如果不采用任何措施,直接將兩個(gè)文件合并起來要在580KB左右,大于512KB,這是很多系統(tǒng)不能滿足的。第二份bootrom映像的后面部分的內(nèi)容類似表1所列的信息。
表1 bootrom映像部分二進(jìn)制內(nèi)容
000 | 210h | EB | E2 | BD | 95 | BD | 15 | 87 | AE | 3C | 74 | FD | 5C | 5F | 6A | FD | 8B |
000 | 220h | D6 | BD | 3A | EB | FF | 6F | CF | 2A | D2 | 69 | 95 | E9 | 34 | AE | E7 | EF |
000 | 230h | 86 | 94 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
000 | 240h | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
000 | 250h | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
從表1可以看出,在地址0x00078233處就是0值了。這樣可以通過對(duì)文件內(nèi)容的操作將0x00078240后面的內(nèi)容全部剔除,從而可將合并后的bootrom代碼控制在512KB以內(nèi)。當(dāng)然,我們通常會(huì)選擇一個(gè)整數(shù)值進(jìn)行操作,即將0x0007824后的所有值去掉即可。
這樣處理,可以減少維護(hù)和開發(fā)的工作量。如果按照以往的做法,bootrom軟件對(duì)外將有第一份和第二份的區(qū)別,無(wú)論是生產(chǎn)、上層軟件調(diào)試還是開發(fā),都需要分別對(duì)待,這樣維護(hù)量和開發(fā)量將會(huì)加大。而經(jīng)過修改后,可把區(qū)別只控制在開發(fā)階段,在線升級(jí)時(shí),可以按照一個(gè)軟件來通過串口或網(wǎng)口來進(jìn)行升級(jí)。通過對(duì)bootrom最后生成文件大小的控制,可以簡(jiǎn)化生產(chǎn)流程,加快生產(chǎn)進(jìn)度。
3 小結(jié)
在嵌入式操作系統(tǒng)中進(jìn)行程序開發(fā),需要經(jīng)常開辟新的思路,以一些簡(jiǎn)單的實(shí)現(xiàn)方式代替復(fù)雜易錯(cuò)的方式。在本次產(chǎn)品開發(fā)過程中,將bootrom映像生成方式由慣用的GNU make命令行實(shí)現(xiàn),修改為按照新建工程的方式來實(shí)現(xiàn),是一個(gè)相對(duì)好的方法,對(duì)整個(gè)產(chǎn)品的后續(xù)批量生產(chǎn)、用戶維護(hù)和后續(xù)開發(fā)都奠定了一個(gè)良好的基礎(chǔ)。