前言
本篇文章,主要记录对 Intel x86 架构 CPU 的 VMX 硬件虚拟化技术的学习和研究情况。
参考资料清单如下:
x86 架构虚拟化的障碍
敏感指令定义:
Gerald J.Popek 和 Robert P.Goldberg 指出,修改系统资源的,或者在不同模式下行为有不同表现的,都属于敏感指令。在虚拟化场景下,VMM 需要监测这些敏感指令。
特权指令定义:
一个支持虚拟化的体系架构的敏感指令都属于特权指令,即在非特权级别执行这些敏感指令时 CPU 会抛出异常,进入 VMM 的异常处理函数,从而实现了控制 VM 访问敏感资源的目的。
但是,x86 架构恰恰不能满足这个准则。x86 架构并不是所有的敏感指令都是特权指令,有些敏感指令在非特权模式下执行时并不会抛出异常,此时 VMM 就无法拦截处理 VM 的行为了。
我们以修改 FLAGS 寄存器中的 IF(Interrupt Flag)为例:
- 首先使用指令 pushf 将 FLAGS 寄存器的内容压到栈中,然后将栈顶的IF清零,最后使用 popf 指令从栈中恢复 FLAGS 寄存器。
- 如果虚拟机内核没有运行在 ring 0,x86 的 CPU 并不会抛出异常,而只是默默地忽略指令 popf,因此虚拟机关闭 IF 的目的并没有生效。
有人提出半虚拟化的解决方案,即修改 Guest 的代码,但是这不符合虚拟化的透明准则。
后来,人们提出了二进制翻译的方案,包括静态翻译和动态翻译:
-
静态翻译:运行前扫描整个可执行文件,对敏感指令进行翻译,形成一个新的文件。然而,静态翻译必须提前处理,而且对于有些指令只有在运行时才会产生的副作用,无法静态处理。
-
动态翻译:即在运行时以代码块为单元动态地修改二进制代码,动态翻译在很多 VMM 中得到应用,而且优化的效果非常不错。
Intel VMX 简介
Intel 开发了 VT 技术以支持虚拟化,为 CPU 增加了 Virtual-Machine Extensions,简称 VMX。
两种运行模式:
- VMX root operation(host 模式)
- VMX non-root operation(guest 模式)
每个运行模式都支持 ring 0 ~ ring 3。
如下图所示:
┌──────────────────┐ ┌──────────────────┐│ring3 │ │ring3 ││ │ │ ││ ┌─────────────┐ │ │ ┌──────────────┐ ││ │ Host App │ │ VM Entry │ │ Guest App │ ││ └─────────────┘ │ ─────────► │ └──────────────┘ ││ ──────────────── │ │ ─────────────────┤│ ┌─────────────┐ │ │ ┌──────────────┐ ││ │ Host Kernel │ │ VM Exit │ │ Guest Kernel │ ││ └─────────────┘ │ ◄───────── │ └──────────────┘ ││ │ │ ││ring0 │ │ring0 │└──────────────────┘ └──────────────────┘ VMX Root Mode VMX non-Root Mode
模式切换:
- VM Entry,从 VMX root Mode 切换到 VMX non-root Mode
- VM Exit,从 VMX non-root Mode 切换到 VMX root Mode
一个数据结构:
- Virtual-Machine Control Structure(VMCS)