• Bochs源码分析-MEM类


    因为学习需要,要看虚拟机Bochs的源代码。写随笔主要为了学习总结,其次是分享大家共同研究,大神勿喷,欢迎评论。

    手头资料:bochs源代码,下于:bochs.sourceforge.net,还有喻强写的源码分析电纸书。

    计算机系统最主要的两个部件是CPU和内存。CPU负责不断读取内存里面的指令进行工作。一块固定大小的内存条(2G)和能由很多ROM,RAM,SDRAM通过位扩展法、字扩展法共同组合而成,有的外部设备的驱动的各种特殊功能控制器也被编址到内存空间,也就是说:内存集成了很多功能,虽然同样是内存空间的地址访问,可能对应不同的设备,有着不同的处理办法。CPU对外界的访问是通过地址线和内存线,只管把要访问的地址交与总线,具体是有南北桥这样的设备,进行地址到各种不同设备、处理办法之间的转换。Bochs需要模拟整个内存空间,就要相应的申请相同大小的变量来模拟器状态的变化,具体上Bochs把内存分成三块主存SDRAM,256KB ROM,和另外一个附加的空间(特殊功能寄存器)。具体的代码是在memory/misc_mem.cpp:init_memorty(int memsize)来实现,调用是在main函数,bx_init_hardware()中:BX_MEM(0)->init_memory(memSize);在函数中内存变量的具体申请是:alloc_vector_aligned(memsize+ BIOSROMSZ + EXROMSIZE  + 4096, BX_MEM_VECTOR_ALIGN);BX_MEM_THIS rom = &BX_MEM_THIS vector[memsize];
      BX_MEM_THIS bogus = &BX_MEM_THIS vector[memsize + BIOSROMSZ + EXROMSIZE];可以看出变量vector指向内存初始地址(表示主内存SDRAM),rom指向memsize向后的一段地址(表示ROM),bogus指向更后面一段(为特殊功能寄存器使用),分开处理,就是为了,模拟对不同的内存空间对用的具体操作和安全限制是不一样的。对于固定的体系架构(如X86)内存空间具体每部分地址空间的用途都已经设计好了,约定熟成,这样方便操作系统的开发,当然模拟机也要遵循这样的约定管理不同的地址空间,以便不加修改就能运行x86对应的操作系统。具体表现在mem类最主要的两个函数:memory/memory.cpp writePhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)和readPhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)主要工作就是对要访问的地址,按约定熟成进行划分,对应到具体的某项用途,调用相应的处理方法。其x86内存约定比如:(1m之内的内存使用)

    // 0x00000 - 0x7ffff    DOS area (512K)
    // 0x80000 - 0x9ffff    Optional fixed memory hole (128K)
    // 0xa0000 - 0xbffff    Standard PCI/ISA Video Mem / SMMRAM (128K)
    // 0xc0000 - 0xdffff    Expansion Card BIOS and Buffer Area (128K)
    // 0xe0000 - 0xeffff    Lower BIOS Area (64K)
    // 0xf0000 - 0xfffff    Upper BIOS Area (64K)

    这两个函数其实是模拟了南北桥这样设备的功能。

    因为各种外部设备可能把自己控制器的特殊功能控制器,映射到内存空间上(统一地址映射),统一管理,Bochs也是这样处理的, 具体是维持很多mem_handler链表,具体数据结构是:struct  memory_handler_struct {
      struct memory_handler_struct *next;      // 下一个的pointer,  用来构成链表
      unsigned long begin;       // 受管理的内存端开始地址
      unsigned long end;        // 受管理的内存端结束地址
     memory_handler_t read_handler ;  // 读函数
     memory_handler_t write_handler;  // 写函数
     void *read_param;
     void *write_param;
    };

    可见,当Bochs新添加一个设备时,要让它的特殊功能控制器,在内存空间申请一段空间,注册相应的mem_handler链表,说明申请空间的地址范围,和自己想要注册的回调函数。当CPU通过上面两个函数访问内存时,会首先遍历mem_handler链表,如果地址落到其中之一,就调用里面的注册函数。

    当然我上面提到的访问地址都已经是物理地址,而从软件指令使用的逻辑地址要经过逻辑地址->线性地址->物理地址,之间的转换,也就是CPU开启,分段、分页功能。主要的实现代码是在:CPU/page.cpp中,其中最主要的函数是:translate_linear(bx_address laddr, unsigned pl, unsigned rw, unsigned access_type);

    主要过程是,分别获取页目录项、页表项,获取物理页的地址,其中对每个表项会有特权级等安全方面的检测,同时还会涉及TLB数据结构的查询、更新等管理。其中TLB数据项的结构(cpu.h)

    typedef struct {
      bx_address lpf;     // linear page frame
      bx_phy_address ppf; // physical page frame
      Bit32u accessBits;  // Page Table Address for updating A & D bits
      bx_hostpageaddr_t hostPageAddr;
    } bx_TLB_entry;

    struct {    

    bx_TLB_entry entry[BX_TLB_SIZE]  BX_CPP_AlignN(16);

    } TLB;

  • 相关阅读:
    nginx.conf nginx反向代理配置文件
    linux shell date的用法
    shell find 命令 find命令报错 find: paths must precede expression:
    nginx平滑升级
    centos 6/7 tar包安装mysql 5.7
    3. Longest Substring Without Repeating Characters
    模板之类模板2
    排序之归并排序
    排序之堆排序
    排序之选择排序
  • 原文地址:https://www.cnblogs.com/zeng2013/p/3409859.html
Copyright © 2020-2023  润新知