首页 > 代码库 > Gexmul虚拟机内存空间原理简述

Gexmul虚拟机内存空间原理简述

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