Skip to content

QEMU/KVM

KVM

KVM(Kernel-based Virtual Machine) 是运行在 Linux 内核中的硬件虚拟化管理模块,用户态的程序可通过 KVM 暴露的用户态接口使用硬件虚拟化的功能。在用户态程序运行之前,KVM 通过 Linux 在 /dev/kvm 设备文件交互,以调用内核态 KVM 的 API。KVM 收到 API 调用后,在 Linux 内核中创建相应的虚拟机、vCPU、第二阶段页表等数据结构。用户态程序调用了 KVM_SET_USER_MEMORY_REGION API 后,KVM 据此建立了虚拟机的第二阶段页表。在此程序调用 KVM_RUN API 时,KVM 使用 eret 指令找到某 vCPU 相关的代码位置开始执行。

KVM 与 QEMU

可以将 KVM 理解为硬件虚拟化机制的驱动程序。而如何使用这个驱动程序,则需要由用户态的应用程序来决定。也就是说,KVM 决定使用硬件虚拟化的“机制”,而用户态程序提供硬件虚拟化的使用“策略”。

运行在用户态的 QEMU 是一个进程,对应于一个虚拟机。在 QEMU 进程内,每一个用户态线程负责运行虚拟机内的一个 vCPU。具体而言,一个 QEMU 用户态线程会管理一个对应的 vCPU 的所有寄存器状态,当次线程调用 KVM_RUN 接口时,KVM 会将对应的 vCPU 的所有寄存器状态加载到硬件中,并开始执行。对于 Linux 内核而言,调度用户态线程相当于调度其对应的 vCPU。这种方式非常巧妙地复用了 Linux 的调度机制,因此不需要为虚拟化重新实现一套新的调度算法。

作为一个用户态程序,QEMU 拥有自己的虚拟地址空间;但作为用户态虚拟机监控器,它还需要为虚拟机分配客户物理内存。为了支撑虚拟机的运行,QEMU 会使用 mmap 系统调用分配一大段连续的内存区域,并将此区域作为虚拟机的客户物理地址空间。此外,因为虚拟机内存本质上属于 QEMU 进程内部的内存,因此 QEMU 可以直接读写虚拟机的内存数据。这不仅可以加速 I/O 虚拟化的数据传输(例如 QEMU 可以直接读取虚拟机指定的 DMA 内存区域),还可以方便 QEMU 实现虚拟机热迁移等功能。

记录原理、连接知识、积累实践。