Linux内核分析之虚拟化-01

This language version is unavailable; showing the other language.

50.1 x86 VT-x / AMD-V 扩展

VT-x(Intel)与 AMD-V(SVM)是 x86 硬件虚拟化的两大扩展:新增一个"非根模式"(客户机运行态),敏感操作触发 VM-Exit 回根模式(宿主内核),VMCS/VMCB 保存双态上下文。两者语义同构而编码各异。本节解剖 VT-x 的模式模型、控制位体系与 AMD-SVM 的对照,以及 KVM 的初始化路径。


50.1.1 模式模型:根与非根

x86 特权模型的虚拟化扩展:

 传统 (无 VT-x): ring0 内核 / ring3 用户
   客户内核怎么跑? 二进制翻译或半虚拟化 (史前) —
   ring0 的敏感指令 (CPUID/MSR/页表) 无法拦截

 VT-x 模型: 两个维度正交
   根模式 (root)     : 宿主内核 (KVM) — 拥有全部控制
   非根模式 (non-root): 客户机 — 其 ring0 也是"受控的"
        + ring0..ring3 两个模式各自可跑客户代码

  宿主:   root/ring0  ←── VM-Exit ── 非根/ring0 (客户内核)
     ▲                                │ 敏感指令/事件
     └──── VM-Entry (VMRESUME) ──── 非根/ring3 (客户应用)
  (VMCS 控制位决定非根下"哪些操作触发退出" — 49.2 节)

 AMD-V (SVM) 的对应: VMCB (≈VMCS), VMMCALL (≈VMCALL),
   vmsave/vmload (上下文块), INTR/MASK 模型细节不同

50.1.2 控制位体系与退出消除

// arch/x86/include/asm/vmx.h:30-90(控制位样例)
#define CPU_BASED_HLT_EXITING                   VMCS_CONTROL_BIT(HLT_EXITING)   /* :30 */
#define SECONDARY_EXEC_ENABLE_EPT               VMCS_CONTROL_BIT(EPT)       /* :57 */
#define PIN_BASED_NMI_EXITING                   VMCS_CONTROL_BIT(NMI_EXITING)   /* :90 */
三大控制组与典型优化 (49.2 节的展开):

 pin-based: NMI/中断退出窗口, posted-interrupt
   (APICv: 中断直接注入非根态, 不退出!)
 primary:   HLT/CR/DR/IO/MSR-bitmap/中断窗口...
 secondary: EPT/EPT-violation#/VPID/RDTSCP/
   UNRESTRICTED_GUEST (实模式客户)/VMFUNC/APICv...

 逐项退出的性能账 (49.3 节 1-2μs/次):
   关 CR3_LOAD_EXITING + EPT   → 内存访问零退出
   MSR bitmap (4096 位)        → 常用 MSR 直通
   APICv/PI                   → 中断注入零退出
   VPID                       → TLB 不全刷
   enable V Gust shadow...     → (5 章每代 CPU 新增)
 剩余必然退出: CPUID/IO(无模拟)/部分 MSR/自修改页表

50.1.3 KVM 的初始化路径

// arch/x86/kvm/vmx/vmx.c:8922
int __init vmx_init(void)
// :354 区(预初始化注释: EPT 能力协商的先后依赖)
     * Has vmx_init() run already? If not then this is the pre init
     * vmx_init() do the proper setup after enable_ept has been
kvm_intel 模块的装载链:

 module_init(vmx_init) (:8922)
   ├─ hv_enable_ept / cpu_has_vmx 逐项探测 VMX 能力
   │   (读 IA32_VMX_*_CTLS MSR: 每个控制位的
   │    "允许 0/允许 1" 位图 — KVM 按位取交集)
   ├─ enable_ept 协商 (TDP MMU 的前提, 49.4 节)
   │   (注释: pre-init 阶段 EPT 未定时先跳过)
   ├─ 分配 VMCS 区域池 / VPID 位图
   └─ kvm_init() → misc_register(/dev/kvm, 49.1 节)

 失败路径: CPU 无 VMX 或 BIOS 关闭 → 模块退出,
   /dev/kvm 缺失 → QEMU 报 "virtualization disabled"
   (BIOS 里开 VT-x 的提示就来自这条链)

VMX preemption timer 与 nested:VMCS 还提供"预设置定时器到时退出"(KVM 用于客户内定时器精度)与 nested VT-x(L1 客户自己也跑 KVM——L0 用影子 VMCS 合成 L1 的 EPT,49.4.4 节影子思想的二级嵌套回归)。


