1.1.1 CPU虚拟化

1.虚拟化技术概述

对直接运行在硬件上的操作系统(见图1-1a)而言,CPU的虚拟化就是对CPU资源的分时复用。vCPU本质上是一小段在pCPU(Physical CPU,物理CPU)运行的时间片。当一个进程独占CPU运行一段时间被中断后,操作系统会保存当前进程的上下文,然后恢复另一个进程的上下文,一段时间后重复类似操作。上述过程在主流操作系统(比如Linux)中一般每10ms发生一次。


提示:此时的vCPU和pCPU虽然概念上是类似的,但实现上并不相同。vCPU包含虚拟用户模式和虚拟特权模式,pCPU包含原生用户模式和原生特权模式。vCPU的虚拟特权模式或由Hypervisor模拟实现,或由vCPU和Hypervisor协作实现。


当部署Hypervisor时,如图1-1b所示,Hypervisor运行在pCPU的特权模式下,原本直接运行在原生硬件上的操作系统改变为运行在Hypervisor创建的虚拟机中,并且降级到用户模式运行。此时Hypervisor需要解决的问题不仅是pCPU的分时复用,还涉及映射到虚拟机中的vCPU特权指令的模拟问题。因为虚拟机中的操作系统仍然会执行它所认为的特权指令,这才是CPU虚拟化所要解决的关键问题。

图1-1 传统操作系统模式和Hypervisor运行模式

为了能更清楚地描述CPU的虚拟化问题,计算机科学领域的著名学者杰拉尔德·J.波普克(Gerald J. Popek)和罗伯特·P.戈德堡(Robert P. Goldberg)在1974年发表的论文《第三代可虚拟化架构的正式要求》中引入了特权指令和敏感指令的概念,并将CPU的指令集分为3类:特权指令、控制敏感指令和行为敏感指令。其中,控制敏感指令是指试图修改系统中资源配置状态的指令,包括更新虚拟地址到物理地址的映射、修改与设备通信或使用系统全局配置相关的寄存器指令等;行为敏感指令的行为或结果取决于系统的资源配置状态,例如对虚拟内存进行加载和存储操作的指令就属于行为敏感指令。

这些概念的引入对虚拟化和操作系统的设计非常重要,这3类指令的拦截和模拟是虚拟化技术实现的核心。这篇论文为虚拟化技术的发展奠定了基础,并对后续的研究和实践产生了深远影响。

CPU可虚拟化的充分条件是所有敏感指令(包括控制敏感指令和行为敏感指令)必须是特权指令集合的子集。Hypervisor利用特权指令实现对敏感指令的拦截和处理,以控制虚拟机对底层硬件的访问,实现对虚拟机的隔离和资源分配。Hypervisor负责解释敏感指令或修改其行为,或将敏感指令传递给底层物理硬件进行处理。这样的机制允许Hypervisor实现虚拟机的隔离、资源调度、内存虚拟化和设备模拟等功能。

2.虚拟化技术的类型

从客户操作系统的角度来说,CPU虚拟化行为可以分成两类。

(1)完全模拟原生pCPU的行为

完全模拟原生pCPU的行为,客户操作系统将完全不需要修改就可以直接在虚拟机中运行,就像运行在原生物理设备上一样。因此客户操作系统感知不到Hypervisor的存在。

(2)非完全模拟原生pCPU的行为

非完全模拟原生pCPU的行为需要客户操作系统和Hypervisor相互配合来实现客户操作系统的服务,因此客户操作系统可以感知到Hypervisor的存在。

3.虚拟化技术的原理

具体采用哪一种虚拟化技术实现Hypervisor,取决于CPU ISA(Instruction Set Architecture,指令集架构)和具体的应用需求。

(1)可虚拟化的ISA

如果所有的敏感指令都是特权指令,根据波普克和戈德堡的理论,该CPU ISA可通过陷入-仿真[1]一模型进行完全虚拟化,如图1-2所示。支持陷入-仿真模型的ISA有ARMv8、RISC-V、MIPS、PowerPC、SPARC指令集。

图1-2 基于陷入-仿真模型的完全虚拟化技术

在虚拟化实现中,Hypervisor运行在特权模式,具有对硬件资源的完全控制权,因而可以在所有虚拟机间共享硬件平台。所有虚拟机运行在用户模式下,而虚拟机中的vCPU期望能够访问所有硬件资源,因此Hypervisor必须提供一种间接的机制来实现vCPU期望的所有功能。在用户模式下执行特权指令会产生一条陷阱异常信息,Hypervisor会利用这个特征来捕获虚拟机试图执行的特权指令,并精确地模拟该特权指令的原有功能。

如图1-2所示,如果异常触发的原因是vCPU在虚拟特权模式下执行特权指令,则该条特权指令会被Hypervisor模拟;如果异常是由于vCPU处于虚拟用户模式下非法执行特权指令而触发(比如除零异常),则该异常会被Hypervisor转发给当前虚拟机,并在vCPU中触发一个可编程异常。也就是说,如果pCPU处于虚拟用户模式,但是vCPU处于虚拟特权模式,那么需要给vCPU创造一种幻象,即vCPU运行在自己期望的特权模式中,并且每一条特权指令在Hypervisor中都会有一个对应的模拟程序。当Hypervisor需要模拟某条特权指令时,对应的程序将会被调用。总之,无论是Hypervisor模拟特权指令还是将异常转发给虚拟机,Hypervisor最终都会恢复vCPU的上下文,以使当前虚拟机继续执行。

(2)不可虚拟化的ISA

如果某敏感指令不是特权指令,那么该敏感指令在虚拟用户模式下执行时不会触发陷阱,因而无法被运行在虚拟特权模式下的系统软件所捕获,所以不能通过陷入-仿真模型进行完全虚拟化。例如,在没有引入硬件虚拟化扩展的X86 32位指令集中,某些敏感指令在虚拟用户模式下执行时会被忽略,而不会触发陷阱异常。以X86的POPF指令为例,该指令用于替换标志寄存器的值,会改变允许/禁止中断的标志位。但是在虚拟用户模式下执行这条指令时,这个标志位不会被改变,也不会触发陷阱。因此,X86 32位ISA是不能通过陷入-仿真模型进行虚拟化的ISA。但是我们可以通过特殊的工程技术来实现pCPU虚拟化(详情见1.1.4小节)。

讨论了CPU虚拟化后,下面来研究一下I/O虚拟化。