mini2440 nboot 源码分析+TOC框架图

2014年4月25日

废话少说,先上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 (;;);
}

main()函数很简单,使能MMU的指令和数据cache,端口初始化,串口初始化,nand初始化,然后调用Memset函数将pBSPArgs指针指向的1024大小的内存空间全部清零,清零后串口打印加载WinCE镜像文件的消息:
Uart_SendString("load Windows CE Image..\r\n");
然后初始化LCD显示器,然后调用
   result = ReadImageFromNand(1);
函数将镜像文件从nand flash中读取至内存中,最后调用
 if (run)   run();
启动内核。整体流程还是比较清晰明了的。
初始化什么的内部函数可以暂时不管,关键关注的重点在于
    result = ReadImageFromNand(1);
好了,我们来看一看这个函数,ReadImageFromNand()的定义在nand.c中,里面的内容还是很丰富的:

// 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;

首先是
NF_ReadSector(TOC_BLOCK*SECTOR_PER_BLOCK, (U8*)pToc);
将nand flash的TOC_BLOCK*SECTOR_PER_BLOCK区域的一个扇区大小的数据搬运至pToc所指向的内存区域
接着判断此区域数据内容
    if (!VALID_TOC(pToc))
        return 0x32;
    
    if ( !(pToc->id[dwEntry].dwImageType & IMAGE_TYPE_RAMIMAGE) ) {
        return 0x33;
    }
如果不是有效的TOC,则返回0x32,若有效,读取pToc指针指向的结构体的内容,此结构体内容如下:

//
// 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是被保留的。
TOC结构体包含了四个成员,其中id成员为 IMAGE_DESCRIPTOR类型的结构体,包含了镜像的各种描述,查看id成员:

// 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






你可能感兴趣的:(操作系统与应用透明加载)