STEPLDR是用来加载EBOOT的,即引导EBOOT的启动。STEPLDR主要包括两部分:StartUp.s 与 main.c,StartUp.s 主要是初始化CPU,引导EBOOT的功能主要在main.C中完成,该部分结构和代码都比较简单,代码如下:
// Set up copy section (initialized globals).
//
// NOTE: after this call, globals become valid.
//空函数什么都不做
SetupCopySection(pTOC);
// Enable the ICache.
//System_EnableICache(); // I-Cache was already enabled in startup.s
// Set up all GPIO ports for LED.
Port_Init();
Led_Display(0xf);
// UART Initialize
//Uart_Init();
//Uart_SendString("/r/nWinCE 6.0 Steploader for SMDKC100/r/n");
// Initialize the NAND flash interface.
//Uart_SendString("NAND Initialize/n/r");
NAND_Init();
// Copy image from NAND flash to RAM.
pBuf = (unsigned char *)LOAD_ADDRESS_PHYSICAL;
nBadBlocks = 0;
Led_Display(0x8);
for (nPage = LOAD_IMAGE_PAGE_OFFSET; nPage < (LOAD_IMAGE_PAGE_OFFSET + LOAD_IMAGE_PAGE_COUNT) ; nPage++)
{
//Led_Display(0x1);
nBlock = ((nPage / NAND_PAGES_PER_BLOCK) + nBadBlocks);
if (!NAND_ReadPage(nBlock, (nPage % NAND_PAGES_PER_BLOCK), pBuf))
{
if ((nPage % NAND_PAGES_PER_BLOCK) != 0)
{
Led_Display(0x9); // real ECC Error.
//Uart_SendString("ECC Error./r/n");
while(1)
{
// Spin forever...
}
}
// ECC error on a block boundary is (likely) a bad block - retry the page 0 read on the next block.
nBadBlocks++;
nPage--;
continue;
}
pBuf += NAND_BYTES_PER_PAGE;
}
Led_Display(0x0);
//Uart_SendString("Launch Eboot.../n/r");
((PFN_IMAGE_LAUNCH)(LOAD_ADDRESS_PHYSICAL))();
}
我们从头来看起,首先是一个SetupCopySection(pTOC),该函数是一个空函数,如下:
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);
}
注释说这是一个stub function,不明白什么意思。接着是GPIO端口和LED指示灯的初始化,然后就是NAND FLASH的初始化。注意,这部分中没有初始化串口,主要是为了加快启动速度。若要在这部分输出信息就有进行串口初始化。
pBuf = (unsigned char *)LOAD_ADDRESS_PHYSICAL; 其中的“LOAD_ADDRESS_PHYSICAL”就是要将EBOOT下载到的地址,位于DRAM,值为0X20030000。初始化完成以后就开始加载EBOOT了:
for (nPage = LOAD_IMAGE_PAGE_OFFSET; nPage < (LOAD_IMAGE_PAGE_OFFSET + LOAD_IMAGE_PAGE_COUNT) ; nPage++)
{
//Led_Display(0x1);
nBlock = ((nPage / NAND_PAGES_PER_BLOCK) + nBadBlocks);
if (!NAND_ReadPage(nBlock, (nPage % NAND_PAGES_PER_BLOCK), pBuf))
{
if ((nPage % NAND_PAGES_PER_BLOCK) != 0)
{
Led_Display(0x9); // real ECC Error.
//Uart_SendString("ECC Error./r/n");
while(1)
{
// Spin forever...
}
}
// ECC error on a block boundary is (likely) a bad block - retry the page 0 read on the next block.
nBadBlocks++;
nPage--;
continue;
}
pBuf += NAND_BYTES_PER_PAGE;
}
其中EBOOT的大小事先定义好的。加载好EBOOT以后就要运行它了:((PFN_IMAGE_LAUNCH)(LOAD_ADDRESS_PHYSICAL))();其中的PFN_IMAGE_LAUNCH是一个定义的空函数指针:typedef void (*PFN_IMAGE_LAUNCH)();这种方式比较巧妙。这样EBOOT就运行起来了。