Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1691361
  • 博文数量: 206
  • 博客积分: 1450
  • 博客等级: 上尉
  • 技术积分: 2285
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-11 11:38
个人简介

学习永无止境!!

文章分类

全部博文(206)

文章存档

2022年(5)

2019年(3)

2018年(8)

2017年(32)

2016年(7)

2015年(13)

2014年(44)

2013年(24)

2011年(6)

2010年(17)

2009年(46)

2008年(1)

分类: 嵌入式

2010-06-11 10:26:25

在Eboot的main.c文件中需要存在下一语句

ROMHDR *const volatible pTOC=(ROMHDR *)-1; // Get replaced by romloader with real address.

这一语句的作用是提供给函数KernelRelocate 进行数据和代码的位置重定位。

现在关注一下ROMHDR的结构体:
typedef struct ROMHDR {
       ULONG dllfirst;
       ULONG dlllast;
       ULONG physfirst;
       ULONG physlast;
       ULONG nummods;
       ULONG ulRAMStart;
       ULONG ulRAMFree;
       ULONG ulRAMEnd;
       ULONG ulCopyEntries;
       ULONG ulCopyOffset;
       ULONG ulProfilLen;
       ULONG ulProfileOffset;
       ULONG numfiles;
       ULONG ulKernlFlags;
       ULONG ulFSRamPercent;
       ULONG ulDrivglobStart;
       ULONG ulDrivgloblen;
       ULONG usCPUType;
       ULONG usMiscFlags; //miscellaneous flags
       PVOID   pExtensions;
       ULONG ulTrackingStart;
       ULONG ulTrackinglen;
}ROMHDR;

在eboot的bootloadermain函数中有ROMHDR * volatile const pTOC = (ROMHDR *)-1;

   Bootloader在启动之后主要作用就是拷贝内核到指定地址的ram中去,而boot代码之所以知道需要拷贝哪些代码或数据段到目标地址,是因为它根据一个约定的数据结构来拷贝的,这个数据结构就是ROMHDR。它是在产生ROM image的时候由OS linker来填充的.

// Search for a valid ROMHDR. This callback looks for sections that
// are 8 bytes long and that contain a "CECE" signature. It then
// enumerates all sections looking for one whose offset matches the
// offset following the "CECE" signature. That will be the ROMHDR
// itself.
HeaderCallbackCode FindROMHDR(unsigned __int8 *RomImage, DWORD FileSize, const CESectionHeader *pSection)
{
CESectionHeader sectionHeaderLocal;
if ( !safe_copy((void*)§ionHeaderLocal, (void *)pSection, sizeof(CESectionHeader) ))
{
return Error_StopEnumerating;
}
if (sectionHeaderLocal.fSectionSize != 8) {
return ContinueEnumerating;
}
unsigned __int32 ContentsLocal[2];
if ( !safe_copy((void*)&ContentsLocal[0], (void *)&pSection[1], sizeof(ContentsLocal) ))
{
return Error_StopEnumerating;
}
if (ContentsLocal[0] != 0x43454345) {
return ContinueEnumerating;
}
ROMHDRAddress = ContentsLocal[1];
pROMHDR = NULL;
if (ForEachSectionHeader(RomImage, FileSize, FindROMHDRFromAddress)) {
// Enumerating completed successfully. Now... did we find a ROMHDR for our pSection?
if (pROMHDR) {
   return Success_StopEnumerating;
} else {
   return ContinueEnumerating;
}
}
return Error_StopEnumerating;
}

    ce支持把os image放到不连续的rom里面,并且sdram也可以不连续,ce用这个结构来标示每一块memory。
          typedef struct ROMChain_t {
              struct ROMChain_t *pNext;
              ROMHDR *pTOC;
         } ROMChain_t;
 
