基於ARM的Windows CE核心啟動分析1
1.startup.s2
2.KernelStart2
2.1 ARMInit()3
2.1.1 OALIntrInit3
2.1.2 OALTimerInit4
2.1.2.1 Variable Tick Scheduler4
2.2 KernelInit()4
2.3 FirstSchedule5
1.startup.s
核心進入點startup.S,核心從這裡啟動.因為核心經過bootloader載入,內 核運行時候,已經由bootloader完成了硬體的基本初始化(關閉watchdog, pll設定等等)所以,startup.S的任務比較簡單,只是將oemaddrtab_cfg.inc裡面的g_oalAddressTable數組地 址作為參數,傳遞給KernelStart,這個數組用來描述和實現物理地址到虛擬位址的映射.
(. + 8)是流水線處理.KernelStart()位於
PRIVATE/WINCEOS/COREOS/NK/KERNEL/ARM/armtrap.s
2.KernelStart
ARMInit()位於本目錄的mdram.c檔案.
KernelInit()位於PRIVATE/WINCEOS/COREOS/NK/KERNEL/kwin32.c中.
FirstSchedule()位於armtrap.s的一個label.
主要關注ARMInit()和KernelInit(),前一個進行目標板的初始化,後一個負責核心的初始化.FirstSchdule()開始調度第一個程式.
2.1 ARMInit()
先看看ARMInit()它的幾個關鍵性動作如下:
KernelRelocate()是進行重定位.KernelFindMemory()是尋找系統可用記憶體,並分成應用記憶體和object store兩部分.這2個函數都已由MS自己實現.我們需要添加的函數是名字以OEM開頭的函數.
OEMInitDebugSerial()初始化一個調試口,我們一般使用一個串口來作為調 試口,這個函數需要自己實現,在 PLATFORM/SMDK2440A/Src/Kernel/Oal/debug.c中定義這個函數.比如可以將串口0設定為調試口,在這個函數中對串 口0進行初始化.
OEMInit()是一個比較重要的函數,
OALCacheGlobalsInit()在PLATFORM/COMMON/SRC/ARM/COMMON/CACHE/init.s中實現,這部分代碼以PQOAL的形式提供.
OALIntrInit()初始化中斷.
OALTimerInit()初始化定時器TIMER4,作為系統時鐘(tick),
configGPIO()初始化gpio口,設定相關寄存器.
InitDisplay()初始化LCD.有時候,我們希望在oal啟動和核心載入期間顯示一副等待圖片或者顯示LOGO,為達到這個目的,需要先初始化LCD.
OALKitlStart()準備啟動KITL.
此外,在ARMInit還會通過調試口列印一些基本資料,開始時候列印”Windows CE Kernel for ARM….”字樣, 中間列印處理器類型等等資訊.結束時候列印” ARMInit done.”
2.1.1 OALIntrInit
調用OALIntrMapInit()初始化2個數組g_oalSysIntr2Irq,g_oalIrq2SysIntr,這2個數組表徵irq和邏輯中斷SysIntr的映射關係.
然後初始化中斷寄存器,
最後,留一個介面給oem: BSPIntrInit(),如果oem需要在這個階段初始化一些中斷,可以定義這個函數並實現.
2.1.2 OALTimerInit
這個函數比較重要. 都知道所有WinCE系統都需要一個定時器來提供一個heartbeat,
g_oalTimer包含各種系統時鐘相關的變數.
curridlehigh, curridlelow,這2個32位的DWORD變數合起來實現一個64位的計數器,反映了系統處於空閑模式(Idle mode)的時間。一般在OEMIdle()函數內更新。使用者程式通過調用GetIdleTime()函數可以得到這個值。
初始化核心功能指標:pQueryPerformanceFrequency, pQueryPerformanceCounter.通過這兩個函數實現高精度的計時器. 這兩個函數的原型也已經由PQOAL實現.
初始化TIMER4作為系統時鐘.TIMER4是一個16bit的定時器.此函數將TIMER4設定成為自動轉載模式.
2.1.2.1 Variable Tick Scheduler
可變的系統時鐘節拍,這個是WinCE5.0中增加的新的效能.
每一次定時器中斷時候,核心分析所有線程後決定切換到哪個線程運行.假如所有線程都在等待狀 態,系統將進入idle狀態.在這個狀態的時候,任何中斷都會喚醒系統重新開始調度.一般系統大部分時間是處於idle狀態的,核心會調用 OEMIdle()進入idle狀態,我們已經知道這個狀態會被任何中斷喚醒. 在以前的版本中,系統中斷(即上面的TIMER4中斷)每毫秒產生一次,查看系統是否需要重新調度. 為了節電,不希望中斷那麼頻繁.於是WinCE5.0中,在調用OEMIdle()之前會先調用pOEMUpdateRescheduleTime(). 通過這個函數重新設定俠義次系統時鐘中斷的時間.
2.2 KernelInit()
再看看KernelInit()函數
不過多關注KernelInit().
2.3 FirstSchedule
位於armtrap.s的一個label.開始第一個線程調度.整個核心開始運行.