WINCE TOC解析

1.  TOC是什么

TOC:Table Of Contents, OEM on disk structure.

2.  为什么要进行全局变量重定位

Bootloader的主控制函数BootloaderMain()调用的第一个函数是KernelRelocate (pTOC),WINCE操作系统OAL模块的启动过程中调用的ARMInit()函数页调用了KernelRelocate (pTOC)。这两次对KernelRelocate函数的调用把全局变量重定位到RAM中,只不过它们操作的对象不同。OAL模块的ARMInit函数调用的KernelRelocate函数是对WINCE操作系统镜像的全局变量进行重定位,而BootloaderMain函数调用KernelRelocate函数是对Bootloader的全局变量重定位。

那么为什么要对bootloader及操作系统的全局变量进行重定位呢? bootloader及WINCE操作系统的源代码中,需要定义一些全局变量,当这两者的源代码分别编译链接成可执行的二进制文件后,这些全局变量被放在可执行文件的一个数据段中。此二进制代码被烧写到目标设备上,包括全局变量所在的数据段,而很多种情况下,bootloader是在只读的目标设备(比如nor flash)上运行,如果是这种情况,那么bootloader的代码要对全局变量进行写操作就会失败。因此,需要把bootloader的全局变量所在的数据段移到RAM中,来确保全局变量可写。而在操作系统启动过程中,需要把镜像的数据从目标设备(比如nand flash)读入到config.bib文件中定义的RAMIMAGE的区域内,这块区域是SDRAM

我们知道boot的方式一般有nandboot和nor boot这两种,其中nor flash支持XIP执行的方式,但因为nor flash价格相对nand flash高许多,所以现在很多系统采用的boot方式是nand boot方式,但不管使用哪种方式,保存着bootloader的镜像和WINCE镜像的nand flash或是norflash

3.  如何实现全局变量重定位

相关的代码如下:

// Gets replaced by RomLoader with realaddress

ROMHDR * volatile const pTOC = (ROMHDR*)-1; 

/**********************************************/

可知它是一个指向ROMHDR结构体的指针。此指针描述了整个ROM的几乎所有信息。但是也可看到在变量声明时,此变量被赋予了一个非法值-1.那么这个变量到底是在什么时候、什么地方被初始化的呢?

此指针指向包含ROM信息的结构体,在编写代码时,代码本身不可能知道自己将会被烧写到什么样的ROM里。因此代码本身是不包含ROM信息的,那么唯一可以确定ROM信息的就是ROM的制作工具—RomImage.exe(MakeImage.exe调用RomImage.exe来打包所有的文件,RomImage.exe接受BIB文件作为参数,根据BIB(eboot.bib,config.bib,platform.bib)文件的内容打包,在该步中,MakeImage.exe会调用命令:romimage config.bib(这个文件是我的理解),从而根据config.bib的内容来把EBOOT打包为ROM文件(eboot.nb0)时初始化的。)。

RomImage.exe把文件打包为ROM文件时,读取一些特殊的全局变量或函数的符号表,然后对这些符号表进行一些操作。pTOC全局变量就是这些特殊的全局符号之一。RomImage.exe保证代码在ROM运行时,pTOC指针已经指向了正确的位置。

 

/************************************************/  

void BootloaderMain (void)

{

    ……………………

   // relocate globals to RAM

   if (!KernelRelocate (pTOC))

   {

       // spin forever

       HALT (BLERR_KERNELRELOCATE);

}

……………………

}

KernelRelocate的函数体如下所示:

KernelRelocate

//KernelRelocate: move global variables to RAM

static BOOL KernelRelocate (ROMHDR *const pTOC)

{

    ULONG loop;

    COPYentry *cptr;

    if (pTOC == (ROMHDR*const) -1)

    {

        return (FALSE);// spin forever!

}

// This is where the datasections become valid... don't read globals until after //this

    for (loop = 0; loop< pTOC->ulCopyEntries; loop++)

    {

        cptr = (COPYentry*)(pTOC->ulCopyOffset + loop*sizeof(COPYentry));

        if(cptr->ulCopyLen)

            memcpy((LPVOID)cptr->ulDest,(LPVOID)cptr->ulSource,cptr->ulCopyLen);

        if(cptr->ulCopyLen != cptr->ulDestLen)

memset((LPVOID)(cptr->ulDest+cptr->ulCopyLen),0,

cptr->ulDestLen-cptr->ulCopyLen);

    }

    return (TRUE);

}

 

