VxWorks啟動代碼romStart()函數分析
DanielLee_USTB 2013-6-14
QQ:382899443
好幾天沒有學習Vxworks了,真的有點悔恨。每每因各種原因止步夢想的跑道,上班的路上還真是充滿了羈絆。還好串口伺服器以及完成關鍵性驗證,暫時告一段落,繼續潛心學習。今天去一個複用器公司瞭解他們的產品,覺得他們做的很不錯,可以看出沒有多年積累不可能達到這麼高的技術水平。個人也一樣,在長跑的路上你偷懶了,慢下來,不想跑了,那麼什麼都不可能實現,只有堅持做認為對的事兒,才不後悔。
言歸正傳,開始研究bootInit.c中romStart()這個函數。
當romInit.s執行到LDR pc, L$_rStrtInRom時,就跳轉到這個位置去執行:
L$_rStrtInRom:.long ROM_TEXT_ADRS + FUNC(romStart)- FUNC(romInit)
可以看出顯然romStart顯然定位在了RAM,通過以上運算,計算出其在ROM中的位置,romInit應該對應於romInit.s在RAM中的位置。
VolatileFUNCPTR absEntry;
VOIDFUNCPTR ramfillLongs = fillLongs; /*force call to RAM */
#definefillLongs(a,b,c) ramfillLongs(a,b,c)
這裡面定義了一個函數指標ramfillLongs,只是對fillLongs換個名字而已。
暫時不管ROM_RESIDENT類型的鏡像,看看UNCOMPRESS類型。
(1) UNCOMPRESS
((FUNCPTR)ROM_OFFSET(copyLongs))(ROM_TEXT_ADRS, (UINT)romInit,
ROM_COPY_SIZE/ sizeof (long));
此時就直接把從ROM_TEXT_ADRS開始的ROM中的整個鏡像都拷貝到RAM中romInit的位置,比較容易理解,此時romInit應該定位在了RAM_LOW_ADRS處。
(2) COMPRESS
可以看到主要實現了兩段程式的拷貝,第一段是:
((FUNCPTR)ROM_OFFSET(copyLongs))(ROM_TEXT_ADRS, (UINT)romInit,
((UINT)binArrayStart- (UINT)romInit)/ sizeof (long));
這一部分是拷貝bootstrap,也就是romInit.s以及bootInit編譯後未經壓縮的目標檔案,這部分要在RAM中去執行;
第二部分是:
((FUNCPTR)ROM_OFFSET(copyLongs))
((UINT *)((UINT)ROM_TEXT_ADRS + ((UINT)BINARRAYEND_ROUNDOFF -
(UINT)romInit)), (UINT *)BINARRAYEND_ROUNDOFF,
((UINT)wrs_kernel_data_end - (UINT)binArrayEnd) / sizeof (long));
這段程式其實是跳過了壓縮的vxworks二進位檔案,從二進位的頂端BINARRAYEND_ROUNDOFF把資料區段拷貝到了BINARRAYEND_ROUNDOFF在RAM中的位置。如此看來就剩下壓縮的vxworks程式碼片段沒有解壓拷貝了。
(3)清除記憶體
由於啟動類型是coldbooting先不研究ROM_RESIDENT類型鏡像,可以看到主要執行了三段程式,第一個是:
fillLongs((UINT *)(SYS_MEM_BOTTOM),
((UINT)romInit - STACK_SAVE -(UINT)SYS_MEM_BOTTOM) /
sizeof(long), 0);
這實現了從SYS_MEM_BOTTOM到STACK_SAVE之前RAM的清零。
如圖灰色部分:
-------------- 0x00100000 = LOCAL_MEM_SIZE = sysMemTop()
| |
| RAM |
| 0 filled |
| |
|------------|= (romInit+ROM_COPY_SIZE) or binArrayStart
| ROM image |
|----------- | 0x00090000 = RAM_HIGH_ADRS = romInit
| STACK_SAVE |
|------------|
| | 0x00080000 = 0.5 Megabytes
| |
| |
| 0 filled |
| |
| | 0x00001000 = RAM_ADRS &RAM_LOW_ADRS
| |
| | exc vectors, bp anchor, exc msg, bootline
| |
| |
-------------- 0x00000000 = LOCAL_MEM_LOCAL_ADRS
第二部分是對於非壓縮方式UNCOMPRESS,清零了黃色的一段記憶體。
#if defined (UNCOMPRESS)
fillLongs((UINT *)((UINT)romInit + ROM_COPY_SIZE),
((UINT)SYS_MEM_TOP - ((UINT)romInit +ROM_COPY_SIZE))
/ sizeof(long), 0);
#else
第三部分是針對壓縮方式COMPRESS:
fillLongs((UINT *)wrs_kernel_data_end,
((UINT)SYS_MEM_TOP- (UINT)wrs_kernel_data_end) / sizeof (long), 0);
#endif /*UNCOMPRESS */
清零的是vxworks資料區段到SYS_MEM_TOP的RAM區。
(4)執行下一段程式
對於UNCOMPRESS方式,可以直接到absEntry= (FUNCPTR)usrInit;去執行;
對於COMPRESS方式,執行解壓程式,把從binArrayStart到binArrayEnd的二進位檔案解壓出來,放到RAM_DST_ADRS的位置,這時候應該定位到RAM_HIGH_ADRS上。
volatile FUNCPTRabsUncompress = (FUNCPTR) UNCMP_RTN;
if ((absUncompress) ((UCHAR*)ROM_OFFSET(binArrayStart),
(UCHAR *)RAM_DST_ADRS, binArrayEnd- binArrayStart) != OK)
不必擔心解壓出來的檔案過大在RAM裡面沒地方放,因為有((UINT)SYS_MEM_TOP- ((UINT)romInit這麼大的地方可以放解壓出來的代碼。
absEntry =(FUNCPTR)RAM_DST_ADRS;這時候程式的入口地址就是RAM_HIGH_ADRS。 最後通過(absEntry) (startType)跳轉到相應的入口函數,對於COMPRESS方式也應該去執行usrInit函數。