废话少说,先上main函数:
void Main(void)
{
char result;
MMU_EnableICache();
MMU_EnableDCache();
Port_Init();
Uart_Init();
Nand_Init();
//Memset((char*)0x30000000, 0, 3U * 512 * 1024);
//Memset((char*)0x30000000 + 32U * 1024 * 1024, 0, 128U * 1024U);
Memset((char*)pBSPArgs, 0, 1024);
Uart_SendString("load Windows CE Image..\r\n");
//for(;;);
InitLCD();
result = ReadImageFromNand(1);
if (run) run();
// shouldn't be here.
for (;;);
}
// Loading
char ReadImageFromNand(unsigned int dwEntry)
{
volatile unsigned int dwSectorsNeeded;
volatile unsigned int dwSector, dwLength; // Start Sector & Length
volatile unsigned int dwRAM, i;
NF_ReadSector(TOC_BLOCK*SECTOR_PER_BLOCK, (U8*)pToc);
if (!VALID_TOC(pToc))
return 0x32;
if ( !(pToc->id[dwEntry].dwImageType & IMAGE_TYPE_RAMIMAGE) ) {
return 0x33;
}
dwSectorsNeeded = pToc->id[dwEntry].dwTtlSectors;
dwRAM = VIRTUAL_TO_PHYSICAL(pToc->id[dwEntry].dwLoadAddress);
run = (void (*)(void))(pToc->id[dwEntry].dwJumpAddress ? VIRTUAL_TO_PHYSICAL(pToc->id[dwEntry].dwJumpAddress) :
VIRTUAL_TO_PHYSICAL(pToc->id[dwEntry].dwLoadAddress));
i = 0;
while (dwSectorsNeeded && i < MAX_SG_SECTORS)
{
dwSector = pToc->id[dwEntry].sgList[i].dwSector;
dwLength = pToc->id[dwEntry].sgList[i].dwLength;
ProgressBarInit(dwLength);
// read each sg segment
while (dwLength) {
if (dwSector % SECTOR_PER_BLOCK == 0) {
if (! NF_IsBadBlock(dwSector/SECTOR_PER_BLOCK)) {
dwSector += SECTOR_PER_BLOCK;
continue;
}
}
if(!NF_ReadSector(dwSector, (unsigned char*)dwRAM)){
Uart_SendString("\nCannot load Windows CE\n");
while (1);
}
dwSector++;
dwLength--;
dwRAM += SECTOR_SIZE;
ProgressBarStep();
}
dwSectorsNeeded -= pToc->id[dwEntry].sgList[i].dwLength;
i++;
}
return 0;
//
// TOC: Table Of Contents, OEM on disk structure.
// sizeof(TOC) = SECTOR_SIZE.
// Consider the TOC_BLOCK to contain an array of PAGES_PER_BLOCK
// TOC entries, since the entire block is reserved.
//
typedef struct _TOC {
DWORD dwSignature;
// How to boot the images in this TOC.
// This could be moved into the image descriptor if desired,
// but I prefer to conserve space.
BOOT_CFG BootCfg;
// Array of Image Descriptors.
IMAGE_DESCRIPTOR id[MAX_TOC_DESCRIPTORS];
CHAININFO chainInfo;
} TOC, *PTOC; // 512 bytes
TOC包含了OEM代码在磁盘上的存储结构,TOC的大小呢等于一个扇区的面积,这也就和从磁盘(nand flash)的指定位置读取一个扇区的面积的数据相对应了。TOC_BLOCK存放了PAGES_PER_BLOCK TOC入口信息队列,因此这个整个block是被保留的。
// IMAGE_DESCRIPTOR: describes the image to load.
// The image can be anything: bootloaders, RAMIMAGE, MXIP, ...
// Note: Our NAND uses H/W ECC, so no checksum needed.
//
typedef struct _IMAGE_DESCRIPTOR {
// File version info
DWORD dwVersion; // e.g: build number
DWORD dwSignature; // e.g: "EBOT", "CFSH", etc
UCHAR ucString[IMAGE_STRING_LEN]; // e.g: "PocketPC_2002"
DWORD dwImageType; // IMAGE_TYPE_ flags
DWORD dwTtlSectors; // TTL image size in sectors.
// We store size in sectors instead of bytes
// to simplify sector reads in Nboot.
DWORD dwLoadAddress; // Virtual address to load image (ImageStart)
DWORD dwJumpAddress; // Virtual address to jump (StartAddress/LaunchAddr)
// This array equates to a sector-based MXIP MultiBINInfo in blcommon.
// Unused entries are zeroed.
// You could chain image descriptors if needed.
SG_SECTOR sgList[MAX_SG_SECTORS];
// BinFS support to load nk region only
//struct
//{
ULONG dwStoreOffset; // byte offset - not needed - remove!
//ULONG RunAddress; // nk dwRegionStart address
//ULONG Length; // nk dwRegionLength in bytes
//ULONG LaunchAddress; // nk dwLaunchAddr
//} NKRegion;
} IMAGE_DESCRIPTOR, *PIMAGE_DESCRIPTOR;
在 ReadImageFromNand()的前部分,主要任务是校验TOC合法性、验证image类型、image总扇区数、image加载至内存的地址dwRAM、跳转地址run,然后通过while循环读取flash中的image信息至内存中。
while (dwSectorsNeeded && i < MAX_SG_SECTORS)
{
dwSector = pToc->id[dwEntry].sgList[i].dwSector;//image段第i个list的开始扇区
dwLength = pToc->id[dwEntry].sgList[i].dwLength;//镜像段的第i个list的长度(多少个扇区)
ProgressBarInit(dwLength);//
// read each sg segment
while (dwLength) {
if (dwSector % SECTOR_PER_BLOCK == 0) {//若dwSector为block的开头
if (! NF_IsBadBlock(dwSector/SECTOR_PER_BLOCK)) {//则检查block是否是坏块
dwSector += SECTOR_PER_BLOCK;//坏块则跳过此坏块
continue;
}
}
if(!NF_ReadSector(dwSector, (unsigned char*)dwRAM)){//读取dwSector的一个扇区至dwRAM
Uart_SendString("\nCannot load Windows CE\n");
while (1);
}
dwSector++;//扇区头地址往后挪一个位置
dwLength--;//镜像长度减一
dwRAM += SECTOR_SIZE;//ram中的目的地址往后挪一,增加的长度为一个扇区的长度
ProgressBarStep();
}
dwSectorsNeeded -= pToc->id[dwEntry].sgList[i].dwLength;//需要读取的总扇区数=总扇区数-已经读取数据的扇区数
i++;
}
此段代码负责将flash中的内容复制至RAM中,包含两个while循环while (dwSectorsNeeded && i < MAX_SG_SECTORS)、while (dwLength) ,其中while (dwLength) 负责将一个list的数据,从dwSector开始的dwLength个扇区数据搬运至dwRAM中,while (dwSectorsNeeded && i < MAX_SG_SECTORS)负责遍历所有的list,list数据共有MAX_SG_SECTORS个,通过查看这个宏可以知道,MAX_SG_SECTORS为14个,dwSectorsNeeded是镜像所有list的扇区总数,while循环里的判断语句可谓双保险,通过判定:1.复制的扇区总数是否足额2.复制的list数目是否足额,来停止image的复制。
通过list的数据结构可以很清晰的知道,所有的list应该是连续的,而这MAX_SG_SECTORS个的各个list可以使不连续的。
将nand里面的内容读取完成之后,就可以执行:
if (run) run();
跳转至内核,启动。
run = (void (*)(void))(pToc->id[dwEntry].dwJumpAddress ? VIRTUAL_TO_PHYSICAL(pToc->id[dwEntry].dwJumpAddress) :
VIRTUAL_TO_PHYSICAL(pToc->id[dwEntry].dwLoadAddress));
其中函数run的声明也特别有意思:
void (*run)(void)=(void (*)(void))(DOWNLOAD_ADDRESS);
void (*run)(void)定义了一个名称为run指向参数为void,返回值也为void的函数的指针,可以看做:
run为指向出入参数和返回值均为void的函数的指针,void (*run)(void)=(void (*)(void))(DOWNLOAD_ADDRESS);表示将地址DOWNLOAD_ADDRESS赋予run指针,也就是跳转执行了。(void (*)(void))表示将DOWNLOAD_ADDRESS地址强制转换为和run指针类型一致的地址值,也就是所谓的强制转换。
void (*run)(void) = (void (*)(void))0x0;
void (*run)(void) = (void (*)(void))0x0;
定义了一个不带参数和返回值的函数指针run ,同时对它进行初始化。指向了内存的0号单元。
run是一个指向返回值和参数都为空的函数的指针,0x0就是0,这个赋值就是将地址0强制转换为返回值和参数都为空的函数的地址赋给run。
(void (*)(void))进行强制转换.就好象(char *)str一样
void (*run)(void)与void (*)(void)有什么区别呢 ?
只是差个名称
对于类型来说本身叫什么就没必要
void (*)(void) 就是函数指针,它是个类型说明
void (*)(void)
(*) --我是函数指针
(void)-不需要传给我参数
void --我的返回类型为空
------------------
void (*run)(void)
(*run) --我是函数指针 ,我叫run
(void)-不需要传给我参数
void --我的返回类型为空
你可以这么看typedef void (*run)(void) 然后run a = (run)0x00; 这样总能理解了吧
typedef struct _TOC {
DWORD |
dwSignature; |
BOOT_CFG |
BootCfg; |
IMAGE_DESCRIPTOR |
id[MAX_TOC_DESCRIPTORS]; |
CHAININFO |
chainInfo; |
} TOC, *PTOC; // 512 bytes
typedef struct _BOOTCFG {
ULONG |
ImageIndex; |
ULONG |
ConfigFlags; |
ULONG |
BootDelay; |
EDBG_ADDR |
EdbgAddr; |
ULONG |
SubnetMask; |
} BOOT_CFG, *PBOOT_CFG;
typedef struct _EDBG_ADDR {
DWORD |
dwIP; |
USHORT |
wMAC[3]; |
USHORT |
wPort; |
} EDBG_ADDR;
typedef struct _IMAGE_DESCRIPTOR {
DWORD |
dwVersion; |
DWORD |
dwSignature; |
UCHAR |
ucString[IMAGE_STRING_LEN]; |
DWORD |
dwImageType; |
DWORD |
dwTtlSectors; |
DWORD |
dwLoadAddress; |
DWORD |
dwJumpAddress; |
SG_SECTOR |
sgList[MAX_SG_SECTORS]; |
} IMAGE_DESCRIPTOR, *PIMAGE_DESCRIPTOR;
typedef struct _SG_SECTOR {
DWORD |
dwSector; |
DWORD |
dwLength; |
} SG_SECTOR, *PSG_SECTOR;
typedef struct _CHAININFO {
DWORD |
dwLoadAddress; |
DWORD |
dwFlashAddress; |
DWORD |
dwLength; |
} CHAININFO, *PCHAININFO;
TOC分析见 http://blog.csdn.net/formerman/article/details/4347905