基本上吧Nboot的程序看完了,总结一下。

主要包含以下文件:

2410init.s  
2410slib.s  
nand_s.s  
 
2410loader.c  
2410lib.c  
nand.c 
2410init.s
2410slib.s
nand_s.s

2410loader.c
2410lib.c
nand.c

其中最重要的是2410init.s和2410loader.c。

2410init.s是汇编程序,所作的工作有:屏蔽所有中断、设置CPU的速度和时钟频率、RAM的初始化、LED的初始化等。

2410loader.c是C语言程序,下面着重介绍。

首先,入口程序main():

view plaincopy to clipboardprint?
void Main(void)  
{  
    DWORD err;  
   
    DWORD dwEntry = 0;        //定义入口方式,是直接进入WinCE内核,还是启动Eboot  
 
    MMU_EnableICache();         //MMU_Cache On  
 
    Uart_Init();            //初始化串口  
    Uart_SendString(SIGN_ON);            //打印启动信息  
 
    NF_Init();              //初始化Nand Flash  
 
    Uart_SendString("\ndwEntry is ");  
    Uart_SendDWORD(dwEntry, TRUE);  
 
    err = ReadImageFromNand(dwEntry,0); //读TOC信息、将Image写入内存等  
 
    if (ERR_SUCCESS == err) {  
        Uart_SendString("\nDone!");  
        Uart_SendDWORD(JumpAddr, TRUE);  
         Launch(JumpAddr);      //执行指定地址的程序(RAM中,物理地址)  
        err = ERR_JUMP_FAILED;  
    }  
 
    Uart_SendString("\nBoot ERROR:");  
    Uart_SendDWORD(err, TRUE);  
    while (1);  

void Main(void)
{
    DWORD err;
 
    DWORD dwEntry = 0;        //定义入口方式,是直接进入WinCE内核,还是启动Eboot

    MMU_EnableICache();   //MMU_Cache On

    Uart_Init();   //初始化串口
    Uart_SendString(SIGN_ON);          //打印启动信息

    NF_Init();    //初始化Nand Flash

    Uart_SendString("\ndwEntry is ");
    Uart_SendDWORD(dwEntry, TRUE);

    err = ReadImageFromNand(dwEntry,0); //读TOC信息、将Image写入内存等

    if (ERR_SUCCESS == err) {
     Uart_SendString("\nDone!");
     Uart_SendDWORD(JumpAddr, TRUE);
         Launch(JumpAddr);  //执行指定地址的程序(RAM中,物理地址)
        err = ERR_JUMP_FAILED;
    }

    Uart_SendString("\nBoot ERROR:");
    Uart_SendDWORD(err, TRUE);
    while (1);
}

里面重要的有两个程序Uart_Init()和ReadImageFromNand()。

先来看Uart_Init():

view plaincopy to clipboardprint?
//***************************[ UART ]******************************  
void Uart_Init(void)  
{  
    int i;  
 
    rUFCON0 = 0x0;      // FIFO disable  
    rUMCON0 = 0x0;      // AFC disable  
 
    rULCON0 = 0x3;      // Normal,No parity,1 stop,8 bits  
    rUCON0  = 0x245;     
      
    rUBRDIV0=( (int)(PCLK/16./BAUD_RATE) -1 );  
 
    for(i=0;i<100;i++);  
      

//***************************[ UART ]******************************
void Uart_Init(void)
{
    int i;

    rUFCON0 = 0x0;      // FIFO disable
    rUMCON0 = 0x0;      // AFC disable

    rULCON0 = 0x3;      // Normal,No parity,1 stop,8 bits
    rUCON0  = 0x245;  
   
    rUBRDIV0=( (int)(PCLK/16./BAUD_RATE) -1 );

    for(i=0;i<100;i++);
   
}

注意其中的rUFCON0、rUMCON0等参数里的数字0,这代表初始化的是UART0端口,而所有的打印输出也是向UART0的,所以在计算机上用超级终端监控时,串口一定要接到UART0上。

接下来是最重要的ReadImageFromNand():

view plaincopy to clipboardprint?
DWORD  
ReadImageFromNand(DWORD dwEntry, DWORD dwSig)  
{  
    DWORD dwSectorsNeeded;  
    DWORD dwSector, dwLength;         // Start Sector & Length  
    DWORD dwRAM, i;  
 
    Uart_SendString("TOC_SECTOR: \n");  
    Uart_SendDWORD(TOC_SECTOR,TRUE);  
 
    //读TOC内容,确定拷贝Image所需空间、拷贝的起始地址、跳转位置等信息  
    if ( !FMD_ReadSector(TOC_SECTOR,(LPBYTE)&toc,NULL, 1) )  
    {  
        Uart_SendString("ERR_DISK_OP_FAIL1\n");  
        return ERR_DISK_OP_FAIL1;  
    }  
 
    //验证TOC是否合法  
    if ( !VALID_TOC(&toc) ) {  
        Uart_SendString("ERR_INVALID_TOC: ");  
        Uart_SendDWORD(toc.dwSignature, TRUE);  
        return ERR_INVALID_TOC;  
    }  
 
    //拷贝到RAM的Image所占的Page  
    dwSectorsNeeded = toc.id[dwEntry].dwTtlSectors;  
      
    Uart_SendString("Sector addr on NAND: ");  
    Uart_SendDWORD(toc.id[dwEntry].sgList[0].dwSector, TRUE);  
    Uart_SendString("TotalSector: ");  
    Uart_SendDWORD(dwSectorsNeeded, TRUE);  
 
    //dwRAM:拷贝Image到RAM的起始地址  
    //JumpAddr:拷贝完成后的执行程序地址  
    dwRAM = VIRTUAL_TO_PHYSICAL(toc.id[dwEntry].dwLoadAddress);  
    JumpAddr = VIRTUAL_TO_PHYSICAL(toc.id[dwEntry].dwJumpAddress);  
 
    // 将Image拷贝到RAM中  
    i = 0;  
    while (dwSectorsNeeded && i < MAX_SG_SECTORS)  
    {  
        dwSector = toc.id[dwEntry].sgList[i].dwSector;  
        dwLength = toc.id[dwEntry].sgList[i].dwLength;  
        // read each sg segment  
        while (dwLength) {  
 
            if ( !FMD_ReadSector(dwSector,  
                                (LPBYTE)dwRAM,  
                                NULL, 1) )  
            {  
                Uart_SendString("ERR_DISK_OP_FAIL2: ");  
                Uart_SendDWORD(dwSector, TRUE);  
 
                dwSector++;  
                continue;  
            }  
              
            dwSector++;  
            dwLength--;  
            dwRAM += SECTOR_SIZE;  
        }  
 
        dwSectorsNeeded -= toc.id[dwEntry].sgList[i].dwLength;  
        i++;  
    }  
 
    return ERR_SUCCESS;  

DWORD
ReadImageFromNand(DWORD dwEntry, DWORD dwSig)
{
    DWORD dwSectorsNeeded;
    DWORD dwSector, dwLength;         // Start Sector & Length
    DWORD dwRAM, i;

    Uart_SendString("TOC_SECTOR: \n");
    Uart_SendDWORD(TOC_SECTOR,TRUE);

    //读TOC内容,确定拷贝Image所需空间、拷贝的起始地址、跳转位置等信息
    if ( !FMD_ReadSector(TOC_SECTOR,(LPBYTE)&toc,NULL, 1) )
    {
        Uart_SendString("ERR_DISK_OP_FAIL1\n");
        return ERR_DISK_OP_FAIL1;
    }

    //验证TOC是否合法
    if ( !VALID_TOC(&toc) ) {
        Uart_SendString("ERR_INVALID_TOC: ");
        Uart_SendDWORD(toc.dwSignature, TRUE);
        return ERR_INVALID_TOC;
    }

 //拷贝到RAM的Image所占的Page
 dwSectorsNeeded = toc.id[dwEntry].dwTtlSectors;
 
 Uart_SendString("Sector addr on NAND: ");
 Uart_SendDWORD(toc.id[dwEntry].sgList[0].dwSector, TRUE);
    Uart_SendString("TotalSector: ");
    Uart_SendDWORD(dwSectorsNeeded, TRUE);

 //dwRAM:拷贝Image到RAM的起始地址
 //JumpAddr:拷贝完成后的执行程序地址
    dwRAM = VIRTUAL_TO_PHYSICAL(toc.id[dwEntry].dwLoadAddress);
    JumpAddr = VIRTUAL_TO_PHYSICAL(toc.id[dwEntry].dwJumpAddress);

    // 将Image拷贝到RAM中
 i = 0;
 while (dwSectorsNeeded && i < MAX_SG_SECTORS)
 {
        dwSector = toc.id[dwEntry].sgList[i].dwSector;
        dwLength = toc.id[dwEntry].sgList[i].dwLength;
        // read each sg segment
        while (dwLength) {

            if ( !FMD_ReadSector(dwSector,
                                (LPBYTE)dwRAM,
                                NULL, 1) )
            {
                Uart_SendString("ERR_DISK_OP_FAIL2: ");
                Uart_SendDWORD(dwSector, TRUE);

       dwSector++;
    continue;
            }
           
      dwSector++;
      dwLength--;
            dwRAM += SECTOR_SIZE;
        }

        dwSectorsNeeded -= toc.id[dwEntry].sgList[i].dwLength;
        i++;
    }

    return ERR_SUCCESS;
}

里面有一个函数FMD_ReadSector(),它的功能是读取一个Page的内容到RAM中,里面调用的是一个汇编程序__RdPage512。

等ReadImageFromNand()程序成功返回后,由Launch(JumpAddr)调用一个汇编程序,执行RAM指定地址的程序。

这样就基本上把Nboot的流程讲完了。当然,还有ECC验证、Chain.bin等,以后再说。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/formerman/archive/2009/07/17/4356034.aspx

posted on 2010-08-09 00:44  jiege  阅读(524)  评论(0编辑  收藏  举报