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

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

本文内容参考:

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

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

QEMU内存管理模型

浅谈QEMU Memory Region 与 Address Space

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

特此致谢!

2. QEMU虚拟机内存初始化

上一回沿着以下代码路径:

qemu_init()

---> qemu_create_machine()

---> cpu_exec_init_all()

---> memory_map_init()

---> address_space_init()

---> address_space_update_topology()

串讲了一遍cpu_exec_init_all()的流程。但是其中还有一些内容讲得并不细致、有些甚至没有讲到,本回就对这些内容进行精讲。

首当其冲地,要讲一下地址空间(AddressSpace)中与树形结构(MemoryRegion)并列的“平面”结构(FlatView)两者之间的转换,也可以说是讲一下虚拟机内存平坦化过程。

前文提到过,之所以要有两种表示同一事物的结构是因为:

树形内存结构更便于管理;而平的内存结构则更方便与内核通信,以请求物理内存。虽然操作系统内核中也是使用树形结构来表示内存区域的,但是用户态向内核申请内存的时候,会按照平的、连续的模式进行申请。由于QEMU在用户态,因此需要做这样一个转换。

QEMU中的ioctl(KVM_SET_USER_MEMORY_REGION)接口(参见accel/kvm/kvm-all.c的kvm_set_user_memory_region函数中的代码:kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);)用来设置QEMU虚拟地址与虚拟机物理地址的对应关系,这是平坦的。但是,QEMU是以AddressSpace根MemoryRegion为起始的树状结构表示虚拟机的内存的。这就需要将树状结构转换为平坦结构,即虚拟机内存的平坦化。

7085e764c0cd4e34bd20979bf145be65.png

虚拟机内存的平坦化过程指的是,将AddressSpace根MemoryRegion表示的树形虚拟机内存地址空间转换成一个平坦的线性地址空间。每一段线性地址空间的属性与其所属的MemoryRegion都一致,每一段线性地址空间与虚拟机的物理地址空间都相互关联。

虚拟机内存的平坦化以AddressSpace为单位,也就是以AddressSpace的根MemoryRegion为起点,将其所表示的内存拓扑的无环图结构变为平坦模式。表示虚拟机平坦内存的数据结构已经提到过多次了,是FlatView;相关函数是前文书提到过的generate_memory_topology(参见 QEMU源码全解析 —— 内存虚拟化(8)-CSDN博客 )。

FlatView结构的定义在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;
};

更多内容请看下回。