QEMU_OPTION_m: 用来解析 -m 参数
Qemu命令行选项“-m [size=]定义了guest物理可支持的guest物理内存最大值。
如下图所示,host在给 guest分配物理内存时,流程如下:
qemu_init_board
-》create_default_memdev
-》obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM); //找到"memory-backend-ram" 对应的type
-》user_creatable_complete
-》host_memory_backend_memory_complete
-》bc->alloc(backend, &local_err)
-》ram_backend_memory_alloc
-》memory_region_init_ram_flags_nomigrate
-》qemu_ram_alloc
-》qemu_ram_alloc_internal
-》ram_block_add
-》qemu_anon_ram_alloc
-》qemu_ram_mmap
-》mmap_reserve
-》mmap(0, size, PROT_NONE, flags, fd, 0) //qemu通过mmap()为Guest OS分配2GB内存
中间会用到ram_backend_info,它的定义如下:
static const TypeInfo ram_backend_info = {
.name = TYPE_MEMORY_BACKEND_RAM, //"memory-backend-ram"
.parent = TYPE_MEMORY_BACKEND,
.class_init = ram_backend_class_init,
};
当Guest对RAM或者IO进行读写时,一定会调用 store和load汇编指令,该指令,会被TCG捕捉到,然后,进入store_helper或者load_helper中,IO空间的 MemoryRegion 是有对应的 ops 中的read/write接口的,但是对于 system ram,并没有ops,那么,各自是如何读写的呢?
store_helper //进到这个地址的时候,addr 是 GVA 地址
-》tlb_hit(tlb_addr, addr) //
-》io_writex(env, iotlbentry, mmu_idx, val, addr, retaddr, op ^ (need_swap * MO_BSWAP)) //如果是访问IO空间,调用到这里
-》haddr = (void *)((uintptr_t)addr + entry->addend); //addr是GVA,为什么加上entry->addend, 就能得到HVA 地址?另外,要注意:GPA不等于HVA
-》store_memop(haddr, val, op); //如果是RAM地址空间,haddr代表 GPA 地址,也就是 HVA 地址
-》stw_le_p(haddr, val) //哈哈,在这里,如果是系统RAM,不需要ops, 直接 memcpy
如果 访问的不是系统RAM空间,而是IO空间,则会入到 io_writex(),最终会进入下面的 mr->ops->write()接口中:
io_writex
-》access_with_adjusted_size(addr, &data, size,
mr->ops->impl.min_access_size,
mr->ops->impl.max_access_size,
memory_region_write_accessor, mr,
attrs)
-》memory_region_write_accessor
-》mr->ops->write(mr->opaque, addr, tmp, size)
因此,对于 Guest的RAM 访问,直接mempcy即可,不需要 ops() 设置的,而对于IO空间,会通过mr->ops->write()接口来读写IO空间。