WinCE6.0 BootloaderMain源码分析之KernelRelocte

       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函数的实现,里面有两个结构体COPYentryROMHDR,它们的定义在文件\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 的阶段了。

你可能感兴趣的:(源码分析,休闲,WinCE6.0,BootloaderMain,KernelRelocte)