基于S3C2410A的WINCE下Stepldr程序移植详细分析


在SAMSUNG公司提供的S3C2440A的BSP中有一个Stepldr引导程序。现在我把它移植到S3C2410A上了,已经移植成功。需要修改的地方就是NAND FLASH驱动部分,因为S3C2410A的NAND FLASH寄存器和S3C2440A的NAND FLASH寄存器是有点不一样滴。相比较而言:S3C2440A的NAND FLASH的寄存器丰富一些。而S3C2410A的就比较少。不说废话了。说正文,先分析一下Stepldr.bib文件吧:

;
; Copyright (c) Microsoft Corporation.  All rights reserved.
;
;
; Use of this source code is subject to the terms of the Microsoft end-user
; license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
; If you did not accept the terms of the EULA, you are not authorized to use
; this source code. For a copy of the EULA, please see the LICENSE.RTF on your
; install media.
;
; NOTE: The Steppingstone loader can only be 4096 bytes in length max.  Romimage
;       will need to create and page-align the .pdata section and the linker generates 
;       a 1-page header on the file.  In this .bib file we'll call the size 0x3000, 
;       but we'll post-process the .nb0 file to remove the .pdata section and the header.
;
; NOTE: The Steppingstone loader and the IPL are concatenated and stored in the
;       first two SmartMedia NAND flash blocks.  If the size of either loader is
;       altered in the .bib file, the bootloader code will need to be updated as
;       it makes an assumption about the first two NAND flash blocks being reserved.
;

MEMORY
;   Name      Start     Size      Type
;   -------   --------  --------  ----
    STEPLDR   00000000  00003000  RAMIMAGE
    STACK     33ff5800  00001000  RESERVED
    RAM       33ff0000  00001000  RAM

 

CONFIG
 COMPRESSION=ON
 PROFILE=OFF
 KERNELFIXUPS=ON
    
 ROMSTART=00000000
 ROMWIDTH=32
 ROMSIZE=00001000

 

MODULES
;   Name        Path                                                               Memory Type
;   ----------  --------------------------------------------------------------     -----------
    nk.exe      $(_TARGETPLATROOT)/target/$(_TGTCPU)/$(WINCEDEBUG)/stepldr.exe     STEPLDR

红色部分请注意:由于S3C2410A的芯片的特性,在NAND FLASH作为启动模式时,芯片会自动把NAND FLASH的最开始的4K程序映射到内部的4K SRAM中。同时又由于PB5.0这个软件不能编译小于4K的程序[好像是小于4K时,会有点小问题],解决办法就是将ROMSIZE设置为4K。STEPLDR的RAMIMAGE设置为12K。这样的话,就会产生stepldr.nb0,stepldr.nb1,stepldr.nb2共三个文件。我们只需要烧录stepldr.nb1就可以了。用什么烧录呢。当然是SJF2410A这个JTAG烧录工具啦。嘿嘿。相信大家都会有这个工具吧。没有还学什么ARM呢。。

堆栈的起始地位为:0x33FF5800 大小为:1K的保留区域,不能作为其它用途。

下一篇将详细分析Stepldr如何移植到S3C2410A中,主要是分析汇编代码部分。见 http://www.linuxidc.com/Linux/2012-02/54651p2.htm

前面分析STEPLDR.BIB文件(见 http://www.linuxidc.com/Linux/2012-02/54651.htm),现在分析的是NAND FLASH驱动部分。至于startup.s文件,主要是进行初始化:看门狗。配置MPLL和UPLL以及待机和休眠。还有的就是上电,还是复位等,在移植到STEPLDR到S3C2410A的时候需要修改的地方就是NAND FLASH驱动部分,代码如下:

; NAND code...
;
A410_BASE_ADDR EQU 0x2000000

 MACRO
 LDR4STR1 $src,$tmp1,$tmp2 
 ldrb $tmp1,[$src]
 ldrb $tmp2,[$src]
 orr $tmp1,$tmp1,$tmp2,LSL #8
 ldrb $tmp2,[$src]
 orr $tmp1,$tmp1,$tmp2,LSL #16
 ldrb $tmp2,[$src]
 orr $tmp1,$tmp1,$tmp2,LSL #24
 MEND

 EXPORT __RdPage512
__RdPage512
 ;input:a1(r0)=pPage
 stmfd sp!, {r1-r11}

 ldr r1, =0x4E00000C  ;NFDATA
 mov r2, #0x200

 LDR4STR1 r1, r4, r3
 LDR4STR1 r1, r5, r3
 LDR4STR1 r1, r6, r3
 LDR4STR1 r1, r7, r3
 LDR4STR1 r1, r8, r3
 LDR4STR1 r1, r9, r3
 LDR4STR1 r1, r10,r3
 LDR4STR1 r1, r11,r3
 stmia r0!, {r4-r11}
 subs r2, r2, #32
 bne %B1

 ldmfd sp!, {r1-r11}
 mov pc, lr

这段代码是已经修改过的在S3C2410A可以正常运行的CODE。直接复制到S3C2440A的Stepldr下的startup.s覆盖这段代码即可。这是因为S3C2410A的寄存器和S3C2440A的寄存器不一样引起的问题。上面这段代码是直接可以用滴。

下面来移植S3C2410A的NAND FLASH的STEPLDR驱动吧:

#define NF_CMD(cmd)    {rNFCMD=cmd;}
#define NF_ADDR(addr)   {rNFADDR=addr;} 

// for S3C2410aNAND
//  For flash chip that is bigger than 32 MB, we need to have 4 step address
#define NEED_EXT_ADDR               1

#define NF_nFCE_L()    {rNFCONF &= ~(1<<11);}
#define NF_nFCE_H()    {rNFCONF |=  (1<<11);}
#define NF_RSTECC()    {rNFCONF |=  (1<<12);}

#define NF_MECC_UnLock()  {do{}while( 0 );}
#define NF_MECC_Lock()   {do{}while( 0 );}

#define NF_CLEAR_RB()   {rNFSTAT |=  (1 << 2);}
#define NF_DETECT_RB()   {while(!(rNFSTAT&(1<<0)));}
#define NF_WAITRB()       {while(!(rNFSTAT&(1<<0)));}


#define NF_RDDATA()    (rNFDATA)
#define NF_WRDATA(data)   {rNFDATA=data;}

#define NF_ECC()         (rNFECC)

#define ID_K9S1208V0M   0xEC76

// HCLK=133Mhz
#define TACLS  7 
#define TWRPH0  7
#define TWRPH1  7

typedef union _ECCRegVal
{
 DWORD dwECCVal;
 BYTE bECCBuf[4];
} ECCRegVal;


void __RdPage512(BYTE *bufPt);


int NF_ReadPage(UINT32 block,UINT32 page,UINT8 *buffer)
{
    volatile int i;
    register UINT8 * bufPt=buffer;
    unsigned int blockPage;
// ULONG MECC;
    BYTE   ecc0,ecc1,ecc2;
    ECCRegVal eccRegVal;
 

    blockPage=(block<<5)+page;

    NF_RSTECC();    // Initialize ECC
    
    NF_nFCE_L();    
    NF_CMD(0x00);   // Read command
    NF_ADDR(0);     // Column = 0
    NF_ADDR(blockPage&0xff);     //
    NF_ADDR((blockPage>>8)&0xff);   // Block & Page num.
    NF_ADDR((blockPage>>16)&0xff);  //

    for(i=0 ; i<50 ; i++); //wait tWB(100ns)
    
    NF_WAITRB();    // Wait tR(max 12us)

    __RdPage512(bufPt);

 eccRegVal.dwECCVal = NF_ECC();
 
 // Skip first 8 bytes
 for(i=0; i<8; i++)
 {
  ecc0 = NF_RDDATA(); //必须保留读取8个字节,这里是OEM配置用途
 }

 ecc0 = NF_RDDATA();
 ecc1 = NF_RDDATA();
 ecc2 = NF_RDDATA();  
 
 NF_nFCE_H();

 if( ecc0 != eccRegVal.bECCBuf[0] ||
  ecc0 != eccRegVal.bECCBuf[0] ||
  ecc0 != eccRegVal.bECCBuf[0] ) {
 // Uart_SendString("ECC mismatch for Sector: ");
 // Uart_SendDWORD(blockPage, TRUE);
 }

 return 1;

} //由于NAND FLASH在生产时,必须确保BLOCK0是OK滴。同时在引导时,是不需要校验ECC。因此。不做ECC校验。


void NF_Reset(void)
{
    volatile int i;
   
    NF_nFCE_L();

    NF_CMD(0xFF);              // reset command.

    for(i=0 ; i<10 ; i++);     // tWB = 100ns.

    NF_WAITRB();               // wait 200~500us.
     
    NF_nFCE_H();
}


void NF_Init(void)
{

    rNFCONF =  (1  << 15) | /* Enable/Disable      */ 
    (1   << 14) | /* Page Size : 512Bytes      */
    (1   << 13) | /* 4 Step Address        */
    (1   << 12) | /* Initialize ECC        */
    (1   << 11) | /* nFCE control nFCE = HIGH     */
    (TACLS  <<  8) | /* CLE & ALE = HCLK * (TACLS + 1)   */
    (TWRPH0 <<  4) | /* TWRPH0    = HCLK * (TWRPH0 + 1)   */
    (TWRPH1 <<  0);
    NF_Reset();
}

上面这段代码是直接可以在S3C2410A的stepldr中用滴。已经在我的开发板上实现了滴。

#include <windows.h>
#include <pehdr.h>
#include <romldr.h>
#include "option.h"
#include "s2410addr.h"

// Constants.
//
#define LED_ON                 0xA
#define LED_OFF                 0x0

#define NAND_BLOCK_SIZE_BYTES   0x00004000
#define NAND_PAGE_SIZE_BYTES    0x00000200
#define NAND_PAGES_PER_BLOCK    (NAND_BLOCK_SIZE_BYTES / NAND_PAGE_SIZE_BYTES)

    // 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.
#define NAND_COPY_PAGE_OFFSET   2*NAND_PAGES_PER_BLOCK

#define LOAD_ADDRESS_PHYSICAL   0x30038000
#define LOAD_SIZE_BYTES         0x00040000
#define LOAD_SIZE_PAGES         (LOAD_SIZE_BYTES / NAND_PAGE_SIZE_BYTES)

#define SIGN_ON "/nWinCE nBoot v1.00 " __DATE__ " " __TIME__ "/r/n"

// Globals variables.
//
ROMHDR * volatile const pTOC = (ROMHDR *)-1;

// Function prototypes.
//
void MMU_EnableICache(void);
void Led_Display(int);
void Port_Init(void);
void ChangeClockDivider(int hdivn, int pdivn);
void ChangeMPllValue(int mdiv, int pdiv, int sdiv);
void NF_Init(void);
int NF_ReadPage(UINT32 block, UINT32 page, volatile BYTE *buffer);

// 
typedef void (*PFN_IMAGE_LAUNCH)();

 

/*
    @func   BOOLEAN | SetupCopySection | Copies the IPL image's copy section data (initialized globals) to the correct fix-up location.  Once completed, the IPLs initialized globals are valid.
    @rdesc  TRUE == Success and FALSE == Failure.
    @comm
    @xref
*/
static BOOLEAN SetupCopySection(ROMHDR *const pTOC)
{
    // This code doesn't make use of global variables so there are no copy sections.  To reduce code size, this is a stub function...
    //
    return(TRUE);
}


/*
    @func   void | main | C entrypoint function for the Steppingstone loader.
    @rdesc  None.
    @comm    
    @xref   
*/
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();
    
    // Set up clock and PLL.
    //
    ChangeClockDivider(1, 1);       // 1:2:4.
    ChangeMPllValue(0x5C, 0x4, 0x0);  // Fin=12MHz FCLK=202.8MHz.


    // Set up all GPIO ports.
    //
    Port_Init();

    Uart_Init();
    Uart_SendString(SIGN_ON);

    // Initialize the NAND flash interface.
    //
    NF_Init();

    // Turn the LEDs off.
    //
    Led_Display(LED_OFF);

    // 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.
    
    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(0x9);    // 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;
    }

    // Turn the LEDs on.
    //
    Led_Display(LED_ON);
 
    // Jump to the image...
    //
    ((PFN_IMAGE_LAUNCH)(LOAD_ADDRESS_PHYSICAL))(); //跳转到EBOOT的起始地址,可以参考BOOT.BIB

}

