---
title: KVM 架构
url: https://doc.liz6.com/linux-kernel/13-kvm-and-virtualization/01-kvm-architecture
locale: zh
area: linux-kernel
tags:
- linux-kernel
- KVM与虚拟化
date: 2026-06-30
modified: 2026-07-11
description: '覆盖: KVM 作为 Linux hypervisor → VMX/SVM 硬件虚拟化 → vCPU 生命周期 → VM exit 处理 → KVM + QEMU 协作模型 → /dev/kvm ioctl API 内核版本: 2.6.20 ~ 6.x'
---

# KVM 架构

> 覆盖: KVM 作为 Linux hypervisor → VMX/SVM 硬件虚拟化 → vCPU 生命周期 → VM exit 处理 → KVM + QEMU 协作模型 → /dev/kvm ioctl API
> 内核版本: 2.6.20 ~ 6.x

## 概述

KVM (Kernel-based Virtual Machine) 把 Linux 内核转变为一个 type-1 hypervisor——利用 Intel VMX 或 AMD SVM 硬件虚拟化扩展，让 guest 在 VMX non-root 模式下直接运行在物理 CPU 上。每个 VM 是用户态的一个 QEMU 进程，每个 vCPU 是进程中的一个线程。

## 架构分层

<svg viewBox="0 0 720 340" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="KVM 架构分层:QEMU 用户态通过 ioctl 对接内核态 KVM 模块">
  <defs>
    <marker id="kvmah1" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker>
  </defs>
  <rect width="720" height="340" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">KVM 架构分层:QEMU 用户态 · 内核态 KVM</text>

  <rect x="60" y="50" width="600" height="28" rx="6" fill="#4f46e5"/>
  <text x="360" y="69" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">QEMU(用户态)</text>

  <rect x="60" y="88" width="190" height="50" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="155" y="108" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">设备模拟</text>
  <text x="155" y="125" text-anchor="middle" font-size="10.5" fill="#4f46e5">virtio / VGA / 存储 / 网络</text>

  <rect x="265" y="88" width="190" height="50" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="360" y="108" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">虚拟机管理</text>
  <text x="360" y="125" text-anchor="middle" font-size="10.5" fill="#4f46e5">live migration / snapshot</text>

  <rect x="470" y="88" width="190" height="50" rx="6" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="565" y="108" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">KVM ioctl</text>
  <text x="565" y="125" text-anchor="middle" font-size="10.5" fill="#4f46e5">/dev/kvm</text>

  <line x1="360" y1="140" x2="360" y2="176" stroke="#475569" stroke-width="1.8" marker-end="url(#kvmah1)"/>
  <text x="380" y="162" font-size="11" fill="#64748b">ioctl 系统调用穿透用户态 → 内核态</text>

  <rect x="60" y="180" width="600" height="28" rx="6" fill="#0d9488"/>
  <text x="360" y="199" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">内核(KVM)</text>

  <rect x="60" y="218" width="190" height="50" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="155" y="238" text-anchor="middle" font-size="12" font-weight="700" fill="#115e59">kvm.ko</text>
  <text x="155" y="255" text-anchor="middle" font-size="10.5" fill="#0f766e">架构无关 core</text>

  <rect x="265" y="218" width="190" height="50" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="360" y="238" text-anchor="middle" font-size="12" font-weight="700" fill="#115e59">kvm-intel.ko</text>
  <text x="360" y="255" text-anchor="middle" font-size="10.5" fill="#0f766e">VMX 支持</text>

  <rect x="470" y="218" width="190" height="50" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="565" y="238" text-anchor="middle" font-size="12" font-weight="700" fill="#115e59">kvm-amd.ko</text>
  <text x="565" y="255" text-anchor="middle" font-size="10.5" fill="#0f766e">SVM 支持</text>

  <rect x="60" y="284" width="600" height="44" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="76" y="304" font-size="12.5" fill="#3730a3">QEMU 只通过 /dev/kvm ioctl 与内核对话,不直接碰虚拟化寄存器;</text>
  <text x="76" y="321" font-size="12.5" fill="#3730a3">kvm.ko 是架构无关核心,kvm-intel.ko / kvm-amd.ko 分别对接 VMX / SVM。</text>
</svg>

## VM Entry / VM Exit

