您的位置:首页 > 大数据 > 人工智能

WinCE6.0 BootloaderMain源码分析之KernelRelocte

2011-06-23 20:26 513 查看
Eboot启动过程中,在经历了汇编的Startup.s后,跳转到了C语言的main.c文件的main函数中,该函数中实质上就是执行的BootloaderMain函数,那这样写的目的是什么呢?微软这样的设计是为了方便用户在Startup之后和BootloaderMain之前加入一些高级语言的处理代码。
BootloaderMain函数的第一个任务就是进行全局变量重定位,即KernelRelocte函数的功能。至于为何要进行全局变量重定位,这里进行简单的描述。Bootloader通常是在ROM存储器重以XIP的方式启动运行的,在运行之初自己复制自身的镜像至RAM内存中。由于镜像所在的存储区域都是只读而不可写的,所以有必要将镜像中的数据段读到程序内存中来以保证其中的全局变量是可写的。

//
// 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 data sections 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);
}

上面是KernelRelocate函数的实现,里面有两个结构体COPYentry和ROMHDR,它们的定义在文件\WINCE600\PUBLIC\COMMON\OAK\INC\romldr.h中,定义如下:

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

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
// from FSRAMPERCENT .bib config option
// byte 0 = #4K chunks/Mbyte of RAM for filesystem 0-2Mbytes 0-255
// byte 1 = #4K chunks/Mbyte of RAM for filesystem 2-4Mbytes 0-255
// byte 2 = #4K chunks/Mbyte of RAM for filesystem 4-6Mbytes 0-255
// byte 3 = #4K chunks/Mbyte of RAM for filesystem > 6Mbytes 0-255

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;
COPYentry结构体比价简单,就是定义了源数据的地址和长度、目的地址、目的地址的空间大小,从注释中可以看出,如果目的地址空间大于源数据的长度,则多余的空间填0。

ROMHDR结构体较为负责,这里主要说一下KernelRelocate函数中用到的两个变量,ulCopyEntries表示的是全局变量重定位时需要搬移的条目数,ulCopyOffset表示的是全局变量重定位时搬移条目的偏移地址。
现在看KernelRelocate函数的实现就很简答了,COPYentry是对搬移条目的描述,通过从pTOC获得到一条一条的COPYentry,然后根据描述中的信息进行数据的搬移。
这里值得提到的是pTOC参数的定义,在KernelRelocate函数所在源文件的前面有如下定义:

ROMHDR * volatile const pTOC = (ROMHDR *)-1; // Gets replaced by RomLoader with real address
在KernelRelocate函数的一开始就判断pTOC是否等于-1,那么后面的搬移操作还会进行吗?显然要进行全局变量重定位的,要不该函数就没有意义了。那样问题的关键就在于pTOC是什么时候赋值的,以便为后面的重定位提供相关信息?
答案:pTOC是在产生ROM image的时候由WinCE的编译系统赋值的,并同时为该指针指向的ROMHDR类型的内存区域填充数据内容的。具体填充过程的代码请见这篇文章http://jamsan.blog.hexun.com/58621673_d.html。那又为何要这样做呢?《Windows CE工程实践完全解析》中有这样的介绍,完整的编译过程分为4个过程:Compile、Sysgen、Release Copy、MakeRun-Time Image。Compile阶段负责将源代码翻译成二进制目标代码,Sysgen阶段将Compile生成的目标代码链接成可执行文件(.exe和.dll),Release Copy阶段负责将Sysgen生成的可执行文件以及其他系统运行需要的数据文件复制到指定的目录下,MakeRun-Time Image阶段最后将指定目录中的所有文件打包成操作系统镜像。pTOC指向的ROMHDR的数据内容依赖于Sysgen生成的可执行文件的内容,所以只能放到MakeRun-Time Image的阶段了。本文出自 “飞雪待剑” 博客,请务必保留此出处http://jazka.blog.51cto.com/809003/595261
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: