接前一篇文章: QEMU源码全解析 —— 内存虚拟化(11)
本文内容参考:
《 QEMU /KVM源码解析与应用》 —— 李强,机械工业出版社
浅谈QEMU Memory Region 与 Address Space
QEMU内存分析(一):内存虚拟化关键结构体 - Edver - 博客园
特此致谢!
2. QEMU虚拟机内存初始化
上一回讲到,虚拟机内存的平坦化以AddressSpace为单位,也就是以AddressSpace的根MemoryRegion为起点,将其所表示的内存拓扑的无环图结构变为平坦模式。具体的实现函数是address_space_update_topology和其中的generate_memory_topology,两个均在softmmu/memory.c中,代码如下:
static void address_space_update_topology(AddressSpace *as)
{
MemoryRegion *physmr = memory_region_get_flatview_root(as->root);
flatviews_init();
if (!g_hash_table_lookup(flat_views, physmr)) {
generate_memory_topology(physmr);
}
address_space_set_flatview(as);
}
/* Render a memory topology into a list of disjoint absolute ranges. */
static FlatView *generate_memory_topology(MemoryRegion *mr)
{
int i;
FlatView *view;
view = flatview_new(mr);
if (mr) {
render_memory_region(view, mr, int128_zero(),
addrrange_make(int128_zero(), int128_2_64()),
false, false);
}
flatview_simplify(view);
view->dispatch = address_space_dispatch_new(view);
for (i = 0; i < view->nr; i++) {
MemoryRegionSection mrs =
section_from_flat_range(&view->ranges[i], view);
flatview_add_to_dispatch(view, &mrs);
}
address_space_dispatch_compact(view->dispatch);
g_hash_table_replace(flat_views, mr, view);
return view;
}
从代码层面概括来讲,虚拟机内存的平坦化过程是将AddressSpace中的根MemoryRegion表示的虚拟机内存地址空间转变成一个平坦的线性地址空间。每一段线性地址空间的属性和其所属的MemoryRegion都一致,每一段线性空间与虚拟机的物理地址空间都相互关联。
虚拟机内存的平坦化 以AddressSpace为单位 ,也就是 以AddressSpace的根MemoryRegion为起点 ,将其所表示的内存拓扑的无环图变成平坦模式。
前文已讲过,AddressSpace结构体中有一个类型为FlatView的current_map成员,其用来表示该AddressSpace对应的平坦视角。
而MemoryRegion展开之后的内存拓扑由FlatRange表示。FlatRange结构的定义在include/exec/memory.h中,代码如下:
typedef struct FlatRange FlatRange;
struct FlatRange在softmmu/memory.c中,代码如下:
/* Range of memory in the global map. Addresses are absolute. */
struct FlatRange {
MemoryRegion *mr;
hwaddr offset_in_region;
AddrRange addr;
uint8_t dirty_log_mask;
bool romd_mode;
bool readonly;
bool nonvolatile;
};
每一个FlatRange表示一段AddressSpace中的一段空间。
由于AddressSpace不是直接与FlatRange打交道的,而是经过FlatView,因此在此也给出FlagView的定义,在include/exec/memory.h中,如下:
/* Flattened global view of current active memory hierarchy. Kept in sorted
* order.
*/
struct FlatView {
struct rcu_head rcu;
unsigned ref;
FlatRange *ranges;
unsigned nr;
unsigned nr_allocated;
struct AddressSpaceDispatch *dispatch;
MemoryRegion *root;
};
struct FlagView的成员中:
- unsigned nr:表示FlatRange的个数。
- unsigned nr_allocated:表示已经分配的FlatRange个数。
- FlatRange *ranges:指向分配的FlatRange数组。
- unsigned ref:引用计数,当为0时就销毁。
struct FlatRange的成员中:
- MemoryRegion mr:表示对应的MemoryRegion。
- hwaddr offset_in_region:表示该FlatRange在MemoryRegion中的偏移。
- AddrRange addr:表示本FlatRange所代表的区间,包括地址和大小。
/* Range of memory in the global map. Addresses are absolute. */
struct FlatRange {
MemoryRegion *mr;
hwaddr offset_in_region;
AddrRange addr;
uint8_t dirty_log_mask;
bool romd_mode;
bool readonly;
bool nonvolatile;
};
FlatView与FlatRange的关系如下图所示:
generate_memory_topology函数就是要生成这样一个FlatView。对于该函数的详细解析,请看下回。