您的当前位置:首页正文

QEMU 6.2 源代码分析之 [ 4 ] —— 内存虚拟化

2024-11-29 来源:个人技术集锦

QEMU初始化时解析 -m 参数

QEMU_OPTION_m: 用来解析 -m 参数
Qemu命令行选项“-m [size=]定义了guest物理可支持的guest物理内存最大值。

Guest OS需要的RAM是如何得到的?

如下图所示,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 OS如何读写RAM空间?

当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空间。

显示全文