基本上吧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