QEMU之CPU虚拟化(一):CPU虚拟化介绍
最近在阅读李强编著的《QEMU/KVM源码解析与应用》这本书来学习Linux内核虚拟化相关知识,通过读书笔记的方式来提炼和归纳书中重要的知识点。本系列主要内容是关于QEMU中CPU虚拟化方面的介绍。
关注微信公众号:Linux内核拾遗
1 CPU虚拟化介绍
1.1 CPU虚拟化简介
介绍CPU虚拟化之前,首先对下面的概念进行解释和区分:
特权指令和非特权指令
- 特权指令(Privileged Instructions):特权指令是只有特定特权级别的程序(例如操作系统内核)才能执行的指令。这些指令通常用于执行对底层系统资源和状态的操作,如访问硬件设备、修改内存管理和权限控制等。在x86体系结构中,特权指令运行在ring0。
- 非特权指令(Non-privileged Instructions):非特权指令是可以由任何权限级别的程序执行的指令。这些指令通常用于一般的应用程序和用户级别代码。非特权指令提供了一组基本的操作和计算功能,但没有直接访问和控制系统底层资源的能力。在x86体系结构中,非特权指令运行在ring3。
敏感指令和非敏感指令
- 敏感指令(Sensitive Instructions):敏感指令是那些具有一定风险或可能对系统造成影响的指令。这些指令可能会改变或获取系统的全局资源,例如修改系统状态、访问敏感数据或进行特殊处理。敏感指令可能涉及对系统的访问、操作或控制,因此在执行这些指令时需要谨慎,并遵循相应的安全策略和权限管理。
- 非敏感指令(Non-sensitive Instructions):非敏感指令是指那些不被认为具有风险或不会对系统产生重大影响的指令。这些指令通常是常规的操作和计算指令,不涉及对系统底层资源的直接访问或控制。非敏感指令在大多数情况下是安全的,可以由普通用户程序执行。
x86系统的敏感指令与特权指令并不是完全相同的,存在一些属于敏感指令但不是特权指令的指令,也就是说用户程序能够运行一些可以改变/获取全局资源的指令。
在虚拟化情况下,这种特殊情况会出现问题:虚拟化平台上面会运行多个虚拟机,如果里面的操作系统都能够随意读取/修改全局数据,这会影响其他虚拟机操作系统的正常运行。
为了解决这个问题,历史上出现了几种方案:
- Bochs和(不含KVM的)QEMU之类的模拟器:逐条解析和执行指令。
- VMWare早期方案:虚拟化用户态的程序直接在CPU上执行,但是一些特权指令会通过动态的二进制翻译去执行。
- VMWare Xen方案:修改虚拟机操作系统内核的代码,使虚拟机内核运行在ring1,并且对虚拟机中操作系统内核的敏感指令进行替换进而使其陷入到ring0的Xen内核。
上述各方案都有缺点,随着云计算及其底层支撑的虚拟化技术的快速发展,Intel和AMD都相继在硬件层面支持了虚拟化。下面将着重介绍基于硬件CPU虚拟化的VT-x技术。
1.2 VMX架构简介
Intel通过在原来x86 CPU的基础上增加VMX架构来实现CPU的硬件虚拟化。
VMX架构下定义了两类软件的角色:
- 虚拟机监控器(VMM,VM Monitor) :VMM对整个系统的CPU和硬件有完全的控制权,它抽象出虚拟的CPU给各个VM,并且能够将VM的CPU直接调度到物理CPU上运行。
- 虚拟机(VM) :每个VM都是一个虚拟机实例,能够支持操作系统以及各种软件栈和应用程序,VM本身不会意识到其处在虚拟化环境中。每一个VM都相互独立,有自己独立的CPU、内核、中断和设备等,这些资源都是VMM提供的。
为了使得VMM能够管理各个VM之间的隔离和独立运行,VMM的运行权限要高于VM。
传统上,操作系统内核已经运行在ring0最高级了,所以为了让CPU支持VMM和VM两种软件,Intel为CPU引入了一种新的模式,叫作VMX operation。
VMM执行的模式叫作VMX root operation模式,VM执行的模式叫作VMX non-root operation模式,这两种模式之间的转换叫作VMX转换。从VMX root转换到VMX non-root叫作VM Entry,而从VMX non-root转换到VMX root则叫作VM Exit。
VMM的生命周期以及和VM的交互如上图所示,其中包含如下的转换流程:
- 首先执行VMXON的指令让CPU进入VMX operation。在执行VMXON之前,需要先分配并初始化一个VMXON的区域,以记录VMM本身的相关数据。
- VMM通过VM Entry来使一个VM进入到运行状态。首次进入VM是通过执行VMLAUNCH指令发起的。每一个VM都会有一个对应的虚拟机控制结构(Virtual Machine Control Structure,VMCS)区域与之对应,用来保存该VM的相关信息。所以在进行VMLAUNCH之前需要提前分配并初始化VMCS。
- VM不会主动进行VM Exit。只有当VM的CPU发生预定指令或者是在VMCS中配置一些事件时才会进行VM Exit。VM会退出到VMM指定的一个地址,此时VMM开始执行,可以对VM的退出进行处理。
- VMM可以通过执行VMXOFF指令退出VMX operation。
1.3 VMCS介绍
每个虚拟机的VCPU都有一个对应的VMCS区域。VMCS用来管理VMX non-root Operation的转换以及控制VCPU的行为。
VMCS之于VCPU的作用类似于进程描述符之于进程的作用:
- *(用于进程调度)*传统上操作系统的进程会共享物理CPU资源,操作系统负责在多个进程之间分配CPU,每个进程都有进程描述符来保存进程的信息,并且在进程切换时保存硬件上下文,使得进程能够在下次被调度的时候正常运行。
- *(用于VCPU调度)*VCPU之间会共享物理CPU,VMM负责在多个VCPU之间分配物理CPU,每个VCPU都有自己的描述符,当VMM在切换VCPU运行时需要保存此刻的VCPU状态,从而在下次的VCPU调度中使得VCPU能够从被中断的那个点开始正常运行。
VMCS内部各区域划分及字段含义如下:
参考文献
- QEMU/KVM源码解析与应用 - 李强
关注微信公众号:Linux内核拾遗