文章目录
- 前言
- 一、VMX
- 1.1 处理器是否支持VMX
- 1.2 CPU虚拟化
- 1.3 VMX 简介
- 二、VMCS
- 2.1 VMCS
- 2.2 VMCS data
- 2.3 VMCS launch state
- 2.4 VCPU
- 总结
- 参考资料
前言
本篇文章主要描述了Intel cpu虚拟化的知识,关于虚拟化的简介可以参考这篇文章:
虚拟化技术简述
wiki上面关于虚拟化的定义:
在计算机领域,虚拟化指创建某事物的虚拟(而非实际)版本,包括虚拟的计算机硬件平台、存储设备,以及计算机网络资源可见。
虚拟化是一种资源管理技术,它将计算机的各种实体资源(CPU、内存、存储、网络等)予以抽象和转化出来,并提供分割、重新组合,以达到最大化利用物理资源的目的。
简图如下:
一、VMX
1.1 处理器是否支持VMX
通过cpuid指令判断当前处理器是否支持VMX,输入参数01,判断ECX寄存器中的返回信息的bit5,如果该bit为1代表支持VMX。
VMX:VMX全称 virtual-machine extensions,是Intel为支持处理器硬件虚拟化而引进的一个扩展特性,即Intel的VT(Virtualization Technology)技术,属于硬件虚拟化技术。
1.2 CPU虚拟化
CPU是计算机系统最核心的模块,我们的程序执行到最后都是翻译为机器语言在CPU上执行的。在没有CPU硬件虚拟化技术之前,通常使用指令的二进制翻译(binary translation)来实现虚拟客户机中CPU指令的执行,很早期的VMware就使用这样的方案,其指令执行的翻译比较复杂,效率比较低。
Intel最早发布的虚拟化技术就是CPU虚拟化方面的,引入VT-x硬件虚拟化技术。
1.3 VMX 简介
VMX支持两种主要类型的软件:
(1)Virtual-machine monitors (VMM):虚拟机监控器。VMM作为host,完全控制处理器和其他平台硬件,VMM为来Guest software提供了虚拟处理器的抽象,并允许它直接在逻辑处理器上执行。VMM会保留对处理器资源、物理内存、中断和 I/O 的控制。
(2)Guest software(VM):每个虚拟机的软件栈环境由操作系统和应用软件组成,每个虚拟机都独立于其他虚拟机进行操作,并且使用物理平台提供的与处理器、内存、存储、图形和I/O相同的接口。虚拟机的操作权限必须低于VMM的操作去权限,以便VMM能够保留对物理硬件资源的控制。
VMX提供了处理器的操作叫做VMX operation,有两种类型:
(1)VMX root operation: VMM运行在root mode。
(2)VMX non-root operation:VM运行在 non-root mode。
从 VMX root operation 到 VMX non-root operation之间的转换叫做 VMX transitions,有两种类型:
(1) VMX Entry :从VMX root operation到 VMX non-root operation 。即进入虚拟机。
(2) VMX Exit :从VMX non-root operation 到 VMX root operation 。即退出虚拟机。
VMX提供了两条VMX 指令:
(1)VMXON:Enter VMX Operation。
(2)VMXOFF:Leave VMX Operation。
如下图所示:
VMX root operation和VMX non-root operation 下最初的处理器执行模式基本一样,只是它现在支持了新的VMX相关的指令集以及一些对相关控制寄存器的操作。VMX non-root operation是一个相对受限的执行环境,为了适应虚拟化而专门做了一定的修改;在客户机中执行的一些特殊的敏感指令或者一些异常会触发“VM Exit”退到虚拟机监控器中,从而运行在VMX root operation。正是这样的限制,让虚拟机监控器保持了对处理器资源的控制。
简单点说虚拟机上大部分指令都是再自己的逻辑处理器上运行的,只有执行少部分的敏感指令时退出VM,让VMM来执行这些敏感指令。这些敏感指令一般都是些要修改系统资源的,VMM要检测这些指令。
这么做的原因之一:发生一次VM Exit的代价比较高(一次VM Exit可能会消耗成百上千个CPU执行周期,而平时很多指令是几个CPU执行周期就能完成),应该减少VM Exit 行为。
x86 提供了分层的权限机制,把区域分成了四个 ring,从ring 0 到 ring3 ,ring0权限最高,通常用于操作系统内核, ring3权限最低,用于应用程序。Linux系统仅仅使用 ring 0 和 ring3。
把这个分层模式加入虚拟化 就变成了如下所示(这里以host os kvm虚拟化为例子):
二、VMCS
我们知道Linux调度器在调度时会进行任务上下文的切换,这就伴随着会有上下文的保存与恢复:如虚拟地址空间,内核态堆栈,以及一些寄存器等,那么VMX root operation 到 VMX non-root operation之间的转换呢?同一个物理CPU分时运行着 host 和 guest ,在root mode 和 non-root mode之间按照实际情况进行切换时,不同模式之间的切换也要保存着上下文。那么保存上下文的结构是什么呢?VMX设计了一个数据结构:VMCS,用来保存每个模式的上下文。
2.1 VMCS
VMCS:全称virtual-machine control data structure。逻辑处理器(虚拟处理器)在 VMX operation 时使用该结构管理进入和退出VMX non-root operation (VM entries and VM exits)之间的转换,以及 VMX non-root operation中的处理器行为。该结构是由新的指令控制的: VMCLEAR, VMPTRLD, VMPTRST、VMREAD和 VMWRITE。
VMCS的访问是通过VMCS pointer 来操作的。VMCS pointer 是一个指向VMCS结构的64位的地址。
使用VMCLEAR、VMPTRLD、VMPTRST指令对VMCS pointer进行读写。
使用MREAD、VMWRITE等指令对VMCS实现配置,即:读写VMCS这段内存空间需要使用VMREAD和VMWRITE指令。
VMM可以为其支持的每个虚拟机使用不同的VMCS,对于具有多个逻辑处理器(虚拟处理器)的虚拟机,VMM可以为每个虚拟处理器使用不同的VMCS。即:一个VMCS与一个虚拟CPU对应,一个VMM会为一个VM上的每一个逻辑处理器维护一个VMCS数据结构。
一个逻辑处理器可以维护许多 active 状态 的VMCSs。处理器可以通过在内存或处理器上维护 active VMCS的状态来优化VMX操作,在任何时间,最多只有一个active VMCS是the current VMCS。VMLAUNCH、VMRESUME、VMREAD、VMWRITE指令只能 操作 the current VMCS,不能操作其它的 the active VMCSs。
备注(个人理解):
这里的处于 active 状态 的VMCS就是类似于Linux中的处于就绪态的任务。
这里的处于 current 状态 的VMCS就是类似于Linux任务正在执行当中的任务,Linux内核中也是用 current标识符来表示正在执行中的任务。
active 状态 的VMCS 和 current 状态 的VMCS就是等价于 Linux任务中 处于RUNNING状态的任务。
任何时刻,所有处于 active 状态 的VMCSs只有一个是current 状态。
逻辑处理器如何确定哪些VMCS 是 active 状态,哪些是current 状态的呢?
(1) VMPTRLD指令的内存操作数是一个VMCS的地址(即VMCS pointer),在执行指令之后,该VMCS在逻辑处理器上既是active,也是current。因此其他处于active状态的VMCS仍然是active状态,不能有其他的VMCS是current状态。
(2)VMCLEAR指令的内存操作数也是一个VMCS的地址(即VMCS pointer),在执行指令之后,在逻辑处理器上该VMCS既不是active,也不是current。如果该VMCS当前位于一个逻辑处理器上,则逻该辑处理器不再有current状态的VMCS。
VMPTRST指令将逻辑处理器 的current VMCS的地址存储到指定的内存位置。
备注(个人理解):
VMPTRLD指令让VMCS处于active状态,并且是current状态,也就类似于linux中将一个任务变为就绪态,并且立马投入运行,即处于current状态。
VMCLEAR指令让VMCS不再是active状态和current状态,也就类似于linux中该任务不再是就绪态,也就不会再被调度执行。
VMPTRLD:vm ptr load ,从指定的内存地址中读出VMCS,使其处于current状态,即:让某个VMCS在当前生效,而其他VMCS就自然成为不是当前生效的。
VMPTRST: vm ptr store,将current VMCS存储在指定的内存地址中。
2.2 VMCS data
逻辑处理器将内存中的一个区域与每个VMCS相关联,这个区域称为 VMCS region。
一个 VMCS region的大小为4-KBytes,确切的大小取决于具体的实现,可以通过查询VMX capability MSR寄存器: IA32_VMX_BASIC来确定VMCS region 的大小。
对于 VMCS region ,我们关心的是VMCS region中的VMCS data部分,对于VMCS region 前八个字节我们不太关心,VMCS region剩下的部分都是VMCS data。
VMCS data由6个部分组成,可以分为两大类,一类是状态:包括Guest和Host的状态。另一类则是控制Guest运行时的行为。
(1)Guest-state area: 保存虚拟机状态的区域。当VM exits时处理器的状态被保存在guest-state area ,当VM entry时处理器的状态从guest-state area加载。这些都是在硬件层面上的行为,我们软件编码时无须关心。
(2)Host-state area:保存宿主机状态的区域。当VM entry时,CPU将宿主机的状态保存在该区域;
当VM exits时,CPU从VMCS中恢复宿主机的状态到物理CPU中。
(3)VM-execution control fields :控制 VMX non-root operation中的处理器行为,在一定程度上决定了VM exits 的原因,比如:VMM可以让某些特权指令不产生VM exit,以减少mode切换带来的上下文开销。
(4)VM-exit control fields: control VM exits,管理虚拟机退出的行为。
(5)VM-entry control fields:control VM entries,管理进入虚拟机的行为。
(6)VM-exit information fields:保存VM-exit 的信息,并描述VM exit 的原因和性质,退出的信息供VMM使用。在一些处理器上,这些字段是只读的。但VM发生 VM exit时,VMM需要知道导致VM exit的原因,然后才能进行相应的模拟功能。
备注:mode切换时并不是所有寄存器的值都恢复,由于这些信息一直保存在VMCS中的,可以等到该寄存器真正被guest使用到时再恢复,这就是Lazy Save/Restore,其基本思想是尽量将寄存器的保存/恢复延迟到最后一刻,减少无用功,提高上下文切换的效率。
2.3 VMCS launch state
软件可以使用VMLAUNCH和VMRESUME这两种 VM-entry instructions 进入VMX non-root operation。
VMCS的 launch state 决定了该VMCS应该使用哪条VM-entry instruction。
只有当VMCS的 launch state 是 clear 才能使用 VMLAUNCH 指令,同时只有当VMCS的 launch state 是 launched 才能使用 VMRESUME 指令。VMLAUNCH 指令应该用于VMCLEAR之后的第一个VM entry,VMRESUME应该用于相同VMCS的后续VM entry。
VMLAUNCH指令需要一个launch state 为 “clear” 的VMCS;
VMRESUME指令要求VMCS的launch state 为“launch”。
逻辑处理器在相应的VMCS区域中维护VMCS的 launch state。
备注(个人理解):
(1)当第一次进入VMX non-root operation(VM),即First VM entry,则要使用 VMLAUNCH 指令。
此时VMCS的 launch state 是 “clear”。
(2)后续 的 VM-entry(不是第一次)则使用 VMRESUME 指令。RESUME的意思就是恢复,(中断后)重新开始。此时VMCS的launch state 为“launch”。
一个逻辑处理器如何管理一个VMCS的 launch state的呢?
(1)如果 current VMCS 的 launch state为“clear”,则执行VMLAUNCH指令成功后, launch state 变为“launched”。
(2)VMCLEAR指令的内存操作数是VMCS的地址。执行指令后,该VMCS的 launch state为“clear”。
(3)没有其他方法可以读取修改VMCS的 launch state(不能使用VMWRITE修改,不能使用VMREAD读取)。
下图说明了VMCS X的不同状态,即在执行下面这些指令后,Current VMCS的状态变化情况:
(“X”表示Current VMCS,“Y”表示其他的VMCS。)
主要是三种状态的转换:
(1)active 与 inactive 之间的转换。
(2)current 与 not current 之间的转换。
(3)clear 与 lauched 之间的转换。
关于上图的解释:我觉得英文很容易理解,就没有翻译了。
(1)VMPTRLD X always makes X current and active.
(2)VMPTRLD Y always makes X not current (because it makes Y current).
(3)VMCLEAR X always makes X inactive and not current and makes its launch state “clear”.
(4)VMLAUNCH makes the launch state of X “launched” if X was current and its launch state was “clear”.
2.4 VCPU
VCPU,即虚拟处理器。每个虚拟机可能会有多个虚拟处理器。
虚拟机把VCPU当成真正的CPU,虚拟机在VCPU上调度着自己的任务,VMM给VM分配VCPU,在物理CPU上调度VCPU。
前文提到过一个VMCS与一个VCPU相对应,并不是一个VM对应一个VMCS,一个VM可以使用多个VCPU。
VM使用的多个VCPU可能是共享同一个物理CPU。VMM负责VCPU的调度,当一个VCPU被调度到获得物理CPU的使用权后,基于该VCPU运行的VM OS又可以调度OS中的各个task(线程/进程)了。也就是说,VM中的各个task分时复用了VCPU,而各个VCPU又分时复用了物理CPU。
总结
以上就是对Intel 虚拟化的简单介绍,主要参考了Intel官方手册 vol 3 Chapter 23、24。
参考资料
Intel官方手册 vol 3
KVM实战:原理、进阶与性能调优
深度探索Linux系统虚拟化
https://zhuanlan.zhihu.com/p/69625751