第2篇:x86 虚拟化 — VMX/VMCS 与 SVM/VMCB,VM-Entry/Exit 全解析¶
源码:
arch/x86/kvm/vmx/vmx.carch/x86/kvm/svm/svm.c| 头文件:arch/x86/include/asm/kvm_host.h
系列目录:KVM 内核源码深度解析
1. struct kvm_x86_ops:vendor 抽象层 (kvm_host.h:1762)¶
struct kvm_x86_ops 是 KVM x86 架构最核心的抽象接口,定义了 VMX (Intel) 和 SVM (AMD) 共用的操作集,定义在 arch/x86/include/asm/kvm_host.h:1762。
两个 vendor 实例:
- Intel: vt_x86_ops — arch/x86/kvm/vmx/main.c:872
- AMD: svm_x86_ops — arch/x86/kvm/svm/svm.c:5270
// arch/x86/include/asm/kvm_host.h:1762
struct kvm_x86_ops {
// ========== vCPU 生命周期 ==========
int (*vcpu_create)(struct kvm_vcpu *vcpu);
void (*vcpu_free)(struct kvm_vcpu *vcpu);
void (*vcpu_reset)(struct kvm_vcpu *vcpu, bool init_event);
// ========== vCPU 执行 ==========
fastpath_t (*vcpu_run)(struct kvm_vcpu *vcpu, u64 run_flags); // VM-Entry
int (*handle_exit)(struct kvm_vcpu *vcpu, int reason); // VM-Exit 分发
void (*handle_exit_irqoff)(struct kvm_vcpu *vcpu); // 关中断的 exit 处理
void (*request_immediate_exit)(struct kvm_vcpu *vcpu); // 请求立即退出
// ========== 寄存器虚拟化 ==========
int (*get_segment)(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
void (*set_segment)(struct kvm_vcpu *vcpu, const struct kvm_segment *var, int seg);
void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l);
void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer);
u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
// ========== MSR 虚拟化 ==========
int (*get_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr);
int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr);
int (*get_msr_feature)(struct kvm_msr_entry *entry);
// ========== 中断虚拟化 ==========
void (*inject_irq)(struct kvm_vcpu *vcpu, bool reinjected);
void (*inject_nmi)(struct kvm_vcpu *vcpu);
void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
void (*enable_irq_window)(struct kvm_vcpu *vcpu);
bool (*apic_init_signal_blocked)(struct kvm_vcpu *vcpu);
bool (*apicv_pre_state_acceptable)(struct kvm_vcpu *vcpu);
// ========== TLB / MMU ==========
int (*tlb_flush)(struct kvm_vcpu *vcpu);
int (*tlb_flush_guest)(struct kvm_vcpu *vcpu);
void (*flush_tlb_all)(struct kvm_vcpu *vcpu);
void (*flush_tlb_current)(struct kvm_vcpu *vcpu);
void (*load_mmu_pgd)(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_level);
// ========== 嵌套虚拟化 ==========
struct kvm_x86_nested_ops nested_ops;
// ========== APIC 虚拟化 ==========
bool (*has_virtual_apic)(struct kvm_vcpu *vcpu);
void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu);
void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
void (*hwapic_isr_update)(int isr);
u64 (*apic_sync_pir_to_irr)(struct kvm_vcpu *vcpu);
// ========== PMU ==========
const struct kvm_pmu_ops *pmu_ops;
// ========== VM 生命周期 ==========
int (*vm_init)(struct kvm *kvm);
void (*vm_destroy)(struct kvm *kvm);
int (*vm_move_enc_context_from)(struct kvm *kvm, unsigned int source_fd);
// ========== 安全检查 ==========
bool (*has_wbinvd_exit)(void);
int (*check_processor_compatibility)(void);
// ========== 内存加密 ==========
int (*mem_enc_ioctl)(struct kvm *kvm, void __user *argp);
int (*mem_enc_register_region)(struct kvm *kvm, struct kvm_enc_region *argp);
int (*mem_enc_unregister_region)(struct kvm *kvm, struct kvm_enc_region *argp);
};
kvm_x86_ops 使得 arch/x86/kvm/x86.c 中的通用代码可以直接调用 vendor 特定实现,而不需要 #ifdef 条件编译。
2. Intel VMX 实现¶
2.1 struct vcpu_vmx (vmx/vmx.h:200)¶
// arch/x86/kvm/vmx/vmx.h:200
struct vcpu_vmx {
struct kvm_vcpu vcpu; // 通用 vCPU (必须是第一个成员)
// VMCS 管理
struct loaded_vmcs vmcs01; // 主 VMCS (L1 guest)
struct loaded_vmcs *loaded_vmcs; // 当前使用的 VMCS 指针 (L1 或 L2)
struct loaded_vmcs *loaded_vmcs_on_cpu; // 当前 pCPU 上已加载的 VMCS
bool __launched; // 首次用 VMLAUNCH, 之后用 VMRESUME
// 嵌套虚拟化
struct nested_vmx nested;
// VPID 和 EPT
u16 vpid; // Virtual Processor ID
// Posted Interrupt
struct pi_desc pi_desc ____cacheline_aligned;
struct pi_desc *pid_table; // Posted Interrupt Descriptor
// 寄存器缓存
unsigned long host_debugctlmsr;
// MSR 自动加载
struct vmx_msrs msr_autoload;
// 统计信息
u32 exit_reason; // 上一次 VM-Exit 原因
u32 exit_intr_info; // 中断/异常信息
u32 exit_qualification;
// IRQ/NMI window
u32 idt_vectoring_info;
...
};
2.2 VMCS 布局¶
Intel VMX 使用 VMCS (Virtual Machine Control Structure) 数据结构控制 VM 切换:
┌─────────────────────────────────────┐
│ VMCS (每个 vCPU 一份) │
├─────────────────────────────────────┤
│ Host-State Area │
│ ├── CR0, CR3, CR4 │
│ ├── RIP (vmx_vmexit 入口) │
│ ├── RSP │
│ ├── CS/DS/ES/SS/FS/GS/TR selec │
│ ├── FS/GS/TR base │
│ └── MSR: EFER, SYSENTER, PAT │
├─────────────────────────────────────┤
│ Guest-State Area │
│ ├── CR0, CR3, CR4, DR7 │
│ ├── RIP, RSP, RFLAGS │
│ ├── CS/DS/ES/SS selector+base │
│ ├── LDTR, GDTR, IDTR, TR │
│ ├── MSR: EFER, SYSENTER │
│ └── Activity State │
├─────────────────────────────────────┤
│ VM-Execution Control Fields │
│ ├── Pin-based controls │
│ │ └── NMI exiting, virtual NMI│
│ ├── Processor-based controls │
│ │ ├── Primary: int window, │
│ │ │ use TSC offsetting, │
│ │ │ CR3-load exiting, ... │
│ │ └── Secondary: EPT, VPID, │
│ │ RDTSCP, XSAVES, ... │
│ └── Exception Bitmap │
├─────────────────────────────────────┤
│ VM-Exit Control Fields │
│ ├── Host address space size │
│ ├── Load MSRs on exit │
│ └── Save MSRs on exit │
├─────────────────────────────────────┤
│ VM-Entry Control Fields │
│ ├── Load MSRs on entry │
│ └── Entry to SMM control │
└─────────────────────────────────────┘
VMREAD/VMWRITE 指令用于读写 VMCS 字段。KVM 使用 vmcs_read(field) / vmcs_write(field, value) 封装。
2.3 VM-Entry: __vmx_vcpu_run (vmenter.S:47)¶
核心汇编函数 __vmx_vcpu_run 实现寄存器级别的世界切换:
// arch/x86/kvm/vmx/vmenter.S:47
SYM_FUNC_START(__vmx_vcpu_run)
// 保存 host 寄存器到栈
push %_ASM_BP
mov %_ASM_SP, %_ASM_BP
push %r15
push %r14
push %r13
push %r12
push %rbx
// 加载 guest 寄存器 (RAX, RCX, RDX, ... → VMCS)
// ...
// VMLAUNCH 或 VMRESUME
// ...
// VM-Exit 后: 保存 guest 寄存器 → VMCS, 恢复 host 寄存器
// ...
// 返回
SYM_FUNC_END(__vmx_vcpu_run)
C 层包装 vmx_vcpu_run (arch/x86/kvm/vmx/vmx.c:7515):
// arch/x86/kvm/vmx/vmx.c:7515
fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
// 1. 准备 VM-entry: 写 VMCS 各字段
vmx_vcpu_prepare(vcpu); // line ~7530
// 2. 允许进入 guest mode
kvm_guest_enter_irqoff();
// 3. 汇编 VM-Entry world switch
vmx->fail = __vmx_vcpu_run(vmx, // line 7490
(unsigned long *)&vcpu->arch.regs,
__vmx_vcpu_run_flags(vmx));
// 4. 退出 guest mode
kvm_guest_exit_irqoff();
// 5. 获取 VM-Exit reason, 尝试快手处理
vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
// 6. 如果可能, 在内核态直接处理 exit (fast path)
if (is_guest_mode(vcpu))
return EXIT_FASTPATH_NONE;
// 尝试 handle_exit_fastpath:
// - EXIT_REASON_MSR_WRITE (EXIT_FASTPATH_MSR_WRITE_12)
// - EXIT_REASON_PREEMPTION_TIMER (reschedule)
return vmx_handle_exit_fastpath(vcpu, run_flags);
}
2.4 VM-Exit 分发¶
// arch/x86/kvm/vmx/vmx.c: ~6980
static int vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
if (exit_fastpath != EXIT_FASTPATH_NONE)
return 1; // fastpath 已经处理
return kvm_vmx_exit_handlers[exit_reason](vcpu);
}
// 部分 exit handler:
static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
[EXIT_REASON_EXCEPTION_NMI] = handle_exception_nmi,
[EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt,
[EXIT_REASON_TRIPLE_FAULT] = handle_triple_fault,
[EXIT_REASON_EPT_VIOLATION] = handle_ept_violation,
[EXIT_REASON_EPT_MISCONFIG] = handle_ept_misconfig,
[EXIT_REASON_CPUID] = handle_cpuid,
[EXIT_REASON_HLT] = handle_hlt,
[EXIT_REASON_INVD] = handle_invd,
[EXIT_REASON_INVLPG] = handle_invlpg,
[EXIT_REASON_RDPMC] = handle_rdpmc,
[EXIT_REASON_VMCALL] = handle_vmcall,
[EXIT_REASON_VMCLEAR] = handle_vmclear,
[EXIT_REASON_VMLAUNCH] = handle_vmlaunch,
[EXIT_REASON_VMPTRLD] = handle_vmptrld,
[EXIT_REASON_VMPTRST] = handle_vmptrst,
[EXIT_REASON_VMREAD] = handle_vmread,
[EXIT_REASON_VMRESUME] = handle_vmresume,
[EXIT_REASON_VMWRITE] = handle_vmwrite,
[EXIT_REASON_VMOFF] = handle_vmoff,
[EXIT_REASON_VMON] = handle_vmon,
[EXIT_REASON_CR_ACCESS] = handle_cr,
[EXIT_REASON_DR_ACCESS] = handle_dr,
[EXIT_REASON_IO_INSTRUCTION] = handle_io,
[EXIT_REASON_MSR_READ] = handle_rdmsr,
[EXIT_REASON_MSR_WRITE] = handle_wrmsr,
[EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window,
[EXIT_REASON_NMI_WINDOW] = handle_nmi_window,
[EXIT_REASON_TASK_SWITCH] = handle_task_switch,
[EXIT_REASON_MCE_DURING_VMENTRY] = handle_machine_check,
[EXIT_REASON_GDTR_IDTR] = handle_desc,
[EXIT_REASON_LDTR_TR] = handle_desc,
[EXIT_REASON_APIC_ACCESS] = handle_apic_access,
[EXIT_REASON_APIC_WRITE] = handle_apic_write,
[EXIT_REASON_EPT_ACCESS] = handle_wbinvd,
[EXIT_REASON_XSETBV] = handle_xsetbv,
[EXIT_REASON_XSAVES] = handle_xsaves,
[EXIT_REASON_XRSTORS] = handle_xrstors,
[EXIT_REASON_PML_FULL] = handle_pml_full,
[EXIT_REASON_PREEMPTION_TIMER] = handle_preemption_timer,
[EXIT_REASON_NOTIFY] = handle_notify,
};
2.5 VPID: 虚拟处理器标识¶
VPID (Virtual Processor Identifier) 避免 TLB flush on VM-entry/exit:
| VPID 值 | 含义 |
|---|---|
| 0 | 共享物理 TLB (legacy) |
| 1+ | 独立 TLB 标签 |
KVM 在 vmx_vcpu_create 中分配 VPID:vmx->vpid = allocate_vpid()。VPID 值写入 VMCS guest-state area 的 VPID 字段,配合 EPT 实现 TLB 隔离。
2.6 TDX: Trust Domain Extensions (vmx/tdx.c)¶
Intel TDX 提供硬件级机密运算。KVM 通过 vmx/tdx.c 支持 TDX guest:
- SEAM (Secure Arbitration Mode) 模块处理 TD VM 的进入和退出
- SEAMCALL 指令替代 VMLAUNCH/VMRESUME
- SEAMRET 返回替代 VM-Exit
- Guest 私有内存通过 SEPTs (Secure EPT) 管理
vt_x86_ops在vmx/tdx.c:3416被 TDX 覆盖若干指针
3. AMD SVM 实现¶
3.1 struct vcpu_svm (svm/svm.h:272)¶
// arch/x86/kvm/svm/svm.h:272
struct vcpu_svm {
struct kvm_vcpu vcpu; // 通用 vCPU
struct vmcb *vmcb; // 当前活跃 VMCB (vmcb01 或 vmcb02)
struct vmcb *vmcb01; // L1 guest 的 VMCB
u64 vmcb_pa; // VMCB 物理地址
struct svm_cpu_data *svm_data; // per-CPU SVM 数据
// SEV
void __user *ghcb_sa; // GHCB scratch area
u64 ghcb_reg; // GHCB 寄存器
u64 ghcb_sa_len;
// 嵌套虚拟化
struct nested_state nested;
// ASID
u32 asid; // Address Space ID
u16 asid_generation;
// MSR 权限位图
unsigned long *msrpm; // MSR Permission Map (2K x 2)
// AVIC 相关
struct page *avic_backing_page; // AVIC 后备页
u64 *avic_physical_id_cache; // vCPU → pCPU 映射
bool avic_is_running;
// SEV-ES / SEV-SNP
struct vmcb_save_area *vmsa; // VMSA (VM Save Area)
bool guest_state_loaded; // guest state 是否已加载
};
3.2 VMCB 布局¶
AMD 使用 VMCB (Virtual Machine Control Block) 替代 Intel 的 VMCS:
┌──────────────────────────────────────┐
│ VMCB (4KB) │
├──────────────────────────────────────┤
│ Save Area (偏移 0x000) │
│ ├── ES/CS/SS/DS selector + attr │
│ ├── CPL, CR0, CR2, CR3, CR4 │
│ ├── RIP (nRIP) │
│ ├── RSP │
│ ├── RAX │
│ ├── RFLAGS │
│ ├── DR6, DR7 │
│ ├── EFER, STAR, LSTAR, CSTAR │
│ ├── GDTR, IDTR, TR │
│ └── Efer, PAT │
├──────────────────────────────────────┤
│ Control Area (偏移 0x400) │
│ ├── Intercept vectors │
│ │ ├── INTERCEPT_CR_READ/WRITE │
│ │ ├── INTERCEPT_MSR_PROT │
│ │ ├── INTERCEPT_IOIO_PROT │
│ │ ├── INTERCEPT_INTR, NMI │
│ │ ├── INTERCEPT_VMRUN, VMLOAD │
│ │ ├── INTERCEPT_HLT, PAUSE │
│ │ └── INTERCEPT_EXCEPTION_OFF │
│ │ │
│ ├── IOPM_BASE_PA (IO权限位图) │
│ ├── MSRPM_BASE_PA (MSR权限位图) │
│ ├── TSC_OFFSET │
│ ├── ASID │
│ ├── V_TPR, V_IRQ │
│ ├── V_INTR_VECTOR │
│ ├── NPT (Nested Page Table) │
│ ├── nested_ctl │
│ ├── EVENTINJ (事件注入) │
│ ├── EXITCODE, EXITINFO1/2 │
│ └── VMCB Clean Bits │
└──────────────────────────────────────┘
3.3 VMCB Clean Bits 优化¶
AMD 提供 VMCB Clean Bits 机制标记哪些字段已被 KVM 修改,避免不必要的 VMRUN 时刷新:
#define VMCB_CLEAN_INTERCEPTS (1 << 0)
#define VMCB_CLEAN_IOPM_PA (1 << 1)
#define VMCB_CLEAN_ASID (1 << 2)
#define VMCB_CLEAN_TPR (1 << 3)
#define VMCB_CLEAN_NPT (1 << 4)
#define VMCB_CLEAN_CR2 (1 << 5)
#define VMCB_CLEAN_LBR (1 << 6)
#define VMCB_CLEAN_AVIC (1 << 7)
KVM 使用 vmcb_mark_dirty(vmcb, bits) 标记脏字段,VMRUN 时硬件只加载被标记的字段。
3.4 世界切换:VMRUN / #VMEXIT¶
SVM 的世界切换流程:
host kernel guest
│ │
│ 保存 host 寄存器 │
│ │
│ 设置 VMCB 各字段 │
│ │
│ VMRUN (vmcb_pa) │
│ ──────────────────────────►│ #VMEXIT 返回后第一条指令
│ │ guest 上下文自动加载
│ │
│ │ (guest 执行用户代码)
│ │
│ │ 触发拦截 (IO/MSR/CR access...)
│ │
│ #VMEXIT ◄──────────────────│
│ │
│ 读取 EXITCODE │
│ 分发 handle_exit │
│ │
│ 再次 VMRUN ... │
与 Intel 不同,SVM 没有独立的 Enter/Exit 指令,而是统一的 VMRUN,自动处理 guest state 的加载和保存。AMD 使用 VMRUN vmcb_pa 一条指令完成切换。
3.5 SEV / SEV-ES / SEV-SNP (svm/sev.c)¶
AMD SEV 系列技术提供不同级别的机密运算:
| 技术 | 特性 | 内存加密 | 寄存器保护 |
|---|---|---|---|
| SEV | 基本内存加密 | 每个 VM 独立密钥 | 无 |
| SEV-ES | 加密状态 | guest state 加密 | 是 (VMSA) |
| SEV-SNP | 安全嵌套分页 | 完整性保护 | 是 + RMP 校验 |
SEV 的关键流程:
KVM_SEV_INIT — 初始化 SEV 固件
KVM_SEV_LAUNCH_START — 开始启动加密 guest
KVM_SEV_LAUNCH_UPDATE_DATA — 加载加密数据 (firmware, kernel)
KVM_SEV_LAUNCH_MEASURE — 获取启动度量
KVM_SEV_LAUNCH_FINISH — 完成启动
SEV-ES 扩展引入 GHCB (Guest-Hypervisor Communication Block),为 guest 和 hypervisor 之间的通信提供协议。
3.6 AVIC: Advanced Virtual Interrupt Controller (svm/avic.c)¶
AMD AVIC 提供硬件级中断虚拟化,避免 VM-Exit 处理中断:
Guest writes to APIC TPR/EOI
│
▼
Hardware AVIC table update (no VM-Exit!)
│
▼
Hardware 评估: 是否有 pending 中断 > TPR?
│
├── 是 → 直接注入 (no VM-Exit)
│
└── 否 → 继续 guest 执行
外部中断到达 (IPI / device interrupt)
│
▼
IOMMU 查 AVIC 表 → 发送 Posted Interrupt
│
▼
目标 vCPU 收到通知 → 硬件注入中断 (no VM-Exit!)
AVIC 使用物理 pCPU 门铃机制和 doorbell 页完成中断加速。svm_x86_ops 在 svm/avic.c:1299 启用 AVIC 相关特性。
4. 嵌套虚拟化¶
4.1 VMX Nested (vmx/nested.c, ~237KB)¶
当 L1 hypervisor 运行在 KVM 内部时:
L2 Guest (nested VM)
│
VMLAUNCH/VMRESUME (由 L1 发出)
│
▼
KVM intercept (L1 的 VM-entry 尝试)
│
▼
nested_vmx_run() — 合并 L1 VMCS12 + L0 VMCS01 → 构造 VMCS02 (shadow VMCS)
│
▼
VMRESUME (执行 L2, 使用 VMCS02)
│
▼
L2 执行... → VM-Exit
│
▼
如果 exit 需要 L1 处理 → inject 到 L1 → VM-Entry L1
如果 exit 可以被 L0 处理 → KVM 直接处理并重新进入 L2
关键状态结构:
struct vmcs12 {
// L1 设置的 VMCS fields (guest 视角)
gva_t virtual_processor_id;
u64 io_bitmap_a, io_bitmap_b;
u64 msr_bitmap;
u64 vm_exit_msr_store_addr, vm_exit_msr_load_addr;
u64 vm_entry_msr_load_addr;
u64 tsc_offset;
u64 guest_ia32_pat;
u64 guest_tr_base, guest_gdtr_base, guest_idtr_base;
struct vmcs12_host_state host_state; // L2 exit → L1 的状态
struct vmcs12_guest_state guest_state; // L2 的 guest state
...
};
4.2 SVM Nested (svm/nested.c, ~60KB)¶
SVM 嵌套相对简单,因为 VMRUN 本身是递归可嵌套的:
L1 VMRUN 尝试 → KVM 拦截 → 合并 vmcb12 到 vmcb02 → 设置 vmcb02 的 clean bits → 硬件 VMRUN vmcb02 → #VMEXIT → 如果 L1 需要处理则写回 vmcb12 → VMRUN vmcb01 (返回 L1)。
5. VM-Entry / VM-Exit 完整生命周期¶
┌──────────────────────────────┐
│ KVM_RUN ioctl │
│ (kvm_vcpu_ioctl:4405) │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ kvm_arch_vcpu_ioctl_run │
│ ├─ 处理 pending 信号 │
│ ├─ 处理 pending requests │
│ └─ vcpu->mode = │
│ IN_GUEST_MODE │
└──────────────┬───────────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
┌────────▼───────┐ ┌───────▼───────┐ ┌──────▼───────┐
│ Intel VMX │ │ Intel TDX │ │ AMD SVM │
│ vmx_vcpu_run │ │ tdx_vcpu_run │ │ svm_vcpu_run │
│ (vmx.c:7515) │ │ │ │ │
└────────┬───────┘ └───────┬───────┘ └──────┬───────┘
│ │ │
│ __vmx_vcpu_run │ SEAMCALL │ VMRUN
│ (vmenter.S:47) │ │
│ │ │
┌────────▼────────────────────────────────────────▼───────┐
│ VM-Entry (硬件) │
│ ├─ 加载 guest CR0/CR3/CR4/RIP/RSP/RFLAGS/EFER │
│ ├─ 加载 EPT/NPT 指针 │
│ ├─ 加载中断注入信息 (VM-entry interruption info) │
│ ├─ 设置 VPID/ASID │
│ └─ 跳转到 guest RIP │
└──────────────────────┬──────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────────┐
│ Guest 代码执行 │
│ ├─ 用户程序 / 内核代码 │
│ ├─ 访问 MMIO → EPT/NPT violation │
│ ├─ HLT / PAUSE / CPUID / RDMSR / WRMSR / IN/OUT │
│ ├─ 中断 / NMI / 异常 │
│ └─ EOI / TPR 访问 (可硬件虚拟化) │
└──────────────────────┬──────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────────┐
│ VM-Exit (硬件) │
│ ├─ 保存 guest state → VMCS/VMCB │
│ ├─ 加载 host state → CPU 寄存器 │
│ ├─ 写入 exit reason / qualification │
│ └─ 跳转到 host RIP (vmx_vmexit入口 或 #VMEXIT后) │
└──────────────────────┬──────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────────┐
│ KVM Exit 处理 │
│ ├─ handle_exit_irqoff (关中断快速处理) │
│ ├─ 更新统计计数器 │
│ │ │
│ ├─ Fast Path (无锁, 无阻塞): │
│ │ ├─ MSR_WRITE (WRMSR) │
│ │ └─ PREEMPTION_TIMER │
│ │ │
│ └─ Slow Path (通过 handle_exit): │
│ ├─ handle_exception_nmi │
│ ├─ handle_external_interrupt │
│ ├─ handle_io / handle_in/out │
│ ├─ handle_cpuid │
│ ├─ handle_rdmsr / handle_wrmsr │
│ ├─ handle_cr / handle_dr │
│ ├─ handle_ept_violation → MMU page fault 处理 │
│ ├─ handle_ept_misconfig │
│ ├─ handle_hlt / handle_pause │
│ ├─ handle_interrupt_window / handle_nmi_window │
│ └─ handle_apic_access / handle_apic_write │
└──────────────────────┬──────────────────────────────────┘
│
┌─────────────▼──────────────┐
│ 是否可以在内核态继续运行? │
│ │
└──YES──┬────────NO──────────┐
│ │
┌───────▼──────┐ ┌───────▼──────────────┐
│ 准备下一轮 │ │ vcpu->run->exit_reason│
│ VM-Entry │ │ = KVM_EXIT_IO/MMIO/ │
│ │ │ HLT/... │
│ 循环回到 │ │ │
│ kvm_x86_ops │ │ 返回用户态 (QEMU) │
│ ->vcpu_run() │ │ │
└───────────────┘ └──────────────────────┘
6. 性能对比:VMX vs SVM 关键差异¶
| 特性 | Intel VMX | AMD SVM |
|---|---|---|
| 控制结构 | VMCS (VMREAD/VMWRITE) | VMCB (内存直接访问) |
| 世界切换 | VMLAUNCH/VMRESUME + VM-Exit | VMRUN (含 #VMEXIT) |
| TLB 管理 | VPID | ASID |
| 2D 页表 | EPT | NPT |
| 中断虚拟化 | Posted Interrupt | AVIC |
| VMCS 缓存 | VMCS shadowing (nested) | VMCB clean bits |
| CR 拦截 | VM-execution controls | INTERCEPT_CR 位图 |
| MSR 拦截 | MSR bitmap | MSRPM (MSR Permission Map) |
| 加密 | TDX (SEAM) | SEV/SEV-ES/SEV-SNP |
下一篇文章¶
第3篇:MMU 虚拟化 — EPT/NPT、影子页表与 TDP MMU