小结

VT-x/AMD-V 以"根/非根双模式 + VMCS/VMCB 上下文 + 控制位政策"把客户机的 ring0 变成可拦截的受控态:三大控制组(pin/cpu/secondary)决定退出面,KVM 的优化史是逐位关闭退出(EPT/MSR bitmap/APICv/VPID),初始化链以 IA32_VMX 能力 MSR 与 KVM 逐位取交集收尾,BIOS 关 VT-x 的报错即此链的失败出口。下一章看 ARM64 与 RISC-V 的对应扩展。

50.2 ARM64 VHE 与嵌套虚拟化

ARM64 的虚拟化不是"新增一个模式"而是复用既有的 EL2 异常级:安全监控器/管理程序本来就设计为跑在 EL2。VHE(Virtualization Host Extension)进一步让"内核自己跑在 EL2"成为可能——KVM 的世界切换从"陷入更高异常级"变成"同级的异常进出"。本节解剖 VHE 的模式判定、nVHE/VHE 双模式与 GIC-ITS 的中断虚拟化。


50.2.1 异常级模型与 VHE 判定

// arch/arm64/kernel/cpufeature.c:2090 与 :2357
    return is_kernel_in_hyp_mode();
    ...
    if (is_kernel_in_hyp_mode())
ARM64 异常级与两种 KVM 形态:

 异常级: EL0(用户) EL1(内核) EL2(虚拟化) EL3(安全监控)

 无 VHE (nVHE, 传统):
   Linux 跑 EL1, KVM 的一部分(_kvm hyp 镜像)
   装载到 EL2 运行 — 世界切换 = 陷入 EL2 异常向量
   EL2 代码是独立的二进制镜像 (重定位到 EL2 地址!)
 VHE (ARMv8.1+, 现代):
   CPU 支持 "Host EL2" 模式: 内核直接跑 EL2,
   客户跑 EL1 — 世界切换 = 同级的异常进出,
   KVM 代码就是内核本体的一部分
 判定: is_kernel_in_hyp_mode() (:2090)
   = 读 CurrentEL == EL2 (引导时固件把内核放 EL2)

 VHE 的收益 (对照 49.2 节 VMCS 自动化):
   宿主状态无需手工保存 (EL2 寄存器就是内核自己的)
   TLB: VMID 标签 (≈VPID) + 内核用 host 标签
   切换更少指令, 但异常进出仍是软件路径 —
   硬件自动化程度 < VT-x, 指令数 > VT-x

50.2.2 Stage-2 与中断虚拟化

S2PT (第二阶段翻译) 的内核锚点:

 VTTBR_EL2: S2 页表根 (19.3 节对照表)
 VTCR_EL2:  S2 的 T0SZ/粒度/权限覆盖配置
 arch/arm64/kvm/mmu.c: S2 建表 (49.4 节同思想:
   缺页驱动惰性填充, 权限独立于客户 S1)
 S1+S2 联合: S1 输出 IPA (中间物理地址) → S2 翻 HPA
   大页: S2 也支持 block (2M/1G) — 23.4.5 节表

 中断虚拟化 (42.5.2 节 GIC 的展开):
   GICv3 + ITS: 客户看到虚拟 GIC (vGIC)
   LPI 的转换表由 KVM 管理 (设备 MSI → vCPU)
   vgic-v3 模块: 寄存器模拟 + list register
   硬件直通 (LR 满载时不退出!)

双 T0SZ 技巧(19.3.1 节):VA_BITS=48 配置下内核可能在 52 位能力机器上运行——VHE 时 T0SZ 动态切换(用户进程 52 位、内核 48 位),__cpu_set_tcr_t0sz(mmu_context.h:98)的调用点即此。嵌套虚拟化(nested virt)在 ARM64 上由 NV 扩展支持——L1 的 S2 由 L0 合成(影子思想的回归,49.4.4 节同构)。


小结

ARM64 虚拟化复用 EL2 异常级而非新增模式:nVHE 把 KVM hyp 镜像放 EL2(独立二进制),VHE 让内核直接跑 EL2(现代默认,切换即同级异常进出);S2PT 由 VTTBR/VTCR 描述、缺页驱动填充,权限独立可降权;中断虚拟化复用 GICv3/ITS 的 LPI 转换表加 vGIC 模拟;双 T0SZ 与 NV 扩展分别解决 52 位混部与嵌套虚拟化。下一章看 RISC-V 的 H 扩展与 AIA。

50.3 RISC-V H 扩展与 AIA

