13.x86virt_comp
The main technical contributions of this paper are:
- a review of VMware Workstation’s software VMM, focusing on performance properties of the virtual instruction execution engine;
- a review of the emerging hardware support, identifying performance trade-offs;
- a quantitative performance comparison of a software and a hardware VMM.
Establishes three essential characteristics for system software to be considered a VMM
- Fidelity(保真性) Software on the VMM executes identically to its execution on hardware, barring timing effects.
- Performance(高性能) An overwhelming majority of guest instructions are executed by the hardware without the intervention of the VMM.
- Safety(安全性) The VMM manages all hardware resources.
1. 基础概念
VMM vs Hypervisor
-
VMM (Virtual Machine Monitor):
- 来自 Popek & Goldberg (1974), 强调核心虚拟化功能(trap & emulate, BT, shadow structures);
- 负责虚拟机执行控制;
-
Hypervisor:
- 工程上更常用的术语, 指整个虚拟化层;
- 包含 VMM, 同时提供调度, 资源分配, 设备模型, 管理接口;
- Type 1(bare-metal, 如 Xen, ESXi), Type 2(hosted, 如 VMware Workstation);
关系: Hypervisor VMM;
MMU 的功能
MMU (Memory Management Unit) 是 硬件模块, 存在于 CPU 中:
- 它负责把 虚拟地址 (VA) 物理地址 (PA) 的转换;
- 支持页表遍历, TLB 缓存, 权限检查(R/W/X);
操作系统负责 构建和维护页表(page tables), 但具体的地址转换是在 MMU 硬件里完成的;
- OS 设置 %cr3 指向页表根;
- MMU 硬件在发生 TLB miss 时, 自动去内存里查页表;
但是传统的 MMU 设计并不很支持虚拟化, 本文的最后会提及如何优化 MMU 来支持虚拟化
2. Classical Virtualization 基本方法
De-privileging
- Guest 内核不再运行在最高特权级, 而是被 deprivileged(降低权限);
- 特权指令执行时会 trap, 交由 VMM 处理, 再进行 emulation;
- 满足 Popek & Goldberg 的 Fidelity, Performance, Safety 要求;
Primary vs Shadow Structures
- Primary structure: guest 自己维护的数据结构(页表, IDT, MMIO 寄存器);
- Shadow structure: VMM 维护的, 真正提供给硬件使用的代理结构;
- 确保 guest 的虚拟视角正确, 但硬件只看 VMM 的影子版本, 防止 guestOS 访问非法地址, 满足 secure 要求;
Off-CPU vs On-CPU Privileged State
- On-CPU: 存在于 CPU 内部寄存器(%cr3, %eflags), 特权指令访问时自然触发 trap 容易虚拟化;
- Off-CPU: 存在于内存(页表, MMIO), 普通
mov/store就能改, 不会触发 trap 需要 tracing 技术来确保所有访问都被虚拟化了;
True Page Faults & Hidden Page Faults
- True: 由 guest OS 自己页表里的权限或映射问题引发的缺页;
- guest 程序访问了一个未映射的虚拟地址; 或者违反了 guest 页表里的权限规则(比如只读页被写);
- VMM 捕获后会确认这是 guest 自己的逻辑错误; 然后把这个 page fault 转交给 guest OS 的缺页异常处理程序; guest OS 决定分配新页, 换入磁盘页, 或直接杀进程;
- Hidden: 由 shadow page table 不完整导致的缺页;
- guest 认为地址是合法的(它的页表有映射); 但是 VMM 维护的 shadow page table 里还没有填好对应的条目;
- VMM 捕获这个缺页, 检查 guest 页表; 确认这是个"合法访问"后, 就在 shadow page table 里构造正确的条目; 然后恢复 guest 执行;
Tracing
- 目的: 保持 primary 与 shadow 一致性;
- 做法: 通过页保护 write-protect guest 页表, 触发 trap VMM 捕捉并同步 shadow;
Three-way Trade-off
- trace overhead (频繁 trap)
- hidden page faults (不用 trace 会导致大量隐藏缺页)
- context switch cost (这里指进程切换的花销, 尤其指切换进程所需要的切换 shadow table 从而带来 performance 降低, 但是同时也会降低未来一段时间 hidden 的数量, 因为刚刚强行统一了一次)
性能瓶颈就在于如何平衡三者;
3. x86 虚拟化的障碍与 BT
3.1 Obstacles
- 可见性 Visibility: guest 读
%cs能发现 CPL (current privilege level) 被降级; - Lack of trap: 如
popf在用户态 (ring 1-3) 修改 IF 标志时不会 trap, VMM 无法拦截;
3.2 Interpreter vs Binary Translation
- Interpreter: 逐条解释执行, 语义正确, 但性能极差: 会带来解释的开销, 且无法利用 CPU 的指令流水线和缓存;
- Binary Translation (BT):
- 动态翻译 guest 二进制 安全的 host 指令序列;
- 大部分普通指令可 IDENT 翻译(原样照抄);
- 少量敏感指令替换成 VMM 调用 (比如所有的非确定跳转, 特权指令);
- 翻译结果缓存(Translation Cache, TC), 避免重复翻译;
- 实现 正确性 + 高性能 的平衡;
Translator Properties
- Binary: 输入是 guest 二进制, 不依赖源码;
- Dynamic: 运行时翻译;
- On demand: 只在执行前翻译 (laziness);
- System level: 基于 ISA, 不依赖 ABI/应用假设, 必须保证 OS 内核代码正确;
- 这里 ABI 指的是操作系统和 app 之间的接口, 即封装了底层硬件接口 ISA 以及 OS 对用户态提供的系统调用接口等.
- Subsetting: 输出 host 的安全指令子集;
- Adaptive: 根据 guest 行为优化翻译策略;
IR, TU, BB
- IR (Intermediate Representation): 每条 guest 指令的中间表示, 也就是生成的中间内容, 单位是每一条 二进制代码转化成的结果;
- TU (Translation Unit): 一次翻译的一组 IR( 12 条或遇到控制流终结例如不确定跳转);
- BB (Basic Block): 基本块, 通常一个 TU = 一个 BB;
Translation Cache (TC) 与 CCF
- CCF (Compiled Code Fragment): TU 翻译后的代码片段, 即
assemb -> TU (Set of IR) -> CCF (Set of Host Instructions); - TC (Translation Cache): 缓存所有 CCF, 避免重复翻译, 对于热点代码性能提升巨大, 理解为 icache;
- Chaining 优化:
- 默认 continuation 要回翻译器 慢;
- chaining jump 直接把 CCF 连起来 快;
- 有时甚至可以"fall through", 物理内存相连的 CCF 直接执行;
*的含义: 标记每个 CCF 的第一条指令(入口点);
4.3 虚拟寄存器绑定
- 大多数 guest 虚拟寄存器直接绑定到物理寄存器 方便 IDENT 翻译;
- 例外: %gs
- 被用作进入 VMM 内存空间的"后门";
- BT 需要 spill guest 寄存器(如 %rcx)时, 用
%gs前缀写到 VMM 内存; - 完成操作后再恢复 guest 的寄存器值;
4.4 Paging vs Segmentation
- 选择 segmentation:
- VMM 在高地址, guest 在低地址;
- 截断 guest 段寄存器 防止 guest 越界访问 VMM;
%gs保留用于 VMM 自身访问, 其他访问会被 硬件截断, 触发 segmentation fault;
- 非 IDENT 翻译的情况:
PC(program counter)-relative addressing翻译后的代码段(TC, Translation Cache)和原代码段地址不同, 翻译器插入补偿代码修正 PC-relative 偏移, 会导致小幅度代码膨胀和性能下降- Direct control flow 代码布局变了, 目标地址也不同, 翻译器把 guest 地址映射到 TC 地址;
- Indirect control flow 动态查表, 跳转接口只有在运行时才能确定接下来去哪里, 会造成 个位数百分比的性能损失;
- Privileged instructions 用 in-TC 序列或 callout 模拟; 简单操作可以直接在 TC 内部完成; 复杂的操作需要调用 VMM 的例程(callout);
5. Hardware Virtualization (Intel VT / AMD SVM)
5.1 新机制
- VMCB: 保存 guest 状态 + 控制位;
- guest mode: 直接执行 guest, 包括特权指令;
- vmrun: 进入 guest; exit: 返回 VMM;
- diagnostic fields (诊断方案): 告诉 VMM exit 的原因(如 I/O, fault);
- 硬件扩展基本规定了 VMM 的框架:
- 填 VMCB vmrun exit emulation vmrun;
- 但因为缺少 MMU 虚拟化支持(EPT/NPT 尚未出现), 仍需依赖 shadow page tables;
5.2 Flexibility
- 含义: VMM 可以选择"信任 guest 的程度";
- 情景:
- 如果是合作型 OS(para-virt), VMM 可以允许 guest 驱动外设, 处理中断, 建页表 性能更高;
- 如果是纯虚拟化, VMM 必须设定更多 exit(页表修改, I/O, MMIO) 隔离性强, 但性能下降;
6. BT 的适用范围
- 理论上: BT 可以翻译 guest 的所有代码(内核, 驱动, 应用);
- 实际优化:
- 用户态应用: 通常直接运行, 不用 BT 性能接近原生;
- 内核态代码: 涉及敏感/特权指令, 必须通过 BT 翻译;
7. 总结
- 软件 BT: 灵活, 能做自适应优化, 对 MMU 热点有优势;
- 硬件虚拟化: 结构固定, 性能取决于 exit 频率, 缺乏 MMU 支持时反而不如软件;
- 关键设计点:
- Primary vs Shadow structures;
- Tracing 三难权衡;
- BT 的 IDENT 翻译 + 非 IDENT 特殊处理;
- Segmentation 隔离 +
%gs后门; - 硬件 VMCB 的 flexibility 设定;
一句话总结:
BT 是 VMM 内核的核心技术, 用软件弥补 x86 不可虚拟化之处; 而硬件虚拟化提供了 VMCB 和 guest mode, 但在缺乏 MMU 支持时性能反而受限, 必须依赖 shadow page table 和 exit 控制策略;
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
