四极管:Windows CE stepldr源码----基于Windows CE 5.0 S3C2440 BSP

来源:互联网 发布:吃鸡辅助源码 编辑:程序博客网 时间:2024/06/10 19:28
 

一、nboot与stepldr:

国内很多人做WinCE都是使用Samsung的2410或者2440入门的,所以对nboot和eboot是最熟悉的。eboot是微软在WinCE里面提供的开放源代码的一个bootloader的框架,因为它默认的是使用ethernet从PC下载image而得名,使用该框架,根据自己的硬件做一些修改就可以直接拿来用了,那么nboot又是怎么回事呢?

 

之所以需要nboot(注:三星的后续产品中,nboot已经改名为stepldr,ldr是looder的缩写,step是stepstone的意思,这是三星系列CPU为解决nand启动而内置的一小块RAM),是和硬件紧密相关的。我们在设计硬件的时候,ROM部分可以只使用norflash,也可以使用1片小容量的norflash+大容量的nandflash,还可以只使用nandflash。第一种方案,可以不用bootloader,也可以只使用eboot;第二种方案,把eboot放到norflash中,image放在nandflash中,并将硬件设置为norflash启动模式,也不用nboot。只有第3种方案,才需要使用nboot,这是为什么呢?

 

我们知道nandflash本身不能运行程序,它里面的内容必须拷贝到RAM中才能运行,但是CPU上电后,RAM中是空的,谁来执行这个拷贝的工作呢?三星的解决方案,就是内置了一小块RAM(stepstone),然后从硬件上实现CPU上电后先读取nand flash最开始的一段代码到stepstone中去(当然,要设置硬件为nandflash启动方式),然后从stepstone起始处(被设置为RAM的0地址)去执行。这个stepstone一般很小(2410,2440是4K),所以它没办法放下一个功能复杂的bootloader(比如eboot),只能放一个功能很简单的,这就是需要nboot的原因了。nboot的功能十分单一,就是从nandflash复制image到RAM中去,然后跳转执行。这里的image可以是eboot的(一般开发阶段这样做),也可以是OS的。

 

优龙的开发板提供了一种叫做BIOS的bootloader,它远远超出了4K的限制,但是还可以在nandflash启动方式下正常运行,这是为什么呢?原来,它实现了2次加载,也就是说CPU上电后自动加载了4K代码,这4K代码又将整个bootloader重新拷贝到RAM中再执行,要实现这样的功能要对链接器做一些设置,使“拷贝”功能的代码必须放到前4K里面去。

 

