基本上吧Nboot的程序看完了,总结一下。
主要包含以下文件:
- 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():
- 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():
- //***************************[ 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():
- 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等,以后再说。