searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

虚拟化技术之CPU虚拟化

2024-06-28 10:03:06
2
0

1.  什么是虚拟化

 IBM对虚拟化给出的定义是:虚拟化能够将单台计算机中的CPU、内存、存储器等硬件资源划分为名为虚拟机 (VM) 的多个虚拟计算机。本文我们要讨论的是CPU虚拟化,根据我的理解,CPU虚拟化就是将一个物理CPU虚拟化成多个虚拟CPU (vCPU)。实现将一个物理CPU虚拟化成多个虚拟CPU (vCPU)的方法论其实就是”CPU的时分复用”。CPU时间调度的最小单位是线程。我们将从线程模型的CPU虚拟机,讲到操作系统级别的CPU虚拟化。

2.  线程模型的 CPU 虚拟化

从线程视角来看,一个物理CPU包含的范畴主要是各种CPU寄存器。所谓线程,就是正在被执行的一段代码。如果将代码反汇编,其本质就是在不断操作各种寄存器。对于一个线程来说,其所能感知到的CPU实体主要是CPU的各种寄存器,这也就是本科操作系统教科书中所说的“CPU现场

  最典型的两个寄存器是:

1. SPStack Pointer):指示当前程序的栈顶位置。

2. IPInstruction Pointer):指示当前程序正在执行的指令位置。

为了给每个线程呈现出一个独立的物理CPU,通常的方法是为每个线程定义一个所谓的“CPU上下文,这一般通过软件实现。虽然x86架构中的TSSTask State Segment)设计尝试从硬件上提供任务上下文保存及切换机制,但正统的Linux内核并未采用这一机制。

 CPU上下文”被称为TCBThread Control Block)。一个TCB中包含的CPU上下文信息,就是实现线程级别CPU虚拟化的完整闭包。如下图所示,通过CPU上下文切换实现分时复用的基本手法:

 

 

1 [1]

1. 当内核加载某个线程到物理CPU上运行时

内核通过读取该线程的TCB,将物理CPU的上下文恢复成该线程TCB所描述的CPU现场。

2. 当某个线程不再被内核执行时

内核将当前物理CPU的现场保存到该线程的TCB中。

这种机制确保了每个线程在被调度到物理CPU上运行时,都能有一个独立且完整的运行环境,即独立的虚拟CPU”线程独占CPU的时间片,让它以为它是独占地连续地在CPU上运行。

线程模型的 CPU 虚拟化是建立在同一个操作系统的基础上。线程都有一个共同的内核。但是我们所说的CPU虚拟化,是操作系统级别的虚拟化。操作系统级别的虚拟化,线程会有不同的内核。

3.  操作系统级别的CPU虚拟化

下面我们举个例子来说明为什么线程模型的 CPU 虚拟化不能实现操作系统级别的虚拟化。中断向量表是由操作系统的内核来维护。X86 体系结构下通过 LIDTLoad Interrupt Descriptor Table)指令设置中断向量表基地址,操作系统内核启动时对中断向量表进行初始化,并将中断向量表的基地址通过 LIDT 指令设置到物理 CPU IDTRInterrupt Descriptor Register)中。

中断向量表的基地址是不能乱设置的。如果使用线程模型的 CPU 虚拟化来实现操作系统级别的虚拟化,那么宿主机操作系统中将运行着 N 个操作系统。每个操作系统有不同的内核,这些操作系统在内核启动时,都会设置一次宿主机操作内核中断向量表基地址,最终导致的结果是宿主机器内核的中断向量表会被搞乱,最直接的后果就是宿主机自己先挂了。像 LIDT 这种会对整个系统级别资源(硬件)产生影响的操作指令,被称为 “敏感指令”。

下面我们举个例子来说明为什么线程模型的 CPU 虚拟化不能实现操作系统级别的虚拟化。现代操作系统有内核态(Kernel Mode)和用户态(User Mode)两种不同的运行模式。用户态不能执行内核态的指令。线程运行在用户态。如果用线程模型来实现操作系统级别的虚拟化,运行在线程里的操作系统将无法执行内核态的指令。这些内核态的指令就是通常我们所说的“敏感指令”。解决“敏感指令”的运行是虚拟化技术的关键。解决“敏感指令”的运行有两种常见的手段:

常见的技术方案有:基于二进制翻译的全虚拟化技术(Full-Virtualization)、需要改造 GuestOS 的半虚拟化技术(Para-Virtualization)和 Intel VT-x 硬件辅助的虚拟化技术(Hardware-assisted virtualization)。

接下来我们来介绍一下Intel VT-x 硬件辅助的虚拟化技术(Hardware-assisted virtualization)。

 

2 [2]

如图2所示,Intel VT-x硬件辅助的虚拟化技术原理如下:

     CPU Root Mode Non-root Mode 2 种运行模式。其中,HostOSVMM)运行在 Root Mode 拥有最高执行权限,而 GustOSVM)和 User Application 则运行在 Non-root Mode,并且这 2 种模式都支持 Ring 03。因此 VMM Guest OS 都可以自由选择它们所期望的 CPU 运行级别。GustOSVM)和 User Application 可以对硬件直接执行部分“敏感指令”。

 GustOSVM)和 User Application 不能对硬件直接执行的“敏感指令”,比如HLT指令。运行在 Root Mode 上的 CPU 会自动捕获 GuestOS 发出的“敏感指令”(触发异常),然后交由 VMM 来完成翻译,处理后再使用 VMLAUNCH VMRESUME 指令返回到 GuestOS

下面解释一下为什么 GustOSVM)和 User Application 不能对硬件直接执行HLT指令。HLT指令是停止处理器的指令。GustOSVM) 发出HLT指令是想停止GustOSVM)的CPU,而不是想停止实际物理CPU,所以GustOSVM) 不能直接对硬件执行HLT指令。HLT指令会被HostOSVMM)截获,完成翻译,处理后再使用 VMLAUNCH VMRESUME 指令返回到 GustOSVM

VT-x提供的GuestOS CPU 的上下文称为 VMCSvirtual machine control structure)。VT-x提供了 RootNon-root 两种处理器模式,HostOSVMM)运行在 Root 模式下,GuestOSVM)运行在 Non-root 模式下。当 GuestOSVM)执行HLT指令时,HostOSVMM)将自动捕获这条“敏感指令”,进而引发 CPU Non-root 模式退出到Root 模式,也就是从 GuestOSVM)中退出(VMEXIT)到 HostOSVMM)中,并且GuestOSVM)的 VMCS 中会带有本次从 Non-root 下退出来的原因(reason),VMM 会根据这个 reason 执行相应的模拟逻辑。VMM 会将模拟逻辑的结果写入 GuestOSVM) 所对应的 VMCS 中。等到下次该 GuestOS 再次被调度执行时,VMRESUME 指令会直接将带有模拟逻辑结果的VMCS 所刻画的 CPU 现场恢复到Non-root 模式下的 CPU 上下文中。

简单来说就是,GuestOSVM)的“敏感指令”会被HostOSVMM)截获,并在HostOSVMM)中模拟“敏感指令”的运行,将“敏感指令”模拟运行的结果写入GuestOS VM) 所对应的 VMCS GuestOS VM) 根据VMCS来将GuestOS VM)的CPU上下文更新到“敏感指令”执行后的结果。

所以CPU虚拟化最主要的性能开销就是CPURootNon-root模式之间的切换。

参考文章:

[1]虚拟化技术 — 硬件辅助的虚拟化技术

[2]虚拟化科普之 CPU

 

0条评论
0 / 1000
c****q
1文章数
0粉丝数
c****q
1 文章 | 0 粉丝