现在的位置: 首页 > 综合 > 正文

KernelRelocate

2013年10月09日 ⁄ 综合 ⁄ 共 3609字 ⁄ 字号 评论关闭

KernelRelocate()

BootloaderMain()干的第一件事是把Boot Loader中的全局变量重定位到RAM中,完成这一任务的函数是KernelRelocate()。内核的初始化数据都保存在镜像文件中(data段的数据)。对数据的读写,必须要把镜像的真实数据内容,复制到RAM中,才允许使用。

static BOOL KernelRelocate (ROMHDR *const pTOC)
{

    ULONG loop;
    COPYentry *cptr;
// 如果pTOC为-1则重定位失败
if (pTOC == (ROMHDR *const) -1)
{
return (FALSE); // spin forever!
}
// 根据pTOC结构体中的信息,获得要拷贝的源地址、目标地址和长度
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);
// 把多余的地址置0
if (cptr->ulCopyLen != cptr->ulDestLen) memset((LPVOID)(cptr->ulDest+cptr->ulCopyLen),0,cptr->ulDestLen-cptr->ulCopyLen);
}
return (TRUE);
}

在理解这个函数时,需要知道如下信息

ROMIMAGE.exe:  生成系统镜像文件的程序。

TOC: Table Of Contents, 保存了系统的指针和数据。在镜像文件开头附近,有一个标志,内容是CECE(0x44424442)。这个标志后面就存放着TOC的偏移值,那么bootloader和其他程序可以通过TOC找到镜像相关的信息。

ROMHDR结构体:

typedef struct ROMHDR {

    ULONG   dllfirst;               // first DLL address

    ULONG   dlllast;                // last DLL address

    ULONG   physfirst;              // first physical address

    ULONG   physlast;               // highest physical address

    ULONG   nummods;                // number of TOCentry's

    ULONG   ulRAMStart;             // start of RAM

    ULONG   ulRAMFree;              // start of RAM free space

    ULONG   ulRAMEnd;               // end of RAM

    ULONG   ulCopyEntries;          // number of copy section entries 

    ULONG   ulCopyOffset;           // offset to copy section

    ULONG   ulProfileLen;           // length of PROFentries RAM 

    ULONG   ulProfileOffset;        // offset to PROFentries

    ULONG   numfiles;               // number of FILES

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

    ULONG   ulFSRamPercent;         // Percentage of RAM used for filesystem 

    ULONG   ulDrivglobStart;        // device driver global starting address

    ULONG   ulDrivglobLen;          // device driver global length

    USHORT  usCPUType;              // CPU (machine) Type

    USHORT  usMiscFlags;            // Miscellaneous flags

    PVOID   pExtensions;            // pointer to ROM Header extensions

    ULONG   ulTrackingStart;        // tracking memory starting address

    ULONG   ulTrackingLen;          // tracking memory ending address

} ROMHDR;

ulCopyOffset:全局变量存放的起始地址。

struct COPYentry {

    ULONG   ulSource;                 // copy source address

    ULONG   ulDest;                     // copy destination address

    ULONG   ulCopyLen;              // copy length

    ULONG   ulDestLen;               // copy destination length 

                                                    // (zero fill to end if > ulCopyLen)

} COPYentry;  

ulDest:全局变量被存放的RAM起始地址

ulSource:全局变量被存放的ROM中的起始地址

ulCopyLen:全局变量真实个数长度
ulDestLen:为期望全局变量长度

第一个问题,为什么要把全局变量重定位到RAM中。Boot Loader的大多数代码是用C语言编写的,并且在其中还定义了一些全局变量,当Boot Loader被编译成二进制代码后,这些全局变量被放在可执行文件的一个数据段中。然后整个Boot Loader的二进制代码被烧写到目标设备上,包括全局变量所在的数据段。很多情况下,Boot Loader是在目标设备的只读媒体上运行的(例如NOR Flash ROM上),如果是这种情况,Boot Loader的代码想对全局变量进行写操作就会失败。因此,需要把全局变量所在的数据段移到RAM中,来确保全局变量可写。

第二个问题,如何移动数据段。从代码中我们也可以看出,如何移动数据、移动多少数据完全都是KernelRelocate()函数的唯一一个参数pTOC决定的。如果查找pTOC的定义,可以发现同样在BLCommon.c文件中定义如下:

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

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

从这个变量的含义我们可以看出,这个指针指向包含ROM信息的结构体。在编写代码的时候,代码不可能知道自己将会被烧写到什么样的ROM里。因此,代码本身是不可能得到ROM的信息的,那么,唯一可以确定ROM信息的就是ROM的制作工具——RomImage.exe(工具的详细介绍可以参考本书相关的章节)。是的,pTOC这个全局变量正是由RomImage.exe这个工具在把EBOOT打包成ROM文件时初始化的。

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

经过代码重定位之后,EBoot中的全局变量就可以在RAM中正确的读/写了,这样才可以保证EBoot的代码可以正确运行。

http://hi.baidu.com/xzf20082004/item/4e884ec2481270b30d0a7b37

抱歉!评论已关闭.