QEMU源码全解析 —— 内存虚拟化(12)

接前一篇文章: QEMU源码全解析 —— 内存虚拟化(11)

本文内容参考:

《趣谈 Linux操作系统 》 —— 刘超, 极客时间

QEMU /KVM源码解析与应用》 —— 李强,机械工业出版社

QEMU内存管理模型

浅谈QEMU Memory Region 与 Address Space

【QEMU系统分析之实例篇(七)】-CSDN博客

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对应的平坦视角。

7085e764c0cd4e34bd20979bf145be65.png

而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。对于该函数的详细解析,请看下回。