VMM 对物理资源的虚拟可以划分为三个部分:处理器虚拟化、内存虚拟化和 I/O 虚拟化(设备)。其中以处理器的虚拟化最为关键。
0. 体系结构背景
简而言之,处理器呈现给软件的接口就是一堆的指令(指令集)和一堆的寄存器(含用于通用运算的寄存器和用于控制处理器行为的状态和控制寄存器)。而 I/O 设备呈现给软件的接口也就是一堆的状态和控制寄存器(有些设备亦有内部存储)。这些都是系统的资源,其中影响处理器和设备状态和行为的寄存器称为关键资源 或特权资源,如 x86 之 CR0 ~ CR4,MIPS 的 CP0 寄存器,PowerPC 的 Privileged SPR(SPR 编号第 5 位为 1)。
可以读写系统关键资源的指令叫做敏感指令,如 x86 的 lgdt/sgdt/lidt/sidt/in/out,MIPS 的 mtc0/mfc0,PowerPC 的 mtmsr/mfmsr,SPARC 的 rdpr/wrpr 等,此类又可称为控制敏感指令。
还有一类
行为敏感指令
,该类指令的执行结果依赖于系统的状态(如 x86 之 popf)
现代计算机体系结构一般至少有两个特权级,(即用户态和核心态,未加虚拟化扩展的 SPARC和PowerPC 即是,MIPS 有三个特权级(外加一个 Supervisor 态,没什么用),而 x86 有四个特权级 (Ring0 ~ Ring3))用来分隔系统软件和应用软件。
决大多数的敏感指令是特权指令,特权指令只能在处理器的最高特权级(内核态)执行,如果执行特权指令时处理器的状态不在内核态,通常会引发一个异常而交由系统软件来处理这个“非法访问”(陷入)。
少数敏感指令是非特权指令,如 x86 的 sgdt/sidt 等,非特权指令可以在用户态读取处理器的状态,如 sgdt/sidt 则可在用户态 (Ring3) 将 GDTR 和 IDTR 的值读取到通用寄存器中。
对于一般 RISC 处理器,如 MIPS,PowerPC 以及 SPARC,敏感指令肯定是特权指令,唯 x86 例外。
1. 经典的虚拟化方法
经典的虚拟化方法主要使用“特权解除” (Privilege deprivileging) 和“陷入-模拟” (Trap-and-Emulation) 的方式。即:将 Guest OS 运行在非特权级(特权解除),而将 VMM 运行于最高特权级(完全控制系统资源)。解除了 Guest OS 的特权后,Guest OS 的大部分指令仍可以在硬件上直接运行,只有当执行到特权指令时,才会陷入到 VMM 模拟执行(陷入-模拟)。其早期的代表系统是 IBM VM/370
由此可引入虚拟化对体系结构 (ISA) 的要求:
A.
须支持多个特权级
此亦是现代操作系统的要求
B.
非敏感指令的执行结果不依赖于 CPU 的特权级
“陷入-模拟” 的本质是保证可能影响 VMM 正确运行的指令由 VMM 模拟执行,大部分的非敏感指令还是照常运行。
C.
CPU 需支持一种保护机制,如 MMU,可将物理系统和其它 VM 与当前活动的 VM 隔离
以上三个条件,现代体系结构一般都满足,唯有最后一个也是最重要的条件:
D. 敏感指令需皆为特权指令
此为保证敏感指令在 VM 上执行时,能陷入到 VMM.
因控制敏感指令的执行可能改变系统(处理器和设备)的状态,为保证 VMM 对资源的绝对控制力维护 VM 的正常运行,这类指令的执行需要陷入而将控制权转移到 VMM,并由其模拟处理之。
行为敏感指令的执行结果依赖于 CPU 的最高特权级,而 Guest OS 运行于非最高特权级,为保证其结果正确,亦需要陷入 VMM,并由其模拟之。
2. x86 ISA 分析
x86 ISA 中有十多条敏感指令不是特权指令,因此 x86 无法使用经典的虚拟化技术完全虚拟化。
如:sgdt/sidt/sldt 可以在用户态读取特权寄存器 GDTR/IDTR/LDTR 的值;popf/pushf 在 Ring0 和 Ring3 的执行结果不同;其它的还有 smsw, lar, lsl, verr, verw, pop, push, call, jmp, int n, ret, str, move
关于这些指令的详细分析可以参见:"Analysis of the Intel Pentium's Ability to Support a Secure Virtual Machine Monitor"
3. x86 虚拟化方法
鉴于 x86 本身的局限,长期以来对 x86 的虚拟化都是通过软件方式实现,后来 Intel 和 AMD 都引入各自的硬件虚拟化技术来弥补处理器的缺陷。
3.1
基于二进制翻译 (BT) 的全虚拟化 (Full virtualization)
其主要思想是在执行时将 VM 上执行的 Guest OS 之指令,翻译成 x86 ISA 的一个子集,其中的敏感指令被替换成陷入指令。翻译过程与指令执行交叉进行。不含敏感指令的用户态程序可以不经翻译直接执行。该技术为 VMWare Workstation,VMWare ESX Server 早期版本,Virtual PC 以及 QEMU 所采用。
3.2
基于扫描与修补 (Scan-and-Patch) 的全虚拟化 (Full virtualization)
主要思想:
(1) VMM 会在 VM 运行每块指令之前对其扫描,查找敏感指令
(2) 补丁指令块会在 VMM 中动态生成,通常每一个需要修补的指令会对应一块补丁指令
(3) 敏感指令被替换成一个外跳转,从 VM 跳转到 VMM,在 VMM 中执行动态生成的补丁指令块
(4) 当补丁指令块执行完后,执行流再跳转回 VM 的下一条指令处继续执行
SUN 之 Virtualbox 即采用该技术。
3.2
OS 协助的类虚拟化 (Paravirtualization)
其基本思想是通过修改 Guest OS 的代码,将含有敏感指令的操作,替换为对 VMM 的超调用 (Hypercall,类似 OS 的系统调用,可将控制权转移到 VMM)。该技术的优势在于 VM 的性能能接近于物理机,缺点在于需要修改 Guest OS.
该技术因 Xen 项目而广为人知。
目前嵌入式领域的虚拟化,考虑到性能的因素,亦会在可以使用经典虚拟化方法实现全虚拟的体系结构上采用类虚拟化技术。
3.3
硬件协助的虚拟化
鉴于 x86 在虚拟化上的缺陷,Intel 和 AMD 都引入自己的硬件虚拟化技术来协助完成虚拟化。
Intel VT-x (Virtualization Technology for x86)
Intel VT-i (Virtualization Technology for Itanium)
Intel VT-d (Virtualization Technology for Directed I/O)
AMD-V (AMD Virtualization)
其基本思想就是引入新的处理器运行模式和新的指令,使得 VMM 和 Guest OS 运行于不同的模式下,Guest OS 运行于受控模式,原来的一些敏感指令在受控模式下全部会陷入 VMM。而且模式切换时上下文的保存恢复由硬件来完成。
该技术的引入使 x86 可以很容易地实现完全虚拟化。其被 KVM-x86,新版 VMWare ESX Server 3,Xen 3.0 以及大量 x86 平台上的虚拟化软件所采用。
4. 其它体系结构分析
其它 RISC 之体系结构,如 MIPS, PowerPC, SPARC 等,似乎不存在有敏感指令为非特权指令的情形。即它们应该不存在虚拟化的困难。.
5. 其它体系所采用之虚拟化方法
目前可见的非 x86 体系的虚拟化产品,似乎都倾向于使用类虚拟化的技术手段。