本文只分析红色部分,其他部分,请大家自己分析了哦。。

#define NAND_BLOCK_SIZE_BYTES   0x00004000
#define NAND_PAGE_SIZE_BYTES    0x00000200
#define NAND_PAGES_PER_BLOCK    (NAND_BLOCK_SIZE_BYTES / NAND_PAGE_SIZE_BYTES)

    // 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.
#define NAND_COPY_PAGE_OFFSET   2*NAND_PAGES_PER_BLOCK

#define LOAD_ADDRESS_PHYSICAL   0x30038000
#define LOAD_SIZE_BYTES         0x00040000
#define LOAD_SIZE_PAGES         (LOAD_SIZE_BYTES / NAND_PAGE_SIZE_BYTES)

NAND FLASH的BLOCK0作为BOOT引导。由于NAND FLASH的特性,1BLOCK = 32PAGE = 32X512BYTE=16K。所以NAND_PAGE_SIZE_BYTES被定义为0x200=512。NAND_PAGES_PER_BLOCK的意思是每块有多少页。按着上面的公式算出为32页。NAND_COPY_PAGE_OFFSET=2*NAND_PAGE_PER_BLOCK,为什么要偏移64页呢。。这是因为TOC_BLOCK是被定义在BLOCK2,而NBOOT被定义在BLOCK1,所以需要偏移64页。

