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_mmu3k,translate_v2p_mmu3k在memory_mips.cc中生成?
#define TRANSLATE_ADDRESS translate_v2p_mmu3k #define V2P_MMU3K #include "memory_mips_v2p.cc" #undef TRANSLATE_ADDRESS #undef V2P_MMU3K int 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<mem->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_RW memory_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); }
Gexmul虚拟机内存空间原理简述
时间: 2024-10-04 08:45:29