4.  ROMHDR结构体

我们知道pTOC是一个指向ROMHDR结构体的指针,这个结构体在xxx:\WINCE500\PUBLIC\COMMON\OAK\INC的romldr.h下定义,内容如下

typedefstruct ROMHDR {

    ULONG  dllfirst;               // firstDLL address

    ULONG  dlllast;                // lastDLL address

    ULONG  physfirst;              // first physical address

    ULONG  physlast;               // highestphysical address

    ULONG  nummods;                // numberof TOCentry's

    ULONG  ulRAMStart;             // startof RAM

    ULONG  ulRAMFree;              // startof RAM free space

    ULONG  ulRAMEnd;               // end ofRAM

    ULONG  ulCopyEntries;          // numberof copy section entries

    ULONG  ulCopyOffset;           // offsetto copy section

    ULONG  ulProfileLen;           // lengthof PROFentries RAM

    ULONG  ulProfileOffset;        // offsetto PROFentries

    ULONG  numfiles;               // numberof FILES

ULONG  ulKernelFlags;          //optional kernel flags from ROMFLAGS .bib config option

/************************************************************/

Percentageof RAM used for filesystem  fromFSRAMPERCENT .bib config option

byte0 = #4K chunks/Mbyte of RAM for filesystem 0-2Mbytes 0-255

byte1 = #4K chunks/Mbyte of RAM for filesystem 2-4Mbytes 0-255

byte2 = #4K chunks/Mbyte of RAM for filesystem 4-6Mbytes 0-255

byte3 = #4K chunks/Mbyte of RAM for filesystem > 6Mbytes 0-255

/************************************************************/

    ULONG  ulFSRamPercent;         //

 

    ULONG  ulDrivglobStart;        // devicedriver global starting address

    ULONG  ulDrivglobLen;          // devicedriver global length

    USHORT usCPUType;              // CPU(machine) Type

    USHORT usMiscFlags;            //Miscellaneous flags

    PVOID  pExtensions;            // pointerto ROM Header extensions

    ULONG  ulTrackingStart;        //tracking memory starting address

    ULONG  ulTrackingLen;          //tracking memory ending address

}ROMHDR;

 

    所用的结构体COPYentry的内容如下:

typedefstruct COPYentry {

    ULONG  ulSource;               // copysource address

    ULONG  ulDest;                 // copydestination address

    ULONG  ulCopyLen;              // copylength

    ULONG  ulDestLen;              // copydestination length

                                    // (zero fill toend if > ulCopyLen)

}COPYentry;

    但Romimage.exe如何去初始化这些结构体的呢?首先我们通过下图的命令所得到的文本文件内容如下:

   

                            图1

所得到的文本文件的部分内容:

 

                            图2

打包工具Romimage.exe根据config.bib


                             图3

根据“NK       8C200000  01B00000 RAMIMAGE”,Romimage.exe在编译的时候初始化ROMHDR结构体的成员physfirst=0x8C200000,也就是图2中的“Physical First      : 0x8C200000  ”,但是操作系统镜像的实际大小是图2的“length = 0x0158537C”,所以可以得出0x8C200000+0x0158537C=图2的“Physical Last       : 0x8D78537C  ”,这就初始化了成员physlast=0x8D758537C,其他的成员的初始化可以根据.bib文件来推导。

5.  深入认识TOC数据

WINCE操作系统nk.bin文件是最常用的记录格式类型的操作系统镜像文件(还有nk.nb0)。镜像数据nk.bin格式:最开始是7个字节的文件头,内容为42 30 30 30 46 46 0A,即“B000FF\x0A”,我用记事本打开时看到的内容如下:


                                图4

接下来的4字节是操作系统镜像数据的目的起始地址(Image Start),再4字节是以字节为单位的镜像数据长度(length),再接下来就是nk.bin的逐条记录(Record),也就是操作系统镜像的数据正文,其中每一条记录由4字节起始地址(Start)、4字节数据长度(Length)、4字节校验码(Chksum)和Length个字节的记录数据(RecordData)组成,见下图:

                                图5

    接下来,我们通过图6可知pTOC=0x8d783764,它所指向的内存区域的操作系统镜像数据保存在Record[144]中,这条记录的长度为0x54(=84个字节),正好是ROMHDR类型的大小  (19*4+2*2+4=84)吻合

   

                                                       图6.   

你可能感兴趣的:(WINCE TOC解析)