14.turtle_IBM.md
Authors: Muli Ben-Yehuda et al., IBM Research / IBM Linux Technology Center
1. 背景与动机
- 传统虚拟化 (single-level): 一个 hypervisor (L0) 管理多个 VM, 每个 VM 运行 OS;
- 嵌套虚拟化 (nested virtualization): 允许一个 hypervisor (L1) 作为 guest 运行, 并且还能继续运行自己的 VM (L2);
- 需求来源:
- 现代操作系统自带虚拟化功能(Windows XP mode in Win7, Linux 内置 KVM);
- IaaS 场景: 云提供商 (L0) 希望用户能运行自己的 hypervisor (L1), 自己管理 VM (L2);
- 研究和测试: 嵌套虚拟化方便调试/benchmark hypervisor;
- 安全性: 可以研究/防御 hypervisor-level rootkit;
IaaS (Infrastructure as a Service)
- 云计算三层服务之一: IaaS / PaaS / SaaS;
- IaaS = 提供虚拟化的计算资源(VM, 存储, 网络);
- 例子:
- AWS EC2: 创业公司快速租用 VM, 按需扩展;
- Google Cloud GPU: 科研人员租用 A100 GPU VM;
- 与论文关系: 云提供商必须支持 nested virtualization, 才能让用户在 VM 内运行自己的 hypervisor;
2. 虚拟化理论基础
Popek–Goldberg (1974)
- 三大条件: 等价性 (equivalence), 资源控制 (resource control), 效率 (efficiency);
- 定理: 如果架构中所有 sensitive 指令 都是 privileged 指令, 则该架构是可虚拟化的;
- 影响:
- 解释了早期 x86 不可完全虚拟化 VMware 使用二进制翻译绕过;
- 推动了 Intel/AMD 添加 VT-x / SVM 硬件扩展;
3. 两种嵌套虚拟化模型
1) Multi-level support
- 硬件直接支持多层 hypervisor;
- Trap 从 L2 直接交给 L1;
- 例子: IBM System z;
- 高效, 但硬件设计复杂; 且一般多层的支持都是有限的, 如只支持两层, 这篇论文是在理论上支持任意层数的嵌套虚拟化, 因此更高层的虚拟化实际上还是依赖于单层虚拟化的软件支持逻辑: compress
2) Single-level support
- 硬件只有一层 root mode (L0);
- 所有 trap(无论来自 L1, L2, L3)都掉到 L0;
- L0 决定是否转发给 L1;
- 例子: x86 的 Intel VT-x (VMX), AMD SVM;
- Multiplexing single-level: L0 将唯一的一层虚拟化能力"复用", 对上层 L1/L2 进行模拟;
4. CPU 虚拟化 (VMX)
VMX & L0
- VMX = Intel VT-x 的指令扩展集;
- L0 = 唯一运行在 VMX root mode 的 hypervisor;
- 所有 VMExit/VMEntry 都必须经过 L0;
Trap 流程: Single-level support: L2 trap L0 trap handler L0 转发给 L1;
5. VMCS (Virtual Machine Control Structure)
VMCS 缓存的内容
- Guest state: guest 的寄存器 (因为这里要仿真一个cpu), CR3 等;
- Host state: VMExit 后 CPU 应该恢复的 hypervisor 状态 (比如 L2 就要缓存 L1和L0 的状态);
- Control fields: 哪些事件触发 VMExit (trap entry), 如何注入事件等;
Host state 的作用
- VMExit 时 CPU 自动加载 host state 从而能继续在 hypervisor 中运行;
- 确保 hypervisor 能恢复运行;
- 在 nested virtualization 中:
- VMCS0$\rightarrow$2 host state = 回到 L0;
- VMCS1$\rightarrow\rightarrow$1 guest state;
- 也就是如果要从 L2 返回到 L1, 就要首先映射到 L0, 然后 L0 根据这个内容来恢复 L1 的状态;
Control data merging
- L0 必须合并 VMCS0$\rightarrow\rightarrow$2 的控制字段 VMCS0$\rightarrow$2;
- 例子: L1 想 trap 事件 EA, 但 L0 不关心 L0 必须在 VMCS0$\rightarrow$2 里设置 trap, 否则 L1 永远收不到;
6. VMCS Merging
定义
- L0 根据 VMCS0$\rightarrow\rightarrow\rightarrow$2(硬件实际使用);
- 这是 L2 L1 切换时的关键步骤;
特点
- 动态发生: 在 VMEntry/VMExit 切换时临时合并;
- 不是一次性存起来: 因为 VMCS 内容会频繁变化;
优化
- Partial copy: 只合并修改过的字段;
- Batch copy: 一次 memcpy 多个字段, 绕过 vmread/vmwrite(但不符合官方规范, 兼容性不保证);
7. 内存虚拟化 (MMU)
Shadow page tables
- 早期方案: L0 维护一张影子页表 (GVAHPA);
- 缺点: 每次 guest 页表修改都要 trap 慢;
硬件二维页表 (EPT/NPT)
- CPU 直接支持两层转换:
GVA GPA (guest page table)
GPA HPA (EPT/NPT)
- 优化了:
- 页表更新 (
MOV CR3,INVLPG) - Page fault(大多数在 guest 内完成, 不再 VMExit)
- TLB flush(VPID tag 支持减少开销)
Multi-dimensional paging
- 在 nested virtualization 下:
- L1 以为自己有 EPT1$\rightarrow$2;
- L0 实际把 EPT0$\rightarrow\rightarrow$2 压缩合并 EPT0$\rightarrow$2;
- 如果有 L3:
- 理论上有 EPT2$\rightarrow$3;
- L0 最终把 EPT0$\rightarrow\rightarrow\rightarrow$3 压缩 EPT0$\rightarrow$3;
- 最终 CPU 只用一张表, 把 L3 GPA L0 HPA;
性能
- 如果不用 multi-dimensional paging: 频繁 VMExit three-fold slowdown(性能下降 3 倍);
- 用了 multi-dimensional paging: 性能接近单层虚拟化;
8. I/O 虚拟化
三种方式
- PIO (Port I/O)
- 专用指令 in/out;
- 在虚拟化中, 几乎总是 VMExit;
- MMIO (Memory-Mapped I/O)
- 把设备寄存器映射到内存地址;
- 虚拟化下:
- 直通设备: 不会 trap;
- 模拟设备: 会 VMExit;
- Device assignment
- 设备直通 性能最好, 但迁移难;
Multi-level device assignment
- L2 也能直通设备;
- L0 通过 IOMMU 把 L2 GPA 映射到 HPA;
- 避免多层拷贝, 性能接近裸机;
9. DMA 地址问题
- 设备 DMA 使用的地址不是 VA, 而是 PA;
- 普通系统: 驱动通过
dma_map_page()提供 PA; - 有 IOMMU: 设备发 IOVA (device virtual address), IOMMU 翻译成 Host PA;
- 虚拟化下:
- guest 提供 GPA;
- L0/IOMMU 翻译成 HPA;
10. Rootkit 与虚拟化
- Rootkit = 获取最高权限并隐藏自身的恶意工具集;
- 分类:
- 用户态(替换 ps/ls);
- 内核态(修改 LKM, 系统调用表);
- 固件/硬件级(BIOS, UEFI);
- 与虚拟化关系:
- Hypervisor-level rootkit: 藏在 L0 层, guest OS 完全无法发现;
11. 性能瓶颈与优化
Transitions between L1 and L2
- 每次切换 L2 VMExit L0 VMCS merging L1 再回到 L2;
- 优化方法:
- 部分复制 VMCS;
- 批量复制 VMCS;
- 避免频繁 vmread/vmwrite;
Exit handling in L1
- L1 用 vmread/vmwrite 访问 VMCS1$\rightarrow$2 每次都要 VMExit 到 L0 开销大;
- 优化: 二进制翻译 vmread/vmwrite 直接读写内存 (DRW, Direct Read/Write);
12. 总结
- 核心贡献:
- 在 x86 上实现高效嵌套虚拟化;
- 提出 multi-dimensional paging (MMU) 和 multi-level device assignment (I/O);
- 性能结果:
- 常见 workload 的开销仅比单层虚拟化多 6–8%;
- 避免 naive 方法的 three-fold slowdown;
- 意义:
- 为云计算 (IaaS), 系统安全, 研究提供嵌套虚拟化能力;
- 推动了 x86 虚拟化架构和 hypervisor 的发展;
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