然后将这些不连续的块串成一个链表。具体域的意思你可以结合romimage生成*.bin/*.nb0的时候产生的log文件看,比如
First DLL code Address: 04000000
Last DLL code Address: 04000000
First DLL Address: 02000000
Last DLL Address: 02000000
Physical Start Address: 8c030000
Physical End Address: 8c03b388
Start RAM: 8c050000
Start of free RAM: 8c052000
End of RAM: 8c100000
Number of Modules: 1
Number of Copy Sections: 1
Copy Section Offset: 8c03ad84
FileSys 4K Chunks/Mbyte: 128 <2Mbyte 128 2-4Mbyte 0 4-6Mbyte 0 >6Mbyte
CPU Type: 01c2h
Total ROM size: 0000b388 ( 45960)
Starting ip: 8c031000
Raw files size: 00000000
Compressed files size: 00000000

==============================

romimage.exe如何填充eboot.bin中的pTOC特殊指针生成.nb0

eboot.bin和eboot.nb0的差别就是
eboot.bin中没有填充pTOC结构体,必须使用parser解释器[类似于romimage.exe luther.gliethttp]将全局变量数据段解压释放到运行时使用的地址才行,
eboot.nb0中经过romimage.exe填充了pTOC结构体,所以eboot.nb0可以自己将自己用到的全局量通过KernelRelocate()函数进行解压释放,这就是为什么
eboot.nb0比eboot.bin的size大的原因.

eboot.nb0是一个包含全局变量初始化pTOC结构体的文件,所以当eboot.nb0启动时就可以通过BootloaderMain()==>KernelRelocate(pTOC)
实现eboot.nb0自己初始化自己定义的全局变量的工作,其实KernelRelocate就相当于ADS启动汇编中对如下四个section的操作:
Image$$RO$$Limit
Image$$RW$$Base
Image$$ZI$$Base
Image$$ZI$$Limit
但是我们在源程序中只能找到pTOC的定义ROMHDR * volatile const pTOC = (ROMHDR *)-1;根本找不到对它进行赋值的任何操作,无论是.s汇编还是任何宏中,
那pTOC又是从哪里得到了有效的数值的呢?这就是我们下面继续讨论的问题,一切疑惑都可以从romimage.exe中获得答案.
romimage.exe源码位于WINCE500\PRIVATE\WINCEOS\COREOS\NK\TOOLS\ROMIMAGE\ROMIMAGE目录下,
C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\TOOLS\ROMIMAGE\ROMIMAGE\module.cpp|118| if(token == "pTOC"){
void Module::check_special_symbol(string token, DWORD o32_section, DWORD offset, MemoryList &memory_list){
    ...
    if(is_kernel()){
        if(token == "pTOC"){
//我们在eboot源码PLATFORM\SMDK2440A\Src\Bootloader\Eboot_usb\blcommon.c中定义了该符号,如下:
//ROMHDR * volatile const pTOC = (ROMHDR *)-1; // Gets replaced by RomLoader with real address
//记录pTOC指针所在位置
           m_TOC_offset = offset + m_load_offset;
// doesn't get load offset added, because only compared with rva later
           LAST_PASS_PRINT printf("Found pTOC at %08x\n", m_TOC_offset);
        }
        if(needs_signing()){
          if(token == "OEMIoControl")
             s_oem_io_control = offset + m_初始化c代码定义的非0值全局变量[luther.gliethttp]load_offset - page_size();
        }
        ...
    }
    ...
}
bin.cpp|87| kernel->write_TOC_ptr(romhdr_offset);
bool write_bin(AddressList &hole_list, CopyList &copy_list,
                 ModuleList &module_list, FileList &file_list,
                 MemoryList &memory_list, MemoryList &reserve_list,
                 ModuleList::iterator &kernel, Config &config, MemoryList::iterator xip_mem){
    ...
    
// write toc into kernel
    if(xip_mem->is_kernel() && kernel->is_kernel())
         kernel->write_TOC_ptr(romhdr_offset);
//将romimage.exe计算后的toc起始地址存入pTOC 指针所在处,这样eboot.nb0中的pTOC指针就指向了romhdr_offset这个有效空间
    ...
}
初始化c代码定义的非0值全局变量
void Module::write_TOC_ptr(DWORD addr){
  assert(is_kernel());
  if(!m_TOC_offset){
    fprintf(stderr, "Error: Found NULL or missing TOC pointer for %s\n", m_name.c_str());
    exit(1);
  }
// *(DWORD *)(m_o32_list[0].data.ptr() + m_TOC_offset - page_size()) = addr;
  *(DWORD *)rva2ptr(m_TOC_offset) = addr;
//等效于eboot.nb0中执行pTOC = (void*)addr
}
来看看eboot.nb0是怎么使用pTOC来初始化eboot.bin定义的全局变量的:
main
==>BootloaderMain()
==>KernelRelocate(pTOC)
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;
//
// 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++)
    {
//ulCopyOffset为若干个COPYentry结构体的内存偏移地址
//COPYentry为全局变量描述结构体
//其中ulDest为全局变量被使用时的目的地址
//其中ulSource为全局变量被压缩存储在ROM中的起始地址
//其中ulCopyLen为全局变量真实个数长度
//其中ulDestLen为期望全局变量长度
//ulDestLen一定>=ulCopyLen
//如果ulDestLen大于ulCopyLen,那么说明,该region的全局变量除了有非0数据之外
//还存在ulDestLen减去ulCopyLen字节的清0数据空间
//其实KernelRelocate就相当于ADS中如下汇编代码:
/* add r2, pc,#-(8+.-CInitData) ; @ where to read values (relative)
     ldmia r2, {r0, r1, r3, r4}
     cmp r0, r1 ; Check that they are different
     beq EndRW
LoopRW 初始化c代码定义的非0值全局变量
     cmp r1, r3 ; Copy init data
     ldrcc r2, [r0], #4
     strcc r2, [r1], #4
     bcc LoopRW
EndRW
     mov r2, #0
LoopZI 初始化c代码未定义的全局变量或者强行指定为0值的全局变量

     cmp r3, r4 ; Zero init
     strcc r2, [r3], #4
     bcc LoopZI
     b EndInitC           
CInitData
      IMPORT |Image$$RO$$Limit| ; End of ROM code (=start of ROM data)
     IMPORT |Image$$RW$$Base| ; Base of RAM to initialise
     IMPORT |Image$$ZI$$Base| ; Base and limit of area
     IMPORT |Image$$ZI$$Limit| ; Top of zero init segment
     DCD |Image$$RO$$Limit| ; End of ROM code (=start of ROM data)
      DCD |Image$$RW$$Base| ; Base of RAM to initialise
      DCD |Image$$ZI$$Base| ; Base and limit of area
      DCD |Image$$ZI$$Limit| ; Top of zero init segment
*/

         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);
}

阅读(2511) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~