i.MX21平台上Startup.s代码的分析

i.MX21平台上Startup.s代码的分析

      在嵌入式系统中,Boot Loader是系统运行必不可少的前提。在特定的硬件平台上运行Windows CE最困难的工作之一就是让Boot Loader正常启动这个硬件平台。 Boot Loader从代码层面上来说由OEM启动代码(OEM startup code)和主代码(main code)两部分组成。 其中, OEM启动代码是Boot Loader的入口点,是目标平台上电后最先执行的部分。一般是对处理器内核进行配置和初始化,为后面的引导程序作准备。这类代码直接面向处理器进行编程,一般用汇编语言实现。通用的内容包括:(1)设置中断向量表;(2)初始化存储器系统;(3)初始化堆栈;(4)初始化调试端口和设备;(5)初始化C语言环境;(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()---这部分代码是EbootOAL共享的。

 

    mov     r0, #(SVCMode:OR:IRQDisable:OR:FIQDisable)

    msr     cpsr_c, r0

//在板子上电后,第一步是将处理器设置为特权模式

 

bl      MMUCacheDisable

//跳转到MMUCacheDisable( ),使TLBcache、写缓冲无效,并关闭 MMUcache

 

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

//跳转到OALIsImageInRAMOALSetUpExtMemories以初始化外部存储设备。

 

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

//先后跳转到OALSetUpGpioOALSetUpKeypad,即初始化系统GPIO和键盘设备。最后程序转到OALStartUp(),执行代码重定位和从RAM中启动Eboot功能。

 

上面提到的OALSetUpSystemControl OALSetUpFrequenciesOALSetUpExtMemoriesOALSetUpGpioOALSetUpKeypad这几个函数位于 %WINCE\PLATFORM \iMX21\ Imx21ads\Src\Kernel\Oal\oal_startup.c中;OALIsImageInRAM()和OALStartUp()则位于%WINCE\PLATFORM\Imx21ads\Src\Kernel\Oal\startup.s中。

 

2MMUSetup()---这个函数将被%Eboot\startup.s调用,它根据OEMAddressTable设置MMU,并使能MMU、启用cache

 

(二)%WINCE\PLATFORM\Imx21ads\Src\Kernel\Oal\startup.s

功能:OEM板级初始化

这部分代码首先定义了flashRAM的物理地址和虚拟地址:

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

 

BSPAmdBurstCfg 44M ()---iMX21标准板的flash设置为burst模式 44M 频率

 

BSPAmdBurstCfg 66M ()---iMX21标准板的flash设置为burst模式 66M 频率

 

(三)%WINCE\PLATFORM\Imx21ads\Src\Bootloader\Eboot\startup.s

功能:调用了OALStartup.s(位于%WINCE\Platform\Common\Src\Arm\Freescale\MX21),将Eboot重定位至RAM中运行,并初始化MMU,使能MMUcache,引导启动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初始化。

你可能感兴趣的:(i.MX21平台上Startup.s代码的分析)