在嵌入式系統中,Boot Loader是系統運行必不可少的前提。在特定的硬件平臺上運行Windows CE最困難的工作之一就是讓Boot Loader正常啟動這個硬件平臺。 Boot Loader從代碼層面上來說由OEM啟動代碼(OEM startup code)和主代碼(main code)兩部分組成。 其中, OEM啟動代碼是Boot Loader的入口點,是目標平臺上電后最先執(zhí)行的部分。一般是對處理器內核進行配置和初始化,為后面的引導程序作準備。這類代碼直接面向處理器進行編程,一般用匯編語言實現。通用的內容包括:(1)設置中斷向量表;(2)初始化存儲器系統;(3)初始化堆棧;(4)初始化調試端口和設備;(5)初始化C語言環(huán)境;(6)轉到主代碼main. c。
下面以i.MX21平臺上的啟動代碼文件Startup.s為例進行分析.
(一) %WINCE\PLATFORM\COMMON\SRC\ARM\Freescale\MX21\Startup\startup.s
WinCE_MX21_BSP用戶手冊里提到的OAL層源代碼,用于在OEM板級初始化前先初始化MX21處理器的核心模塊。
主要的函數代碼解讀如下:
1. StartUp()---這部分代碼是Eboot和OAL共享的。
mov r0, #(SVCMode:OR:IRQDisable:OR:FIQDisable)
msr cpsr_c, r0
//在板子上電后,第一步是將處理器設置為特權模式
bl MMUCacheDisable
//跳轉到MMUCacheDisable( ),使TLB和cache、寫緩沖無效,并關閉 MMU、cache。
ldr r1, =CSP_BASE_REG_PA_AIPI1
ldr r0, =0x00040304
……
str r0, [r1, #AIPI_PAR_OFFSET]
//設置AIPI寄存器
bl OALSetUpSystemControl
bl OALSetUpFrequencies
//跳轉到OALSetUpSystemControl 和OALSetUpFrequencies,初始化系統控制模式和時鐘頻率。
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #0x00001000
mcr p15, 0, r0, c1, c0, 0
//啟用I Cache
bl OALIsImageInRAM
bl OALSetUpExtMemories
//跳轉到OALIsImageInRAM、OALSetUpExtMemories以初始化外部存儲設備。
ldr r1, =CSP_BASE_REG_PA_MAX
ldr r0, =0x77123045
str r0, [r1, #MAX_MPR0_OFFSET]
……
str r0, [r1, #AITC_NIPRIORITY0_OFFSET]
//設置MAX寄存器、配置AITC中斷控制器、屏蔽和清中斷的一段代碼。
bl OALSetUpGpio
bl OALSetUpKeypad
b OALStartUp
//先后跳轉到OALSetUpGpio、OALSetUpKeypad,即初始化系統GPIO和鍵盤設備。最后程序轉到OALStartUp(),執(zhí)行代碼重定位和從RAM中啟動Eboot功能。
上面提到的OALSetUpSystemControl 、OALSetUpFrequencies、OALSetUpExtMemories、OALSetUpGpio、OALSetUpKeypad這幾個函數位于 %WINCE\PLATFORM \iMX21\ Imx21ads\Src\Kernel\Oal\oal_startup.c中;OALIsImageInRAM()和OALStartUp()則位于%WINCE\PLATFORM\Imx21ads\Src\Kernel\Oal\startup.s中。
2.MMUSetup()---這個函數將被%Eboot\startup.s調用,它根據OEMAddressTable設置MMU,并使能MMU、啟用cache。
(二)%WINCE\PLATFORM\Imx21ads\Src\Kernel\Oal\startup.s
功能:OEM板級初始化
這部分代碼首先定義了flash、RAM的物理地址和虛擬地址:
FlashPABase EQU CSP_BASE_MEM_PA_CS0
FlashVABase EQU 0x80000000
RamPABase EQU CSP_BASE_MEM_PA_CSD0
RamVABase EQU 0x88000000
RamMaxSize EQU 0x04000000 ; 64M
接下來的代碼可以分成四個函數:
OALStartUp()
adr r0, g_oalAddressTable
b KernelStart
//加載OEMAddressTable地址,跳轉到KernelStart()
OALIsImageInRAM()---檢查Image是否正跑在RAM里
BSPAmdBurstCfg44M()---將iMX21標準板的flash設置為burst模式44M頻率
BSPAmdBurstCfg66M()---將iMX21標準板的flash設置為burst模式66M頻率
(三)%WINCE\PLATFORM\Imx21ads\Src\Bootloader\Eboot\startup.s
功能:調用了OAL的Startup.s(位于%WINCE\Platform\Common\Src\Arm\Freescale\MX21),將Eboot重定位至RAM中運行,并初始化MMU,使能MMU、cache,引導啟動CE內核等。
基本流程:
首先給出了一系列宏定義,比如Eboot的大小和地址信息:
EbootRamOffset EQU 0x00010000
EbootImageSize EQU 0x00040000
EbootFlashPAStart EQU (FlashPABase)
EbootFlashVAStart EQU (FlashVABase)
EbootRamPAStart EQU (RamPABase + EbootRamOffset)
EbootRamVAStart EQU (RamVABase + EbootRamOffset)
//這里的信息是和eboot.bib相對應的,要對照著改動。
MmuPageTableOffset EQU 0x00001000
MmuPageTableBase EQU (RamPABase + MmuPageTableOffset)
//MMU頁表在RAM中的物理地址和大小
StackEndOffset EQU 0x00070000
StackEndVA EQU (RamVABase + StackEndOffset)
//棧尾的偏移地址和虛擬地址
接著進入KernelStart()函數,先跳轉到OALIsImageInRAM程序段判斷Image是否正跑在RAM里。
bl OALIsImageInRAM
cmp r0, #1
beq RamStart
//如果已經在RAM里,則跳轉到RamStart程序段
如果不是,則在接下來的RelocateEBOOT程序段里進行代碼重定位:
ldr r1, =FlashPABase
ldr r0, =EbootRamPAStart
ldr r2, =(EbootImageSize/16)
ldmia r1!, {r3-r6}
stmia r0!, {r3-r6}
subs r2, r2, #1
bne %b10
adr r2, RamStart
ldr r3, =(FlashPABase)
sub r3, r2, r3
ldr r4, =(EbootRamPAStart)
add r2, r4, r3
bx r2
RamStart段代碼如下:
adr r2, MMUSetupDone
ldr r3, =(EbootRamPAStart)
sub r2, r2, r3
ldr r3, =(EbootRamVAStart)
add r2, r2, r3
mov lr, r2
//設置連接寄存器LR
adrl r0, g_oalAddressTable
//加載OEMAddressTable和頁表的地址
ldr r1, =(MmuPageTableBase)
//加載頁表的地址
b MMUSetup
nop
nop
nop
nop
nop
//跳轉到OAL層核心源代碼的MMUSetup函數,使能MMU、設置虛擬內存模式,并通過g_oalAddressTable初始化MMU頁表
MMUSetupDone
ldr sp, =(StackEndVA-4)
//MMU配置完成,使棧指針處于虛擬內存中
b BootloaderMain
//跳轉到% blcommon.c中的BootloaderMain()
最后的Launch()代碼段是由EBOOT啟動函數OEMLaunch( )所調用的,用來關閉MMU,跳轉到CE內核。
mov r1, #0
mcr p15, 0, r1, c7, c7, 0 // 初始化I, D cache
mcr p15, 0, r1, c7, c10, 4 // 初始化write buffer
mcr p15, 0, r1, c8, c7, 0 // 設置TLB無效
mov r1, #0x0078
mcr p15, 0, r1, c1, c0, 0 // Disable MMU, caches 和 write buffer
mov pc, r0 // 跳轉到 PhysicalStart
nop
nop
nop
nop
一般認為%WINCE\PLATFORM\COMMON\SRC\ARM\Freescale\MX21\Startup\startup.s里的Startup( )是i.MX21標準板Eboot的第一個函數,上電后首先完成系統CPU初始化。