由于软件虚拟化带来的内存“影子页表”,以及I/O 虚拟化的性能不佳,最后Intel Virtualization Technology (Intel VT)才是王道。Intel VT 包括了CPU(VT-x)、内存(EPT)和I/O设备(VT-d)等各方面的虚拟化支持。

VT -x 的思路,是引入了两种模式,统称为VMX操作模式。

  • VMX Root Operation :VVM运行所处的模式,以下简称根模式。
  • VMX Non-Root Operation:客户机运行所处的模式,简称非根模式。

关于敏感指令不能通过陷入再模拟的方式实现,导致的虚拟化漏洞。在Vt-x 的解决思路是,非根模式下所有的敏感指令的行为被重新定义,使得不经过虚拟化就直接运行或者通过“陷入再模拟”的方式来处理;

VT-x中,非根模式下敏感指令引起的“陷入”被称为VM-Exit。当发生VM-Exit 是,CPU自动从非根状态切换成根状态。相应的就有VM-Entry 状态,由VMM发起,通常是调度某个Guest运行,此时CPU从根模式切换成非根模式。

VMCS

VMCS(Virtual-Machine Control Structure,虚拟机控制结构),保存了CPU对于虚拟需要的状态,例如根模式和非根模式下的特权寄存器的值。VMCS主要供CPU使用,CPU在VM-Exit 、VM-Entry的时候,都会自动查询和更新VMCS。VMM可以通过指令来配置VMCS,进而影响CPU的行为。

VMCS与之前提到的虚拟机寄存器的概念类似,可以看作其在硬件上的应用。虚拟寄存器的操作和更改完全由软件执行,但VMCS却主要由CPU操作。VMCS是存储在内存上的数据结构,包括虚拟CPU相关的寄存器和控制信息,每个VMCS对应一个虚拟CPU。

尽管使用时需要与CPU绑定,VMCS与CPU是一对一的绑定关系,但是可以在不同的时刻绑定到不同的CPU,称作“迁移”(Migration)。

VMCS 包括六类信息

  1. Guest 状态域(Guest State Area):非根模式时的CPU状态
  2. Host状态域(Host State Area):根模式时的CPU状态
  3. VM-Entry 控制域:
  4. VM-Execution 控制域
  5. VM-Exit 控制域
  6. VM -Exit 信息域

VM-Entry/VM-Exit

VM-Entry

VT-x 为VM-Entry 提供两种指令

  • VMLAUCH:用于执行过VMCLEAER 的VMCS的第一次VM-Entry
  • VMRESUME:用于执行过VMLAUNCH的VMCS的后续VM-Entry 在发起指令时,VMM会设置好VMCS相关域的内容。 ###VM-Exit 1.非根模式下的敏感指令 敏感模式下在VMX非根模式,行为·可能会发生变化。
    1. 行为不变化,但是不引起VM-Exit
    2. 行为变化,产生VM-Exit:这就是典型的需要截获并模拟的敏感指令
    3. 行为变化,产生VM-Exit可控:具体敏感指令是否产生VM-Exit,可以通过VM-Execution域控制。处于优化的目的,VMM可以让某些敏感指令不产生VM-Exit,以减少模式切换带来的上下文开销。
  1. VM-Execution 控制域
    VMM可以通过配置VM-Execution 控制域用来控制CPU非根模式运行时的行为,包括

    1. 某些敏感指令是否产生VM-Exit
    2. 如果某些敏感指令不产生VM-Exit时,控制该指令的行为
    3. 异常和中断是否产生VM-Exit
  2. VM-Exit 控制域
    规定了VM-Exit发生时Cpu的行为

  3. VM-Exit 信息域
    提供了VM-Exit相关的信息,包括:VM-Exit 的进一步原因,事件触发导致的VM-Exit信息、事件注入导致的VM-Exit信息、执行指令导致的VM-Exit的信息

基于硬件的CPU虚拟化的实现

硬件虚拟化使用VCPU描述符虚来描述虚拟CPU,软件虚拟技术使用“CPU执行环境处理器”来描述虚拟CPU。VCPU描述符类似操作系统中进程描述符(或进程控制块),本质是一个结构体,由

1.VCPU标识

2.虚拟寄存器信息

3.VCPU状态信息

3.额外寄存器/部件信息

4.其他信息

VCPU的创建

创建VCPU实际上是创建VCPU描述符,本质上是一个结构体,而且这个结构体可以有多级结构,所谓的初始化,也就是初始化这个描述符,模拟的就是CPU上电初始化的过程。

初始化包括以下内容:

1. 分配VCPU标识:标识所属Guest

2. 初始化虚拟寄存器:初始化VMCS

3. 初始化VCPU状态信息:设置VCPU被调用前需要配置的必要标志

4. 初始化额外部件:将未被VMCS包含的虚拟寄存器初始化为CPU上电后的值