LOAD_SIZE_BYTES被定义为256K。这是因为在BOOT.BIB文件中定义滴,见下面的定义:

MEMORY
;   Name     Start     Size      Type
;   -------  --------  --------  ----
    ARGS     80020800  00000800  RESERVED
    BINFS    80021000  00005000  RESERVED
    RAM      80026000  00006000  RAM    
    STACK    8002c000  00004000  RESERVED
    EBOOT    80038000  00040000  RAMIMAGE

看到了吧LOAD_ADDRESS_PHYSICAL=0x30038000,而在Oemaddrtab_cfg.inc中有这样的定义:[红色部分]

;------------------------------------------------------------------------------
;
;  File:  Oemaddrtab_cfg.inc
;
;  This file is used to define g_oalAddressTable. This table is passed to
;  KernelStart to estabilish physical to virtual memory mapping. This table
;  is used also in IOMEM OAL module to map between physical and virtual
;  memory addresses via OALPAtoVA/OALVAtoPA functions.
;
;------------------------------------------------------------------------------

; Export Definition

        EXPORT  g_oalAddressTable[DATA]

;------------------------------------------------------------------------------
;
; TABLE FORMAT
;       cached address, physical address, size
;------------------------------------------------------------------------------

g_oalAddressTable

        DCD     0x80000000, 0x30000000, 64      ; 32 MB DRAM BANK 6
        DCD     0x84000000, 0x10000000, 32      ; nGCS2: PCMCIA/PCCARD
        DCD     0x86000000, 0x18000000, 32      ; 32 MB SROM(SRAM/ROM) BANK 3
        DCD     0x88000000, 0x20000000, 32      ; 32 MB SROM(SRAM/ROM) BANK 4
        DCD     0x8A000000, 0x28000000, 32      ; 32 MB SROM(SRAM/ROM) BANK 5
        DCD     0x8C000000, 0x08000000, 32      ; 32 MB SROM(SRAM/ROM) BANK 1

因此LOAD_ADDRESS_PHYSICAL=0x30038000和0x80038000是指向同一个地址滴。

下面的代码是从NAND FLASH中的BLOCK3开始读取256K的EBOOT程序:

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(0x9);    // 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;
    }

具体是怎样实现的,请自行分析了哦。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值