RISC-V 的 Hypervisor 扩展(H 扩展,1.10+ 规范冻结)引入 VS-mode(Virtual Supervisor):客户内核跑在一个"被 HS-mode(宿主监督态)包裹的 S-mode"里。AIA(Advanced Interrupt Architecture)则为中断带来消息化(IMSIC)与两级控制器(APLIC)。本树 arch/riscv/kvm/ 的文件清单(aia.c/aia_aplic.c/aia_imsic.c/gstage.c/vcpu_sbi_*.c)就是这套体系的实现地图。本节解剖 VS-mode、G-stage 与 AIA 三件套。


50.3.1 VS-mode 与 H 扩展的寄存器

RISC-V 特权级 (H 扩展启用后):

 M-mode (机器)           ← 固件/SBI (6.5 节)
 HS-mode (宿主监督)       ← Linux 内核 + KVM
 VS-mode (客户监督)       ← 客户内核 (虚拟的 S-mode)
 U/VU-mode (用户)

 H 扩展新增的 CSR (49.2 节对照表):
 hgatp    : G-stage 页表根 (模式/ASID/PPN)
 hstatus  : VS 态的状态镜像/授权位
 hedeleg/hideleg : 异常/中断委派给 VS 的位图
 vsstatus/vsepc/vscause/vstval : VS 态的 sret 上下文
 hvip     : 虚拟中断挂起位 (软件注入的通道)
 hcounteren/henvcfg : 计数器/环境授权

 两阶段翻译:
 客户 va ──[vsatp]──> guest PA (GPA)
        ──[hgatp]──> 宿主 PA (HPA)
 (G-stage 缺页 = vscause 里的 guest-page-fault,
  arch/riscv/kvm/mmu.c + gstage.c 处理)

50.3.2 G-stage 与 AIA 的实现地图

// arch/riscv/kvm/main.c:128
    rc = kvm_riscv_aia_init();
// arch/riscv/kvm/ 文件清单 (本树实况):
    gstage.c        /* G-stage 页表管理 (49.4 节同思想) */
    mmu.c vcpu_exit.c vcpu_switch.S vcpu_sbi_*.c
    aia.c aia_aplic.c aia_imsic.c aia_device.c
AIA (Advanced Interrupt Architecture) 的两层:

 APLIC (Advanced Platform-Level Interrupt Controller):
   线式设备中断的"升级版 PLIC" — 支持把中断
   直接消息化发给指定 hart/客户 (MSI 模式)
 IMSIC (Incoming MSI Controller):
   每 hart/每个客户一组 MMIO 寄存器 —
   设备写 = 投递 MSI (消息化, 与 42.5.2 节 ITS/
   42.5.3 节 MSI-X 同思想)
 KVM 的 aia_imsic.c: 客户 IMSIC 的软件模拟+
   硬件直通混合 (AIA 虚拟化扩展时寄存器直达)

 SBI 的虚拟化面 (6.5 节 SBI 的 VM 视角):
 vcpu_sbi_*.c 一族: 客户的 ecall(SBI 调用) 被
   KVM 截获并模拟/转发 — HSM( hart 启停)/
   PMU/STA(时间) 每个扩展一个文件
   (SBI 之于 RISC-V ≈ 固件服务 ≈ KVM 要虚拟的
    "BIOS 接口")

架构谱系收束(23.4.5/49.2 节对照的完成):三架构的虚拟化共同点是"二级翻译(EPT/S2PT/G-stage)+ 消息化中断(PI/LPI/IMSIC)+ 标签化 TLB(VPID/VMID/VMID)";差异在上下文自动化程度(VMCS 硬件 vs EL2/SRET 软件)与生态(x86 的设备直通成熟度、RISC-V 的 SBI 虚拟化层)。无 THP 的 RISC-V 宿主使大页供应完全依赖 HugeTLB(23.4.5 节)——第九部分的架构对照至此闭环。


小结

RISC-V H 扩展以"VS-mode(被 HS 包裹的 S 态)+ hgatp(G-stage)+ hedeleg/hvip(委派与注入)"实现虚拟化,KVM 的 arch/riscv/kvm/ 文件清单即体系地图:gstage.c 管二段翻译、aia_aplic/imsic 管两级消息化中断、vcpu_sbi_* 族模拟客户可见的固件服务。三架构对照收束:二级翻译+消息化中断+标签化 TLB 是公共面,上下文自动化程度与生态成熟度是差异面。硬件辅助虚拟化三章至此完成;下一章进入 virtio——让客户 I/O 高效到达宿主设备的框架。