5. 初始化额外部件:根据VMM的初始化VCPU的私有数据

VMCS的创建与初始化

VMCS只需要分配4KB大小,并且对齐到4K边界的内存即可,并且初始化之前提到的VMCS六类信息

VCPU 的运行

VCPU创建后,就可以通过调度程序被调度运行。调度程序会根据一定的策略算法来选择VCPU运行。下面接触的是在选定VCPU后,如何将VCPU切换到物理CPU上运行。

1.上下文切换

我们提到在Intel VT-x 中,VCPU的上下文分为两个部分,所以切换也分为有硬件自动切换(VMCS部分)和VMM切换(非VMCS部分)。其中硬件切换可以保证VMM与客户机的隔离,但缺乏灵活性。软件切换部分则可以由VMM自己选择地切换需要的上下文,(比如:浮点寄存器就不需要每次都切换),从而有更大的灵活性并节省切换的开销。

我们知道上下文切换频繁会带来不小的切换开销,因此对上下文切换非常有必要,VMM使用了“惰性保存/恢复(Lazy Save/Restore)”

2.VCPU的硬件优化

Intel-x 提供两种优化,目的在于尽可能少地在Guest和VMM之间切换,减少切换上下文的开销。

1. 无条件优化:以往在软件虚拟技术下必须陷入到VMM中的敏感指令,通过Intel VT-x 已可以在Guest中直接执行

2. 条件优化:通过VMCS中VM-Execution控制域,可以配置某些敏感指令是否产生VM-Exit 而陷入到VMM中。

VCPU 的退出

VM-exit 的退出,就涉及到上下文的切换,这个时候就用上了VMCS

VCPU 原因大体上有三类:

  1. 访问了特权资源,对CR和MSR寄存器的访问都属于这一类。 对于这类VM-Exit,VMM通过特权资源的虚拟化来解决,要点在于让Guest认为自己完全拥有特权资源。VMM 通过引入"虚拟特权资源"和“影子特权资源“来解决。 "虚拟特权资源":Guest 所看到的特权资源,VMM允许其自由读写 "影子特权资源“:Guest运行时特权资源真实的值,通常是VMM通过"虚拟特权资源"的基础上经过处理得到的。

2.Guest 执行的指令引发了异常,如缺页错误。

具体的情况具体分析,调用对应的虚拟模块来处理

3.发生了中断

  • 真实的物理中断:VMM先读取VMCS的VM-Exit interruption information 字段来获得中断向量号,然后调用VMM中赌赢的中断处理函数
  • Guest的虚拟设备发生了模拟中断:VMM在捕获了虚拟中断时,会把该虚拟中断的目标VCPU拖到VMM中,然后,在处理函数中把中断注入到Guest,Guest OS 自行处理.

VPU 的再运行

VMM在处理完VCPU 的退出后,会负责将VCPU投入再运行。我们有两点要考虑。

  1. 如果VCPU可以继续在同一个CPU上运行,可以使用VMRESUME来实现VM-Entry,比VMLAUNCH更轻量,执行效率更高。因此,作为优化,VMM调度程序通常会将VCPU调度在同一个CPU上
  2. 如果VCPU发生了了迁移 2.1 VCPU对应的VMCS迁移到另一个物理CPU 2.2 迁移完成后要重新绑定,然后执行VMLAUNCH发起VM-Entry.

中断虚拟化

其实就是为了模拟出物理机中断的流程

虚拟PIC

PIC只适用域单CPU系统

虚拟I/O APIC

对于多CPU,必须通过I/O APIC 来发送中断。

虚拟Local APIC

Local APIC 是CPU上的内部部件,负责接收中断以及产生中断的功能。

中断采集

中断的采集和注入。

中断的采集是指如何将VM的设备中断请求送入虚拟中断控制器。在虚拟机环境中,客户机中断由两种可能的来源。

  1. 来自软件模拟的虚拟设备,例如一个虚拟出来的串口,可以产生一个虚拟中断。
  2. 来自直通的设备,例如虚拟网卡,可以产生一个真正的物理中断。

前者比较简单,后者则相对复杂。

如果是虚拟设备,可以通过虚拟(A)PIC提供的接口函数发出中断请求

如果是物理设备,由于物理中断发生在Guest OS内,物理中断控制由VMM控制,因此要先给VMM的中断处理函数接收,然后再注入Guest

中断注入

首先是如何需要注入的最高优先级中断的相关信息,其次是如何才能将一个中断 注入Guest 的VCPU.

第一个问题,由于虚拟中断控制器提供了将中断按照优先级排序,VMM只需要调用虚拟中断控制器提供的接口函数,就可以获得当前最高优先级中断的信息

第二个问题,虚拟Local APIC 提供了将中断注入Guest VCPU最基本的功能。