KVM 通过 /dev/kvm 暴露 Linux 硬件虚拟化。KVM 提供内核执行机制,而 QEMU 等虚拟机监控器则构建并运行完整的客户机。
职责划分 #
KVM 尽可能使用 Intel VT-x、AMD-V、Arm 虚拟化扩展或相应的主机设施直接执行客户机指令。内核代码管理 vCPU 状态、第二阶段内存转换、中断传递、定时器,以及客户机和主机执行之间的切换。KVM 有意不提供完整的固件和设备模型。
QEMU 提供该机器模型:固件接口、PCI 拓扑、存储和网络控制器、显示和输入设备、映像后端、迁移,以及通过 QMP 进行管理。使用 -accel kvm 时,QEMU 将加速的 CPU 执行委托给 KVM;没有加速器时,它可以改用 TCG 指令翻译器。QEMU 支持的选项仍然特定于机器和架构。
客户机内存和内存槽 #
QEMU 首先保留由匿名内存、memfd、文件或大页支持的主机虚拟内存。随后,它使用
KVM_SET_USER_MEMORY_REGION 将该地址空间的一部分注册到 VM 文件描述符。每个区域描述:
- 槽编号和标志;
- 客户机物理基址和大小;以及
- 支持该槽的用户空间虚拟地址。
将槽大小设为零会移除该槽。槽描述的是映射,而不是分配客户机 RAM,因此在 KVM 使用支持映射期间,用户空间必须保留该映射。可选的脏页日志会记录写入,以协调迁移和快照。
客户机内存引用可能涉及两次转换。客户机页表将客户机虚拟地址转换为客户机物理地址;然后 KVM 和 MMU 硬件将该地址转换为与已注册用户空间映射对应的主机物理页。Intel 将硬件第二阶段称为 EPT,AMD 称为 NPT。KVM 处理缺失或无效的第二阶段映射,并且当访问目标是普通 RAM 时,可以在不退出到 QEMU 的情况下安装新映射。对仿真 MMIO 范围的访问则会导致退出或内核中的设备操作。
NUMA 放置、透明或显式大页、交换和内存过量分配会影响延迟,但不会改变客户机可见的地址模型。设备直通会增加 DMA 映射;因此 VFIO 依赖 IOMMU 和隔离边界,不能暴露无关的主机设备或内存。
/dev/kvm 生命周期
#
稳定的 KVM 用户空间 ABI 按文件描述符类型组织:
- 打开
/dev/kvm,然后要求KVM_GET_API_VERSION返回KVM_API_VERSION(当前为 12)。使用KVM_CHECK_EXTENSION查询可选行为,而不要比较内核版本。 - 在系统描述符上发出
KVM_CREATE_VM。返回的 VM 描述符开始时没有 RAM 和 vCPU。 - 注册内存槽,并在需要时创建架构的中断控制器和其他内核设备。
- 在 VM 描述符上发出
KVM_CREATE_VCPU。使用KVM_GET_VCPU_MMAP_SIZE,然后映射 vCPU 描述符共享的struct kvm_run区域。 - 配置 CPU 模型和初始寄存器状态,然后从 vCPU 的主机线程执行
KVM_RUN。
VM 和设备 ioctl 必须遵循 KVM API 记录的进程和线程限制。VM 的生命周期取决于其文件描述符的引用,而不是创建它的进程生命周期;因此,通过 fork 继承或通过 dup 创建的意外引用可能保留 VM 资源。
虚拟 CPU、退出和中断 #
每个 vCPU 都有 KVM 描述符,并且通常对应一个 QEMU 线程。KVM_RUN 进入客户机模式,
并在用户空间必须执行操作、信号中断主机线程或发生退出条件时返回。QEMU 检查
kvm_run.exit_reason,处理端口 I/O、MMIO、关机或调试事件等退出,然后再次调用
KVM_RUN。KVM 可以完全在内核中虚拟化的指令不需要用户空间退出。
中断可以通过用户空间仿真控制器或内核中的 irqchip 进入。KVM_IRQ_LINE、MSI 路由和
irqfd 将设备事件连接到客户机中断;ioeventfd 允许选定的客户机 MMIO 或 PIO 写入通知 eventfd,而无需通过主仿真循环往返。客户机 CPU 能够接受待处理中断时,KVM 会注入该中断。
Virtio 和减少退出 #
陷阱并仿真的设备会复现硬件寄存器接口,但每次由用户空间处理的访问都要跨越 KVM 边界。Virtio 则定义半虚拟化设备和共享 virtqueue:客户机将描述符放入内存,在批量处理工作后通知主机。QEMU、内核中的 vhost 后端或 vhost-user 进程都可以处理队列。批处理、中断抑制和 irqfd/ioeventfd 可以减少退出,而设备直通可以从数据路径移除软件设备模型,但代价是更严格的 IOMMU 和迁移限制。
隔离和运维可观测性 #
对 /dev/kvm 的访问控制谁可以创建 KVM VM,但 QEMU 进程还会处理客户机控制的设备输入和主机文件。应在专用身份下运行不可信客户机,并使用 cgroup、命名空间、seccomp 以及 SELinux 或 AppArmor 约束 QEMU。减少仿真设备,保持内核、QEMU 和客户机固件更新,并将 VFIO IOMMU 组和共享内存后端视为明确的信任边界。CPU 侧信道还可能要求超线程和调度策略超越内存隔离。
基本主机检查如下:
test -r /dev/kvm && test -w /dev/kvm
ls -l /dev/kvm
lscpu | grep -i virtualizationQMP 和 libvirt 等管理层会报告客户机状态、vCPU 时间、块 I/O 和迁移进度。在主机层面,
perf kvm stat 汇总代价高昂的 KVM 退出;跟踪文件系统中的 KVM tracepoint 暴露进入、
退出、MMIO 和中断事件;/proc/PID/task 标识 QEMU vCPU 线程。Debugfs 和 tracefs
需要提升权限,并且在内核构建时未启用相关选项的情况下可能不可用。
权威接口是 KVM API 和 QEMU 系统仿真文档。
评论
在 GitHub 上阅读或评论(发表评论需要登录)