首先通常都是彙編代碼:啟動時由系統複位導致PC為0為觸發條件:以2440代碼為例直接進入fw.s檔案,在有一些bsp包中這個彙編代碼的檔案名稱為Startup.s。主要執行的操作為設定處理器頻率(PLL)、初始化RTC、設定記憶體參數、為bootloader的第二個階段準備申請ram並把第二階段的bootloader讀入到ram中,然後進入eboot中的c代碼的main函數中,這個階段一般被稱為N Boot,是機子運行起來時第一次軟體的啟動運行,這個階段一般都是通過讀寫寄存器以達到效果。須注意的是在該部分代碼雖然在形式上實現了諸多中斷向量,但是這些代碼根本上不會得到執行。而在後面會有一些其他手段用於實現中斷向量的功能。由於和hal複用該部分檔案,所以調用的函數名稱會與核心啟動函數的相同(如:KernelStart),但是實現內容卻是完全不同的。在該部分的最後還將儲存一個OEMAddressTable的地址指標到下一格函數,進行應有的記憶體影射。下面還是以2440bsp為例說明。根據windowsCE系統的要求,需要把將會操作到的記憶體空間影射到0x8000 0000後的512M空間中,其中低256M為帶緩衝的,高256M則是不帶緩衝的。不帶緩衝的地區通常是驅動訪問裝置必須的,這樣可以保障對硬體的操作不受到緩衝的幹擾。除了按照OEMAddressTable進行記憶體空間影射外,還可以要根據程式需求進行其他一系列影射,通常的做法都是將目前所有的裝置/記憶體在原地址空間上再影射一次,以方便使用。另外就是在將0x0位置影射到記憶體,這樣,就可以通過這個部分來進行中短向量的安裝了,以實現中斷服務程式。(以上記憶體影射並不是必須的,僅僅是為了方便程式的編寫而已,使用和系統相同的影射表可以使得不必重新另外建一套標頭檔,同時如果需要的話可以一直在記憶體中儲存eboot,這樣記憶體空間的規劃也會相對容易做一些)。
以上的這些工作做完,就進入windowsCE提供的eboot入口函數main了。而main函數的主要工作都是在BootloaderMain中進行,這個函數位於WINCE420\PUBLIC\COMMON\OAK\DRIVERS\ETHDBG\BLCOMMON\blcommon.c檔案中。該目錄的檔案就是微軟提供的eboot架構,儘管這不是實現的部分,也一併分析了吧。這部分的內容一開始就很有意思,第一個執行的語句如下
if (!KernelRelocate (pTOC)) { HALT (BLERR_KERNELRELOCATE); }
而這個傳入的參數卻這樣定義:ROMHDR * volatile const pTOC = (ROMHDR *)-1; 按照程式的內容來說,這個函數到這裡一定是死迴圈了,可是事實上這個死迴圈不會得到執行,也就是pTOC = (ROMHDR *)-1並沒有真正的起到作用。:) 在pTOC第一次使用前檢查了一下pTOC的值,結果如下:pTOC=0x8C04D694。也就是說pTOC在沒有被改變之前就已經不再是-1了,而且pTOC是被定義成const的,也沒有辦法去改變,看樣子就只能是編譯器的過程中這個指標就已經被動了手腳。而查看eboot.map中該地址所對應的內容居然是bootpart.obj的內容。感覺是無從下手了,這樣子讓人太費解了。仔細比較eboot.exe和eboot.nb0後發現,eboot.exe通過romimage處理後長度增加了,而且結構上改變了許多,在原.eboot.exe後增加了一系列原來沒有內容,pTOC的內容就是屬於這部分內容中的一部分。由於牽涉到windowsCE的Image Chain結構,所以無法繼續往下分析,這部分的內容就先跳過。以後再回頭來看。
隨後在 BootloaderMain中對調試介面進行初始化,由OEMDebugInit完成這個函數的實現是由具體的硬體決定的通常來說為串口的初始化,在此以後就通過該調試介面進行調試資訊的發布。
然後在OEMPlatformInit()中對eboot所要用到的硬體資源進行初始化裝置,通常這些會包含:存放裝置(FLASH、硬碟等)、傳輸介面(乙太網路卡、USB-RNDIS、無線網卡、CF—LAN等等)、系統時鐘,為下面將會進行的os鏡像傳輸、os鏡像儲存、讀取等等一系列動作做好準備。
做好準備以後就可以調用OEMPreDownload ()來進行傳輸OS的準備了,在這個函數中通常會實現一系列功能,諸如:裝置的設定、存放裝置的格式化、網卡IP的指定、等等。windowsCE所支援的標準操作則只是兩個,一個是跳轉、一個是下載、分別對應下載OS鏡像和跳入OS的進入點,前面提到的那些功能都是自己的擴充實現。
下面我們分別來看這兩個標準操作的分支:首先是下載的分支,在下載的分支中首先通過OEMReadData來擷取在最先收到的標示位也就是被稱為魔法數的資料,用以比較確認該傳輸的內容是否為windowsCE的鏡像資料,隨後繼續進一步擷取將接收的資料的效驗和,待接收的鏡像的數量,鏡像起始地址、長度等資訊,有了這些個資訊,很自然地就是接收鏡像了,
隨後檢查資料的效驗和。下一個鏡像的資訊的接收,如此往複迴圈直至所有的鏡像資訊接收完畢。
簡而言之,bootloader流程如下:
Boot Loader按照WinCE啟動方式的不同可分為兩大類:一類是下載模式,一類是本地啟動模式。
下載模式的基本執行過程為:
重定位RAM---初始化調試連接埠---初始化平台基本裝置---列印使用者菜單---初始化網路參數---下載OS核心---啟動OS
以Eboot為例,啟動過程函數調用的順序和功能如下:
Startup( )-----------------初始化CPU、記憶體控制器等
KernelRelocate( )-------代碼重定位至RAM
OEMDebugInit( )-------初始化調試連接埠(一般為串口)
OEMPlatformInit( )----初始化板上裝置(初始化顯示、RTC、OAL與eboot共用參數、列印使用者菜單、網卡等)
OEMPreDownload( )---下載前準備(設定裝置名稱、初始化MAC/IP參數)
DownloadImage( )------下載映像檔案
OEMLaunch( )-----------啟動OS
一般來說,Eboot所涉及的檔案主要有:
Startup.s:包括以上提到的Startup( )函數,原始碼位於%WINCE\Platform\Common\Src\***...和%WINCE\Platform\***\Src\Bootloader\eboot目錄
Main.c: 包括以上提到的OEMDebugInit( )、OEMPlatform( )、OEMPreDownload( )、OEMLaunch( ),原始碼位於%WINCE\Platform\***\Src\Bootloader\eboot目錄
Blcommon.c:包括以上提到的KernelRelocate( )、DownloadImage( ),原始碼位於%WINCE\Public\Common\Oak\Drivers\Ethdbg\Blcommon目錄
Eboot下載的過程主要包括:
(1)裝置通過Bootme使開發機擷取裝置IP(DHCP或者指定IP);
(2)開發機通過TFTP協議下載映像到裝置上;
(3) 根據需求把映像燒寫到Flash中或直接從RAM中啟動OS
這裡附上一份文檔,是在《電腦工程》期刊看到的,很不錯。
WinCEBootloader的設計與實現.pdf