【转载】CE5.0 - romimage.exe如何填充eboot.bin中的pTOC特殊指针生成.nb0

本文深入探讨了KernelRelocate函数的作用及实现原理,特别是在嵌入式系统中如何将全局变量从ROM复制到RAM的过程。通过详细分析eboot.bin与eboot.nb0的区别,以及pTOC指针的初始化和使用方式,帮助读者理解全局变量初始化的关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一篇对于了解KernelRelocate函数,很棒的文章。全局变量在ROM中时不能被写,所以需要把全局变量放到RAM中,这样程序就可以对全局变量进行读写操作。下面是文章的详细内容:

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大的原因[ luther. gliethttp].

eboot. nb0是一个包含全局变量初始化pTOC结构体的文件, 所以当eboot. nb0启动时就可以通过BootloaderMain()==> KernelRelocate( pTOC) 实现eboot. nb0自己初始化自己定义的全局变量的工作, 其实KernelRelocate就相当于ADS启动汇编中对如下四个section的操作:[ luther. gliethttp]
Image$$RO$$Limit
Image$$RW$$Base
Image$$ZI$$Base
Image$$ZI$$Limit
但是我们在源程序中只能找到pTOC的定义ROMHDR * volatile const  pTOC = ( ROMHDR *)- 1; 根本找不到对它进行赋值的任何操作, 无论是. s汇编还是任何宏中, 那pTOC又是从哪里得到了有效的数值的呢?这就是我们下面继续讨论的问题, 一切疑惑都可以从romimage. exe中获得答案.[ luther. gliethttp]

romimage. exe源码位于WINCE500\PRIVATE\ WINCEOS\COREOS\NK\TOOLS\ROMIMAGE\ROMIMAGE目录下,
C:\ WINCE500\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指针所在位置[luther.gliethttp]

          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这个有效空间[luther.gliethttp].

    ...
}
初始化c代码定义的非0值全局变量[ luther. gliethttp]
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;[luther.gliethttp]

}

来看看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

    // 就像这句话描述的一样,只有执行完该函数之后,全局变量所在地址处才有了真实的全局变量数值,

    // 所以只有执行完该函数之后,我们才能够访问全局变量[luther.gliethttp]

    for (
loop =  0;  loop <  pTOC-> ulCopyEntries;  loop++)
    {
//ulCopyOffset为若干个COPYentry结构体的内存偏移地址

//COPYentry为全局变量描述结构体

//其中ulDest为全局变量被使用时的目的地址

//其中ulSource为全局变量被压缩存储在ROM中的起始地址

//其中ulCopyLen为全局变量真实个数长度

//其中ulDestLen为期望全局变量长度

//ulDestLen一定>=ulCopyLen

//如果ulDestLen大于ulCopyLen,那么说明,该region的全局变量除了有非0数据之外

//还存在ulDestLen减去ulCopyLen字节的清0数据空间[lutehr.gliethttp]

//其实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值全局变量[luther.gliethttp]
    cmp r1, r3 ; Copy init data
    ldrcc r2, [r0], #4
    strcc r2, [r1], #4
    bcc LoopRW
EndRW

    mov r2, #0
LoopZI 初始化c代码未定义的全局变量或者强行指定为0值的全局变量[luther.gliethttp]
    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);
}

转载于:https://www.cnblogs.com/IamEasy_Man/archive/2009/09/08/1562918.html

<think>嗯,用户的问题是关于如何创建或编辑GeekOS项目0的Bochs配置文件,也就是.bochsrc文件。首先,我需要回忆一下Bochs模拟器的配置方法,以及GeekOS项目中的具体要求。 根据引用[3]中的信息,Bochs的配置文件类似于BIOS设置,需要指定硬件参数和启动顺序。用户可能已经安装了Bochs,但需要针对project0进行配置。接下来,我需要确定正确的配置内容,确保模拟器能够正确加载GeekOS内核。 然后,引用[2]提到在项目0中需要修改.bochsrc文件,但具体步骤可能没有详细说明。用户可能需要知道在哪里创建这个文件,如何编写配置选项,比如设置硬盘映像、内存大小、启动设备等。 另外,用户可能遇到的问题包括路径设置错误、配置语法不正确,或者启动顺序不对。需要提醒用户检查路径是否正确,特别是如果项目文件存放在特定目录下,比如/home或者用户自定义的目录。 还需要考虑用户的操作系统环境,比如是否在Linux下工作,使用哪些命令来创建和编辑文件。例如,使用touch创建文件,nano或vim编辑文件。 可能还需要引用项目文档中的示例配置,确保用户使用的选项与GeekOS的要求一致,比如megs、romimage、vgaromimage、boot等参数。 最后,验证步骤很重要,用户运行Bochs后如果出现黑屏或错误,需要检查配置文件是否正确,日志信息是否有提示错误的地方。例如,引用[3]提到配置错误可能导致无法启动,所以需要指导用户如何排查这些问题。</think>### 创建或编辑 GeekOS Project0 的 Bochs 配置文件 #### 1. **配置文件位置** - Bochs 模拟器通过读取 `.bochsrc` 文件完成硬件配置。该文件通常位于项目根目录下(例如 `/geekos/project0`)[^3]。 - 若文件不存在,需手动创建;若已存在,可直接修改。 #### 2. **配置文件内容** 以下是针对 GeekOS Project0 的典型配置模板: ```ini # Bochs 基础配置 megs: 32 # 分配32MB内存 romimage: file=$BXSHARE/BIOS-bochs-latest, address=0xf0000 vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest floppy_bootsig_check: disabled=0 # 硬盘配置 ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 ata0-master: type=disk, path="hdd.img", mode=flat, cylinders=40, heads=16, spt=63 # 启动设置 boot: disk # 从硬盘启动 log: bochslog.txt # 生成日志文件 display_library: x # 使用X11图形界面 panic: action=report error: action=report info: action=report debug: action=ignore ``` #### 3. **关键参数说明** - `path="hdd.img"`:需替换为项目实际硬盘镜像路径(例如 `/project0/hdd.img`)[^2]。 - `megs: 32`:GeekOS 推荐最小内存配置。 - `boot: disk`:确保系统从包含内核的硬盘镜像启动。 #### 4. **操作步骤** - **创建文件**: ```bash touch .bochsrc nano .bochsrc # 或使用vim/其他编辑器 ``` - **验证配置**: ```bash bochs -f .bochsrc -q # -f指定配置文件,-q跳过启动菜单 ``` #### 5. **常见问题排查** - **路径错误**:若提示 `hdd.img not found`,检查镜像文件路径是否与 `path` 参数一致。 - **权限问题**:使用 `chmod` 确保镜像文件可读。 - **配置语法**:冒号后需保留空格(如 `megs: 32` 而非 `megs:32`)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值