博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Gexmul虚拟机内存空间原理简述
阅读量:6272 次
发布时间:2019-06-22

本文共 4988 字,大约阅读时间需要 16 分钟。

hot3.png

Gxemul将内存空间分为两部分管理,一部分是物理内存,地址分配到0x00000000,另一部分是device的地址,注册device的时候由device自己指定空间

1 创建物理内存

memory.cc memory_new{    初始化物理内存参数    mem->physical_max = physical_max;    mem->dev_dyntrans_alignment = 4095;    创建物理内存    mem->pagetable = (unsigned char *) mmap(NULL, s,	    PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);	if (mem->pagetable == NULL) {		CHECK_ALLOCATION(mem->pagetable = malloc(s));		memset(mem->pagetable, 0, s);	}        初始化device可占用的地址空间    mem->mmap_dev_minaddr = 0xffffffffffffffffULL;    mem->mmap_dev_maxaddr = 0;}

2 内存地址转换

    cpu_new时已经将v2p_translate设置为translate_v2p_mmu3ktranslate_v2p_mmu3kmemory_mips.cc中生成

#define TRANSLATE_ADDRESS        translate_v2p_mmu3k#define  V2P_MMU3K#include "memory_mips_v2p.cc"#undef TRANSLATE_ADDRESS#undef V2P_MMU3Kint TRANSLATE_ADDRESS(struct cpu *cpu, uint64_t vaddr, uint64_t *return_paddr, int flags){           //获取cpu所在状态           cp0 = cpu->cd.mips.coproc[0];           status = cp0->reg[COP0_STATUS];           if (status & MIPS1_SR_KU_CUR)                         ksu = KSU_USER;           else                         ksu = KSU_KERNEL;        //32bit判断        if (x_64 == 0) {            vaddr = (int32_t) vaddr;            xuseg_top = 0x7fffffff;            /*  (Actually useg for R2000/R3000)  */           }         if (vaddr <= xuseg_top) {            KUSEG: 低2G必须使用MMU            use_tlb = 1;           } else {               if (ksu == KSU_KERNEL) {                内核态,直接取低512M                   /*  kseg0, kseg1:  */                   if (vaddr >= (uint64_t)0xffffffff80000000ULL &&                       vaddr <= (uint64_t)0xffffffffbfffffffULL) {                           *return_paddr = vaddr & 0x1fffffff;                           return 2;                   }                   /*  other segments:  KSEG2 必须使用MMU*/                   use_tlb = 1;               } else {                        不是内核态,但访问了对应的地址,将会产生excption                        use_tlb = 0;                 }           }           if (use_tlb)           {                使用MMU           }                      //内存地址excption           mips_cpu_exception(cpu, exccode, tlb_refill, vaddr, 0, vaddr_vpn2, vaddr_asid, x_64);}

3 注册device占用内存空间

device需要内存空间用于安排自己的寄存器和FIFO等

memory.cc memory_device_register{    //查找注册的地址是否可用    for (i=0; i
n_mmapped_devices; i++) { if (i == 0 && baseaddr + len <= mem->devices[i].baseaddr) newi = i; if (i > 0 && baseaddr + len <= mem->devices[i].baseaddr &&     baseaddr >= mem->devices[i-1].endaddr) newi = i; if (i == mem->n_mmapped_devices - 1 &&     baseaddr >= mem->devices[i].endaddr) newi = i + 1; /*  If this is not colliding with device i, then continue:  */ if (baseaddr + len <= mem->devices[i].baseaddr) continue; if (baseaddr >= mem->devices[i].endaddr) continue; fatal("\nERROR! \"%s\" collides with device %i (\"%s\")!\n",     device_name, i, mem->devices[i].name); exit(1); }    注册device内存空间信息及访问函数    mem->devices[newi].baseaddr = baseaddr;    mem->devices[newi].endaddr = baseaddr + len;    mem->devices[newi].length = len;    mem->devices[newi].flags = flags;    mem->devices[newi].dyntrans_data = dyntrans_data;    mem->devices[newi].dyntrans_write_low = (uint64_t)-1;    mem->devices[newi].dyntrans_write_high = 0;    mem->devices[newi].f = f;    mem->devices[newi].extra = extra;    mem->devices[newi].m = NULL;        //更新device内存空间范围    if (baseaddr < mem->mmap_dev_minaddr) mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment;    if (baseaddr + len > mem->mmap_dev_maxaddr) mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) | mem->dev_dyntrans_alignment) + 1;}

4 访问内存

mips_memory_rw generate_tail.c 自动生成的tmp_mips_tail.c结合mempry_rw.cc产生:

#define MEMORY_RW mips_memory_rw#define MEM_MIPS#include "memory_rw.cc"#undef MEM_MIPS#undef MEMORY_RWmemory_rw.cc  int MEMORY_RW(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int misc_flags){    计算出要访问的物理地址    cpu->translate_v2p(cpu, vaddr, &paddr,        (writeflag? FLAG_WRITEFLAG : 0) +        (no_exceptions? FLAG_NOEXCEPTIONS : 0)         + (misc_flags & MEMORY_USER_ACCESS)         + (cache==CACHE_INSTRUCTION? FLAG_INSTR : 0))         if (paddr >= mem->mmap_dev_minaddr && paddr < mem->mmap_dev_maxaddr)         {            属于device的地址,在device中寻找,device地址在memory_device_register已经注册,找到后使用注册的device access函数访问         }                  if (paddr >= mem->physical_max)         {            不在物理内存中,属于PROM不做处理            if ((paddr & 0xffffc00000ULL) == 0x1fc00000) {                /*  Ok, this is PROM stuff  */            }         }        //转换为虚拟机中的内存地址        memblock = memory_paddr_to_hostaddr(mem, paddr & ~offset_mask, writeflag);                获取对应数据,并做读写操作        cpu->update_translation_table        cpu->invalidate_code_translation        if (writeflag == MEM_WRITE)           memcpy(memblock + offset, data, len);        else           memcpy(data, memblock + offset, len);}

转载于:https://my.oschina.net/lgl88911/blog/287978

你可能感兴趣的文章
[React] Override webpack config for create-react-app without ejection
查看>>
检索 COM 类工厂中 CLSID 为{00024500-0000-0000-C000-000000000046} 的组件时失败,原因是出现以下错误: 80070005。...
查看>>
测试java的父子类化
查看>>
HDOJ 1008
查看>>
安装thrift出现的一些问题
查看>>
makefile编写---单个子目录编译模板
查看>>
Oracle DB_LINK如何使用
查看>>
cv resource
查看>>
关于加快INSERT语句执行速度和HINT /*+ append */及/*+ append nologging */的使用
查看>>
JDK源代码学习系列07----Stack
查看>>
firefox
查看>>
PS批处理的使用
查看>>
七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 【转】
查看>>
Quartz作业调度框架
查看>>
腾讯云下安装 nodejs + 实现 Nginx 反向代理
查看>>
js-权威指南学习笔记13
查看>>
《超级时间整理术》晨读笔记
查看>>
Spring Boot 2.0(二):Spring Boot 2.0尝鲜-动态 Banner
查看>>
Delphi IdTCPClient IdTCPServer 点对点传送文件
查看>>
Delphi中使用ActiveX的一些心得
查看>>