Wince stepldr代码解析
Wince系统启动之后最开始执行的代码就是stepldr,当然stepldr之前还有一段汇编,这里着重讲stepldr,stepldr又分为两个部分,Stepldr_NAND和Stepldr_SD,顾名思义,Stepldr_NAND为从nand启动的stepldr引导,Stepldr_SD为从SD启动的stepldr引导。先说Stepldr_NAND,Stepldr_NAND开始部分是对小页和大页sector、 page 、block大小等的一些宏定义,大小页定义之后是对stepldr执行之后的下载地址和地址大小的定义。
这里牵扯到一个bLARGEBLOCK这个变量,该变量定义为bool型,在执行ReadFlashID()函数是被赋值。
DWORD ReadFlashID(void)
{
BYTEMfg, Dev, i;
volatileint ReadID;
UINT32nRet;
bLARGEBLOCK= FALSE;
nRet= TRUE;
NF_nFCE_L();
NF_CMD(0x90); // Send flashID read command.
NF_ADDR(0);
for(i=0; i<10; i++);
Mfg = NF_RDDATA8(); // Maker code
Dev = NF_RDDATA8(); // Devide code(K9S1208V:0x76), (K9K2G16U0M:0xca)
NF_nFCE_H();
//if(Mfg == (UINT8)0xEC || Mfg == 0xAD)
if(Mfg == (UINT8)0xEC || Mfg == (UINT8)0x1)
{
if(Dev >= (UINT8)0xA0){
bLARGEBLOCK= TRUE;
Uart_SendDWORD(bLARGEBLOCK,1);
}
}
/**********************************addend*************************/
elseif (Mfg == (UINT8)0x98)
{
}
else
{
nRet= FALSE;
}
ReadID= (DWORD)((Mfg<<8)+Dev);
Uart_SendDWORD(ReadID,1);
returnnRet;
}
下来就是main函数了,main函数开头有三个函数
MMU_EnableICache();
Uart_Init();
NF_Init();
其中MMU_EnableICache()为使能ICache指令,汇编代码如下;
; void MMU_EnableICache(void);
LEAF_ENTRY MMU_EnableICache
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #R1_I
mcr p15, 0, r0, c1, c0, 0
mov pc, lr
Uart_Init()和NF_Init()分别为串口初始化和nandflash初始化,完成这三部分初始化之后,代码继续向下执行到flash ID判断函数;
if (ReadFlashID() != TRUE)
{
WrUTXH2('I');
while(1);
}
此时如果读取失败的话就会在串口打印一个’i’,然后进入死循环,也就是说如果读取ID失败的话,程序就会卡死在这里了;
如果读取ID正确,那么就会循环读取相应块中的数据,执行代码如下:
for (nPage = NAND_COPY_PAGE_OFFSET ; nPage< (LOAD_SIZE_PAGES + NAND_COPY_PAGE_OFFSET) ; nPage++)
{
nBlock= ((nPage /((bLARGEBLOCK==TRUE)?NAND_LB_PAGES_PER_BLOCK:NAND_SB_PAGES_PER_BLOCK)) +nBadBlocks);
if (!NF_ReadPage(nBlock, (nPage% ((bLARGEBLOCK==TRUE)?NAND_LB_PAGES_PER_BLOCK:NAND_SB_PAGES_PER_BLOCK)),pCopyPtr))
{
if((nPage % ((bLARGEBLOCK==TRUE)?NAND_LB_PAGES_PER_BLOCK:NAND_SB_PAGES_PER_BLOCK))!= 0)
{
WrUTXH2('E');
while(1)
{
}
}
//ECC error on a block boundary is (likely) a bad block - retry the page 0 readon the next block.
nBadBlocks++;
nPage--;
continue;
}
此处有个nBadBlocks++,就是说如果读取失败的话会增加一个坏块,但是NF_ReadPage读取函数里并没有判断坏块,所以说,stepldr里的读是不判断坏块的,这个和nand驱动里的读函数不同,两者定义如下所示:
int NF_ReadPage(UINT32 block,UINT32sector,UINT8 *buffer);
BOOL RAW_LB_ReadPage(SECTOR_ADDRstartSectorAddr, LPBYTE pSectorBuff, LPBYTE pSectorInfoBuff);
后者参数里的pSectorInfoBuff里既包含有坏块信息;
((PFN_IMAGE_LAUNCH)(LOAD_ADDRESS_PHYSICAL))();
Main函数最后的这一段代码是一个长跳转,跳转到EBOOT的物理地址。