(以上stepldr的描述摘自:http://www.cnblogs.com/yashi88/archive/2010/02/11/1667548.html)

 

S3C2440的DATESHEET中描述如下:

目前的NOR Flash 存储器价格较高,相对而言SDRAM 和NAND Flash 存储器更经济,这样促使了一些用户在NAND Flash 中执行引导代码,在SDRAM 中执行主代码。
S3C2440A引导代码可以在外部NAND Flash 存储器上执行。为了支持NAND Flash 的BootLoader,S3C2440A配备了一个内置的SRAM 缓冲器,叫做“Steppingstone”。引导启动时,NAND Flash 存储器的开始4K 字节将被加载到Steppingstone 中并且执行加载到Steppingstone 的引导代码。
通常引导代码会复制NAND Flash 的内容到SDRAM 中。通过使用硬件ECC,有效地检查NAND Flash 数据。在复制完成的基础上,将在SDRAM 中执行主程序。

当自动引导启动期间,ECC 不会去检测,所以,NAND Flash 的开始4KB 不应当包含位相关的错误。

二、Windows CE 5.0的启动过程:

stepldr----eboot----nk,CPU上电后先读取nand flash最开始的一段代码(stepldr)拷贝到S3C2440配备的名为“stepping stone”的SRAM中,然后从stepstone起始处(被设置为RAM的0地址)去执行。stepldr的功能十分单一,就是从nandflash复制eboot的image到RAM中去,然后跳转执行eboot。而eboot执行它的功能代码后跳转到OS的启动代码。

 

三、stepldr代码分析:

stepldr的代码位于{$BSP} /Src/Bootloader/Stepldr目录下。

先看sources文件的如下内容:

TARGETNAME=stepldr

TARGETTYPE=PROGRAM

RELEASETYPE=PLATFORM

EXEENTRY=StartUp

NOMIPS16CODE=1

 

从EXEENTRY=StartUp可知StartUp为入口函数。它的实现代码在/Src/Bootloader/Stepldr/startup.s中:

    STARTUPTEXT

    LEAF_ENTRY StartUp

   

    b     ResetHandler 

    b     .

    b     .

    b     .            

    b     .            

    b     .            

    b     .                   

b     .

 

STARTUPTEXT和LEAF_ENTRY:

这是两个宏,在Kxarm.h中有其定义。说实话,这汇编代码我对着指令手册也看不太懂。

 

STARTUPTEXT大概是指定一个段(CODE表示这个段式代码段),名称为.astart,2字节对齐。字符串变量AreaName的值为"|.astart|"。

       MACRO

       STARTUPTEXT

       AREA |.astart|,ALIGN=2,CODE

AreaName SETS "|.astart|"

       MEND

 

LEAF_ENTRY大概是赋值FuncName,PrologName,FuncEndName几个字符串变量,指定2字节对齐,导出FuncName,,然后$ FuncName的有效范围结束。VBar是一个全局变量,可是VBar:CC:"$Name":CC:VBar是什么意思啊?

       MACRO

       LEAF_ENTRY       $Name

FuncName SETS    VBar:CC:"$Name":CC:VBar

PrologName SETS "Invalid Prolog"

FuncEndName SETS    VBar:CC:"$Name":CC:"_end":CC:VBar

       ALIGN    2

       EXPORT $FuncName

$FuncName

       ROUT

       MEND

 

网上别人都说这就开始了StartUp,就先按这个理解,接着往下看吧。

b     ResetHandler

跳转到ResetHandler执行,其代码如下:

……

ResetHandler

 

    ldr          r0, =WTCON       ; disable the watchdog timer.

    ldr          r1, =0x0        

    str          r1, [r0]

 

    ldr          r0, =INTMSK      ; mask all first-level interrupts.

    ldr          r1, =0xffffffff

    str          r1, [r0]

 

    ldr          r0, =INTSUBMSK   ; mask all second-level interrupts.

    ldr          r1, =0x7fff

    str          r1, [r0]

 

 

    ldr   r0, = INTMOD

    mov       r1, #0x0          ; set all interrupt as IRQ (not FIQ)

    str   r1, [r0]

 

    ; CLKDIVN

    ldr   r0,=CLKDIVN

    ldr   r1,=0x5     ; 0x0 = 1:1:1  ,  0x1 = 1:1:2 , 0x2 = 1:2:2  ,  0x3 = 1:2:4,  0x4 = 1:4:4,  0x5 = 1:4:8, 0x6 = 1:3:3, 0x7 = 1:3:6

    str   r1,[r0]

 

       ldr   r1, =MISCCR                   ; MISCCR's Bit [22:20] -> 100

       ldr          r0, [r1]

       bic          r0, r0, #(7 << 20)

       orr          r0, r0, #(4 << 20)

       str          r0, [r1]

 

    ; MMU_SetAsyncBusMode FCLK:HCLK= 1:2

    ands       r1, r1, #0xe

    beq        %F5

    bl            MMU_SetAsyncBusMode

 

    

5

 

; TODO: to reduce PLL lock time, adjust the LOCKTIME register.

    ldr          r0, =LOCKTIME

    ldr          r1, =0xffffff

    str          r1, [r0]

 

    ; Configure the clock PLL.

    ;     

      [ {TRUE}

      

       ldr          r0, =UPLLCON         

    ldr          r1, =((26<<12)+(0x4<<4)+0x1)  ; Fin=16MHz, Fout=48MHz.    ;//c ksk 20051111

    str          r1, [r0]

 

       nop

       nop

       nop

       nop

       nop

       nop

       nop

       nop

 

       ldr          r0, =MPLLCON         

    ldr          r1, =((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)  ; Fin=16.9344MHz, Fout=399.58MHz

    str          r1, [r0]

 

    mov     r0, #0x2000

10  

    subs    r0, r0, #1

    bne     %B10

       ]

 

    ; Are we waking up from a suspended state?

    ;

    ldr          r1, =GSTATUS2

    ldr          r0, [r1]

    tst           r0, #0x2

    ; Yes?  Then go to the resume handler code...

    bne         WAKEUP_POWER_OFF

 

    ; Set up the memory control registers.

    ;

    add     r0, pc, #SMRDATA - (. + 8)

    ldr          r1, =BWSCON            ; BWSCON Address.

    add         r2, r0, #52           ; End address of SMRDATA.

15      

    ldr          r3, [r0], #4   

    str          r3, [r1], #4   

    cmp        r2, r0            

    bne         %B15

 

 

 

  ; LED_ON (0x1<<7)

    ; If this is a cold boot or a warm reset, clear RAM because the RAM filesystem may be

    ; bad.  If this is a software reboot (triggered by the watchdog timer), don't clear RAM.

    ;

    ldr          r1, =GSTATUS2   ; Determine why we're in the startup code.

    ldr          r10, [r1]       ;

    str         r10, [r1]       ; Clear GPSTATUS2.

    tst           r10, #0x4       ; Watchdog (software) reboot?  Skip code that clears RAM.

    bne         %F40

 

;;;;;;;;;

;NOTE

;;;;;;;;

;this code must run in the flash,not in the ram

    ; Clear RAM.

    ; Clear RAM.

    ;

    mov       r1,#0

    mov       r2,#0

    mov       r3,#0

    mov       r4,#0

    mov       r5,#0

    mov       r6,#0

    mov       r7,#0

    mov       r8,#0

      

    ldr          r0,=0x30000000   ; Start address (physical 0x3000.0000).

    ldr          r9,=0x04000000   ; 64MB of RAM.

20   

    stmia       r0!, {r1-r8}

    subs r9, r9, #32

    bne         %B20

;    ldr         r0,=0x30200000   ; Start address (physical 0x3000.0000).

;    ldr         r9,=0x00100000   ; 1MB of RAM.

;21  

;    stmia      r0!, {r1-r8}

;     subs     r9, r9, #32

;    bne        %B21

 

;    ldr         r0,=0x30038000   ; Start address (physical 0x3000.0000).

;    ldr         r9,=0x00004000   ; 256KB of RAM.

;22  

;    stmia      r0!, {r1-r8}

;     subs     r9, r9, #32

;    bne        %B22

 

    ; Initialize stacks.

    ;

30

    mrs         r0, cpsr

    bic          r0, r0, #MODEMASK|NOINT

    orr          r1, r0, #SVCMODE

    msr         cpsr_cxsf, r1           ; SVCMode.

    ldr          sp, =SVCStack

      

    ; Jump to main C routine.

    ;

       ;LED_ON (0x1<<8)

   

    bl            main

 

    ;//+ ksk 20060404  for s/w reset

40

;    ldr         r4, =0x22B784

;   ldr           r4, =0x200000

;   add          r4, r4, #0x30000000

;    mov              pc, r4

 

; *******  add by zwj **********

       ldr   r0, =GPADAT ;yz2440 powerdown operation

       ldr   r1, =0x0

       str   r1, [r0]

      

       ldr   r0, =GPACON

       ldr   r1, =0x0

       str   r1, [r0]

      

       mov        pc, r1

      

; *******  end  **********    

    b .

……

 

代码看得头很大,一直到

bl            main

这一句,表示跳转到main函数,好了,可以进入到熟悉的C代码中去了。实现代码在Main.c中。我添加的注释也在代码中,main函数大致的功能是:

1. Port_Init();// 端口初始化。

2. Uart_Init()函数来初始化串口,编译debug。

3. NF_Init()函数来初始化nand flash控制器。

4. ReadFlashID()来读取当前nand flash的ID。(前面3个还好理解,nand flash这部分现在还不懂,得找个时间专门学习一下nand flash后写个blog)

5. ((PFN_IMAGE_LAUNCH)(LOAD_ADDRESS_PHYSICAL))();跳转到0x30038000去执行,即eboot。

 

void main(void)

{

    register nBlock;

    register nPage;

    register nBadBlocks;

    volatile BYTE *pCopyPtr;

             

    // Set up copy section (initialized globals).

    //

    // NOTE: after this call, globals become valid.

    //

       SetupCopySection(pTOC);// 这是个空函数

 

    // Enable the ICache.

    //

    MMU_EnableICache();// 在Startup.s中实现

   

    // Set up clock and PLL.

    //

 

#if 0

    ChangeClockDivider(3, 1);          // 1:3:6.

    ChangeMPllValue(0x61, 0x1, 0x2);  // Fin=16MHz FCLK=296.352MHz.

// ChangeMPllValue(229, 0x5, 0x0);  // Fin=12Mhz

#endif

 

 

 

 

    // Set up all GPIO ports.

    //

     Port_Init();// 端口初始化

      

    // Turn the LEDs off.

    //

    //Led_Display(LED_ON);

      

    Uart_Init();//串口初始化,以后就可以使用串口打印了

       Uart_SendString("Step ldr/r/n");

 

    // Initialize the NAND flash interface.

    //

    NF_Init();//NandFlash初始化

      

 

       // Copy image from NAND flash to RAM.

    //

    pCopyPtr = (BYTE *)LOAD_ADDRESS_PHYSICAL;

 

    // NOTE: we assume that this Steppingstone loader occupies *part* the first (good) NAND flash block.  More

    // specifically, the loader takes up 4096 bytes (or 8 NAND pages) of the first block.  We'll start our image

    // copy on the very next page.

 

       //  读nandflash的ID

    if (NF_ReadID() != TRUE)

       {

              Uart_SendString("This NandFlash Type is not supported!!/r/n Booting is failure /r/n");

              while(1)

              {

              }

       }

   

    nBadBlocks = 0;

    for (nPage = NAND_COPY_PAGE_OFFSET ; nPage < (LOAD_SIZE_PAGES + NAND_COPY_PAGE_OFFSET) ; nPage++)

    {

        nBlock = ((nPage / NAND_PAGES_PER_BLOCK) + nBadBlocks);

 

        if (!NF_ReadPage(nBlock, (nPage % NAND_PAGES_PER_BLOCK), pCopyPtr))

        {

            if ((nPage % NAND_PAGES_PER_BLOCK) != 0)

            {

              //  Led_Display(0x1E8);    // real ECC Error.

 

                // Spin forever...

                while(1)

                {

                }

            }

 

            // ECC error on a block boundary is (likely) a bad block - retry the page 0 read on the next block.

            nBadBlocks++;

            nPage--;

            continue;

        }

 

        pCopyPtr += NAND_PAGE_SIZE_BYTES;

    }

 

       Uart_SendString("here");

    // Jump to the image...

    //

    ((PFN_IMAGE_LAUNCH)(LOAD_ADDRESS_PHYSICAL))();

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 一个月的宝宝睡眠不好怎么办 被商场要求撤场怎么办 上班没法接孩子放学怎么办 幼儿下午放学与上班错开怎么办 宝宝早上醒的早怎么办 晚卜睡不着尿多怎么办 要求正常休息公司不准怎么办 我早起被室友说怎么办? 小孩晚上睡的晚怎么办 初中一年级学不扎实怎么办 一年级学生上课爱说话怎么办 孩子不按时完成作业怎么办 高三理科基础不好怎么办 字写快了就难看怎么办 高一文科280分怎么办 高三了学不进去怎么办 副职兼任法人不够条件怎么办 正职和上级不和副职怎么办 中层正职和上级不和副职怎么办 陆军军官年龄大了怎么办 ps选区选多了怎么办 香港货物被海关扣了怎么办 羽绒服棉填充物不均匀了怎么办 蛀牙到牙神经了怎么办 t恤袖子长了怎么办 t恤袖子短了怎么办 ofo突然要交押金余款怎么办 裙子的腰小了怎么办 白衬衣棉质变软怎么办? 车被自行车刮了怎么办 刮花别人的车门怎么办 破腹产九个月意外怀孕怎么办 破腹产一年半意外怀孕怎么办 37天流产了该怎么办 旧鞋穿着磨脚了怎么办 皮鞋磨脚怎么办小窍门 拉链从下面开了怎么办 高帮足球鞋松了怎么办 橡筋裤头太紧了怎么办 内增高鞋跟太高怎么办 电脑增高架高了怎么办