接前一篇文章: QEMU源码全解析 —— 内存虚拟化(6)
本文内容参考:
《 QEMU /KVM源码解析与应用》 —— 李强,机械工业出版社
浅谈QEMU Memory Region 与 Address Space
特此致谢!
2. QEMU虚拟机内存初始化
上一回讲到,内存作为虚拟机的基础部分,其初始化除了在pc_init1函数中进行部分工作外,在cpu_exec_init_all函数中也进行了一部分初始化工作。再来回顾一下,cpu_exec_init_all函数在softmmu/physmem.c中,代码如下:
void cpu_exec_init_all(void)
{
qemu_mutex_init(&ram_list.mutex);
/* The data structures we set up here depend on knowing the page size,
* so no more changes can be made after this point.
* In an ideal world, nothing we did before we had finished the
* machine setup would care about the target page size, and we could
* do this much later, rather than requiring board models to state
* up front what their requirements are.
*/
finalize_target_page_bits();
io_mem_init();
memory_map_init();
qemu_mutex_init(&map_client_list_lock);
}
cpu_exec_init_all函数中有两个函数的调用与内存相关:io_mem_init()和memory_map_init()。
无论是io_mem_init函数还是memory_map_init函数,其底层都直接或间接调用了memory_region_init函数。
本回就来看一下memory_region_init函数的源码,以对于相关的几个数据结构体进行进一步综合掌握。
memory_region_init函数在softmmu\memory.c中,代码如下:
void memory_region_init(MemoryRegion *mr,
Object *owner,
const char *name,
uint64_t size)
{
object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
memory_region_do_init(mr, owner, name, size);
}
上一回讲过:在memory_map_init函数中会创建两个AddressSpace:address_space_memory和address_space_io,分别用来表示虚拟机的内存地址空间和I/O地址空间,其对应根MemoryRegion分别是system_memory和system_io。
也就是说,两次调用memory_region_init函数,传入的实参分别是system_memory(虚拟机的内存地址空间对应的根MemoryRegion)和system_io(虚拟机的I/O地址空间对应的根MemoryRegion)。
回到memory_region_init函数代码。
void memory_region_init(MemoryRegion *mr,
Object *owner,
const char *name,
uint64_t size)
{
object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
memory_region_do_init(mr, owner, name, size);
}
memory_region_init函数一共调用了两个函数,一个一个来看。
1)object_initialize函数
代码片段如下:
object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
object_initialize函数在qom\object.c中,代码如下:
void object_initialize(void *data, size_t size, const char *typename)
{
TypeImpl *type = type_get_by_name(typename);
#ifdef CONFIG_MODULES
if (!type) {
int rv = module_load_qom(typename, &error_fatal);
if (rv > 0) {
type = type_get_by_name(typename);
} else {
error_report("missing object type '%s'", typename);
exit(1);
}
}
#endif
if (!type) {
error_report("missing object type '%s'", typename);
abort();
}
object_initialize_with_type(data, size, type);
}
object_initialize函数是与QOM(QEMU Object Model)密切相关的,关于这部分内容会单独放在一个专题中讲解,因此这里不做深入解析。
TYPE_MEMORY_REGION宏在include\exec\memory.h中定义,如下:
#define TYPE_MEMORY_REGION "memory-region"
2)memory_region_do_init函数
代码片段如下:
memory_region_do_init(mr, owner, name, size);
memory_region_do_init函数也在softmmu\memory.c中,代码如下:
static void memory_region_do_init(MemoryRegion *mr,
Object *owner,
const char *name,
uint64_t size)
{
mr->size = int128_make64(size);
if (size == UINT64_MAX) {
mr->size = int128_2_64();
}
mr->name = g_strdup(name);
mr->owner = owner;
mr->dev = (DeviceState *) object_dynamic_cast(mr->owner, TYPE_DEVICE);
mr->ram_block = NULL;
if (name) {
char *escaped_name = memory_region_escape_name(name);
char *name_array = g_strdup_printf("%s[*]", escaped_name);
if (!owner) {
owner = container_get(qdev_get_machine(), "/unattached");
}
object_property_add_child(owner, name_array, OBJECT(mr));
object_unref(OBJECT(mr));
g_free(name_array);
g_free(escaped_name);
}
}
更多内容请看下回。