<svg viewBox="0 0 720 400" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="VM Entry / VM Exit:guest 运行与内核处理 exit 的循环">
  <defs>
    <marker id="kvmah2" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker>
  </defs>
  <rect width="720" height="400" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">VM Entry / VM Exit:guest 运行与内核处理的循环</text>

  <rect x="50" y="70" width="230" height="130" rx="10" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="165" y="98" text-anchor="middle" font-size="14" font-weight="700" fill="#115e59">Guest 运行</text>
  <text x="165" y="122" text-anchor="middle" font-size="11" fill="#0f766e">VMLAUNCH(VMX) / VMRUN(SVM)</text>
  <text x="165" y="140" text-anchor="middle" font-size="11" fill="#0f766e">→ 进入 VMX non-root 模式</text>
  <text x="165" y="158" text-anchor="middle" font-size="11" fill="#0f766e">guest 直接执行在物理 CPU 上</text>
  <text x="165" y="176" text-anchor="middle" font-size="11" fill="#14b8a6">(直到触发 VM exit)</text>

  <rect x="430" y="70" width="240" height="250" rx="10" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="550" y="98" text-anchor="middle" font-size="14" font-weight="700" fill="#3730a3">VM Exit(root 模式)</text>
  <text x="550" y="118" text-anchor="middle" font-size="10.5" fill="#4f46e5">guest 执行敏感指令</text>
  <text x="550" y="132" text-anchor="middle" font-size="10" fill="#4f46e5">(HLT / IO / EPT violation …)</text>
  <line x1="445" y1="142" x2="655" y2="142" stroke="#c7d2fe" stroke-width="1"/>
  <text x="445" y="158" font-size="10.5" font-weight="700" fill="#3730a3">KVM 读 exit reason 分发处理:</text>
  <text x="445" y="178" font-size="10.5" fill="#4338ca">IO_INSTRUCTION → 模拟 IO 指令</text>
  <text x="445" y="200" font-size="10.5" fill="#4338ca">EPT_VIOLATION → 处理 guest 页表变更</text>
  <text x="445" y="222" font-size="10.5" fill="#4338ca">CPUID → 模拟 CPUID</text>
  <text x="445" y="244" font-size="10.5" fill="#4338ca">HLT → idle injection</text>
  <text x="445" y="266" font-size="10.5" fill="#4338ca">MSR_READ/WRITE → 模拟 MSR 访问</text>
  <text x="445" y="292" font-size="10.5" font-weight="700" fill="#3730a3">处理完 → VMRESUME 回到 guest</text>

  <line x1="280" y1="110" x2="426" y2="110" stroke="#475569" stroke-width="1.6" marker-end="url(#kvmah2)"/>
  <text x="354" y="100" text-anchor="middle" font-size="10.5" fill="#64748b">敏感指令触发 → 退出到 root</text>
  <line x1="426" y1="170" x2="280" y2="170" stroke="#475569" stroke-width="1.6" marker-end="url(#kvmah2)"/>
  <text x="354" y="185" text-anchor="middle" font-size="10.5" fill="#64748b">处理完 → VMRESUME 回到 guest</text>

  <rect x="50" y="340" width="620" height="50" rx="8" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="66" y="360" font-size="12.5" fill="#115e59">VM Exit 是 KVM 的核心循环:guest 尝试敏感操作 → 陷入内核 → KVM 软件模拟 → VMRESUME 恢复;</text>
  <text x="66" y="378" font-size="12.5" fill="#115e59">读 exit reason 后按类型分发处理,是虚拟化里 guest/host 切换开销的主要来源。</text>
</svg>

## vCPU 线程模型

```c
// 每个 vCPU = 一个 QEMU 线程, 执行循环:
while (running) {
    ioctl(vcpu_fd, KVM_RUN, 0);
    // 返回: VM exit
    switch (vcpu->kvm_run->exit_reason) {
    case KVM_EXIT_IO:       handle_io(vcpu);       break;
    case KVM_EXIT_MMIO:     handle_mmio(vcpu);     break;
    case KVM_EXIT_IRQ_WINDOW_OPEN: inject_interrupt(vcpu); break;
    // ...
    }
}
```

### Scheduler 交互

```c
// KVM 通过 preempt notifier 知道 vCPU 何时被抢占:
// → kvm_sched_out(): vCPU 被调度出去了
// → kvm_sched_in():  vCPU 获得了 CPU
// 用于: steal time accounting, TSC 偏移计算
```

## /dev/kvm 接口

```c
// 创建 VM:
int kvm_fd = open("/dev/kvm", O_RDWR);
int vm_fd = ioctl(kvm_fd, KVM_CREATE_VM, 0);

// 注册内存 (guest 物理地址空间):
struct kvm_userspace_memory_region region = {
    .slot = 0, .guest_phys_addr = 0, .memory_size = 1ULL << 30,
    .userspace_addr = (__u64)guest_ram_ptr, .flags = 0 };
ioctl(vm_fd, KVM_SET_USER_MEMORY_REGION, &region);

// 创建 vCPU:
int vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, cpu_id);

// 获取 KVM 版本/能力:
int version = ioctl(kvm_fd, KVM_GET_API_VERSION, 0);
struct kvm_cpuid2 cpuid = { .nent = N }; 
ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, &cpuid);
```

## 中断注入

```c
// KVM 将中断注入给 guest:
//   1. 设置 VMCS (VMX) 或 VMCB (SVM) 的中断信息字段
//   2. 设置 interrupt window → VM entry 后 guest 立即响应
//   3. 如果 vCPU 没在跑 (被调度出去) → 设 kick flags

// 中断来源:
//   - virtio 设备 (msix)
//   - 模拟设备 (8259A PIC, IOAPIC)
//   - IPI (guest 内多 vCPU)
//   - timer (hrtimer→KVM timer)
```

## 参考

- **源码**: `virt/kvm/kvm_main.c` (核心), `arch/x86/kvm/vmx/vmx.c` (Intel VMX), `arch/x86/kvm/svm/svm.c` (AMD SVM)
- **内核文档**: `Documentation/virt/kvm/`
- **LWN**: "KVM: the Linux virtual machine monitor"

*关键词: KVM, VMX, SVM, vCPU, VM exit, VMLAUNCH, VMRESUME, /dev/kvm, KVM_RUN, interrupt injection*
