-
Notifications
You must be signed in to change notification settings - Fork 18
3. CPU 虚拟化
Intel VT-x 技术或 VMX (Virtual-Machine eXtensions) 指令扩展为 x86 处理器提供了硬件虚拟化支持。
启用虚拟化后的处理器处于一种特殊的模式,被称为 VMX operation。VMX operation 又可分为 VMX root operation 和 VMX non-root operation,分别对应 Host 模式与 Guest 模式。从 VMX root operation 切换到 VMX non-root operation 即 VM Entry,反之,从 VMX non-root operation 切换到 VMX root operation 即 VM Exit。
VMX 中有个重要的结构:Virtual-Machine Control Structure (VMCS),可认为是一段特殊的内存区域,用于对 root/non-root 模式的切换进行控制、保存 guest/host 的状态等。其中可以存储许多字段,包括以下 4 类,访问它们需要用到专门的指令(VMREAD
/VMWRITE
):
- 控制字段:对 VM entry/exit/execution 时的行为进行配置;
- 只读字段:提供 VM Exit 时的一些信息;
- Guest 状态:存放 Guest 的一些控制寄存器、段寄存器、RIP、RSP 等,会在 VM Entry 时载入进 CPU,VM Exit 时保存到 VMCS;
- Host 状态:存放 Host 的一些控制寄存器、段寄存器等、RIP、RSP 等,会在 VM Exit 时载入进 CPU,VM Entry 时保存到 VMCS。
VMX 提供了一些特殊指令,常用的几条如下:
- VMXON:进入 VMX (root) operation
- VMXOFF:离开 VMX operation
- VMPTRLD:激活给定物理地址上的 VMCS
- VMCLEAR:清理给定物理地址上的 VMCS
- VMREAD:读 VMCS 字段
- VMWRITE:写 VMCS 字段
- VMLAUNCH/VMRESUME:进入 VMX non-root operation,首次进入要用 VMLAUNCH,之后每次用 VMRESUME
官方文档:
基于 Intel VMX,创建和启动一个 Guest 和 vCPU 的流程如下:
-
RVM_GUEST_CREATE
:- 分配 VMXON 所需的 4096 字节大小的物理内存;
- 执行 VMXON,进入 VMX root operation;
-
RVM_VCPU_CREATE
:- 分配 VMCS 所需的 4096 字节大小的一页物理内存;
- 执行 VMCLEAR 和 VMPTRLD,激活该地址上的 VMCS;
- 对 VMCS 进行初始配置,包括控制字段、Guest 状态、Host 状态;
-
RVM_VCPU_RESUME
:- 保存 Host 通用寄存器到栈上,并载入 Guest 通用寄存器;
- 执行 VMLAUNCH/VMRESUME,进入 VMX non-root operation,开始 Guest 的运行;
- 发生 VM Exit:
- 处理器自动回到 VMX root operation;
- 保存 Guest 通用寄存器到栈上,并恢复 Host 通用寄存器;
- 根据 VMCS 中的 Exit reason 字段,进行相应的处理;
- 回到第 3 步继续执行 Guest;
- 结束:
- 执行 VMCLEAR,清理 VMCS;
- 执行 VMXOFF,退出 VMX operation。
其中,在第 4 步最后也可不回第 3 步,而是返回到用户态,由用户程序来处理 VM Exit,一般用于 I/O 操作的模拟。考虑到这种情况,用户程序执行 RVM_VCPU_RESUME
时的流程可以用下图表示:
运行在 ring3 的用户程序通过系统调用进入 ring0,此时处理器也处于 VMX root operation,通过 VMLAUNCH/VMRESUME 进入 VMX non-root operation,开始 Guest 的运行。
Guest 运行过程中会因某些原因发生 VM Exit,自动退回到 VMX root operation。对于可以完全由 RVM 处理的 VM Exit,处理完后就可以继续执行 VMRESUME 来运行 Guest;不过也有一些 VM Exit 还需由用户程序处理,一般是 I/O 操作,这时就进行系统调用返回,将 I/O 操作转发给用户程序,回到 ring3 继续执行。
用户程序处理完后,可再次进行系统调用,重复刚才的流程。
类似于对中断处理,发生 VM Exit 后也需要根据退出原因进行相应的处理。退出原因保存在 VMCS 的 Exit reason 字段。RVM 中处理的主要几类 VM Exit 如下:
- External interrupt:启用 VMX 后,外部中断不再使用基于 IDT 的中断处理流程,而是会发生该类 VM Exit,此时需要手动跳转到中断处理例程。
- CPUID:Guest 执行 CPUID 指令,获取处理器的一些信息。
- VMCALL:Guest 执行 VMCALL 指令,进行一次 hypercall。
- I/O instruction:Guest 执行 IN/OUT 等 I/O 指令,用于设备的模拟。
- EPT violation:Guest 访问 EPT 中没有映射的物理地址,可用于实现 EPT 延迟映射或 MMIO。