QEMU-KVM 内存虚拟化介绍

背景

主要是背景以及内存虚拟化相关的原理

QEMU和KVM

  • QEMU-KVM的内存虚拟化由QEMU和KVM实现, KVM类似资源管理和提供者, QEMU类似资源的申请和使用者,同时QEMU从guestos角度来看是虚拟设备的提供者

整体业务流程:

  • Guest启动:QEMU 从自己的进程地址空间为Guest申请内存(用户态做内存申请)
  • QEMU调用KVM的API,将Guest的内存地址信息注册到KVM中维护 (内核态做内存管理)
  • GVA-> GPA -> HVA -> HPA 的地址转换, GPA从QEMU的虚拟地址空间中分配
  • 内存虚拟化主要维护GPA到HVA的映射

QEMU内存管理-SPT

  • 前面说到内存虚拟化主要是维护GPA到HVA的映射, 到实现层面,需要的方式是影子页表(SPT, 由KVM维护)和EPT/NTP, 影子页表通过软件实现,ETP/NPT通过硬件时间二级映射。现在基本上都是使用硬件实现。

EPT

  • 在EPT(Extended Page Table,硬件支持GPA<–>HPA)出现之前,内存虚拟化通过维护一个影子页表,VMM拦截page fault更新影子页表。
  • 有了EPT以后,Guest 的缺页在 Guest OS 内部处理,不会 VM-EXIT 到 KVM 中。地址转化基本由硬件(MMU)查页表来完成,大大提升了效率,且只需为 Guest 维护一份 EPT 页表,减少内存的开销
  • 如上图,在 Guest OS 运行时,Guest 对应的 EPT 地址被加载到 EPTP,而 Guest OS 当前运行的进程页表基址被加载到 CR3。于是在进行地址转换时,首先通过 CR3 指向的页表实现 GVA 到 GPA 的转换,再通过 EPTP 指向的 EPT 完成 GPA 到 HPA 的转换。当发生 EPT Page Fault 时,需要 VM-EXIT 到 KVM,更新 EPT。

整体技术栈

  • kvm在整个技术栈中承担硬件操作和资源管理的角色,QEMU承担提供虚拟设备的角色。

QEMU内存数据结构

  • Address Space:
  • Memory Region: QEMU中有两个全局的memory region, 分别是system_memory 和system_io, 以指针的形式存在。 Memory Region负责管理Host的内存
  • Flat View
  • Flat Range
  • Memory Region Section
  • RAMList
  • RAMBlock: RAMBlock ram_block才是真正分配了host内存的地方,如果把它直接理解成一个内存条也是非常合适的,但实际上不仅仅如此,还有设备自有内存,显存。它的主要元素就是mr,host, offset和used_length,size,addr,每一个ramblock都有一个对应的MemoryRegion。
  • KVMSlot
  • kvm_userspace_memory_region

热迁移

热迁移的机制

  • 热迁移的内存复制主要有三种机制,pre-copy, post-copy, hybrid-copy. 现在的虚拟化平台基本上都是使用pre-copy的机制

迭代复制的三个原则

  • 集中原则: 一个循环内的dirty pages小于等于50
  • 不扩散原则: 一个循环内传输的dirty pages少于新产生的,在被迁移VM的内核设置一个内存访问的监控模块,在内存pre-copy阶段,VM的一个进程在一个被调度运行周期,被限制最多执行40次内存写操作。这个措施直接限制了pre-copy过程中内存变脏的速度
  • 有限循环原则: 循环次数必须少于30, 对于每轮pre-copy的效果进行计算,如果pre-copy对于减少dirty page的效果不显著,或者循环次数超过了上限,循环会中止,进入停机拷贝阶段

迭代拷贝的6个阶段

  • 热迁移主要流程是:源端和目的端建立连接,precopy模式下,开始数据的迭代拷贝,源端暂停虚机,拷贝最后一个迭代状态数据,最后在目的端启动虚机。其中迭代拷贝分为几个阶段:
    定义在qemu\migration\savevm.h 中
#define QEMU_VM_EOF                  0x00 //表示数据传递结束
#define QEMU_VM_SECTION_START        0x01 // 第一轮数据传递开始
#define QEMU_VM_SECTION_PART         0x02 // 迭代迁移数据中
#define QEMU_VM_SECTION_END          0x03 // VM已暂停,即将进行最后一轮迁移
#define QEMU_VM_SECTION_FULL         0x04 // 内存数据迁移完成,进行其他设备状态数据迁移
#define QEMU_VM_SUBSECTION           0x05 // 其他设备的状态迁移
(完)