AArch64虚拟化

概述

本指南介绍Armv8-A AArch64中的虚拟化支持。所涵盖的主题包括stage 2 translation, virtual exceptions和trapping。

本指南介绍了一些基本的虚拟化理论,并举例说明了hypervisor如何使用其所描述的功能。它没有涵盖特定hypervisor的操作,也没有试图解释如何从头开始编写自己的hypervisor。

阅读本文,您将了解这两种类型的hypervisor,以及它们如何映射到Arm Exception级别。您将能够解释陷阱的操作以及如何使用它们来模拟操作。您将能够列出hypervisor可以生成哪些虚拟异常,并描述执行此操作的机制。

在阅读文本之前应该对虚拟化有基本的了解,包括什么是虚拟机以及虚拟机管理程序的角色。熟悉内存管理中的异常模型和地址转换。

虚拟化简介

在这里,我们将介绍一些介绍性的hypervisor和虚拟化理论。
我们在本指南中使用术语hypervisor是指负责创建、管理和调度虚拟机(VM)的软件。

为什么虚拟化很重要
虚拟化是一种广泛使用的技术,几乎支撑着所有现代云计算和企业基础设施。开发人员使用虚拟化在一台机器上运行多个操作系统,并在没有损坏主计算环境风险的情况下测试软件。
虚拟化在服务器系统中很流行,对虚拟化的支持是大多数服务器级处理器的要求。这是因为虚拟化为数据中心提供了非常理想的功能,包括:
Isolation:虚拟化的核心是在单个物理系统上运行的虚拟机之间提供隔离。这种隔离允许在相互不信任的计算环境之间共享物理系统。例如,两个竞争对手可以在数据中心共享同一台物理机器,而不能访问彼此的数据。
High Availability:虚拟化允许在物理机器之间无缝透明地迁移工作负载。这项技术通常用于将工作负载从可能需要维护和更换的故障硬件平台上迁移出去。
Workload balancing:为了优化数据中心的硬件和电源预算,尽可能多地使用每个硬件平台是很重要的。同样,这可以通过迁移虚拟机或在物理机上共同托管适当的工作负载来实现。这意味着物理机器将尽可能多地使用其容量。这为数据中心提供商提供了最佳的电源预算,并为租户提供了最佳性能。
Sandboxing:虚拟机可用于为可能干扰其运行的机器其余部分的应用程序提供沙盒。此类应用程序的示例包括遗留应用程序或正在开发的软件。在虚拟机中运行这些应用程序可以防止应用程序的错误或恶意部分干扰物理机器上的其他应用程序或数据。

独立(Standalone)和托管(hosted)hypervisors
管理程序可以分为两大类:独立的(standalone)或类型1(Type 1)的hypervisor和托管(hosted)或类型2(Type 2)的hypervisor。
在Type 2的hypervisor配置中,主机操作系统完全控制硬件平台及其所有资源,包括CPU和物理内存。下图说明了Type 2的hypervisor:
在这里插入图片描述
如果您以前使用过Virtual Box或VMware Workstation等软件,则这是您正在运行的hypervisor类型。Host OS(称为主机操作系统)安装在平台上,hypervisor在主机操作系统中运行,利用现有功能管理硬件。然后,hypervisor可以托管虚拟机,这些虚拟机本身运行一个操作系统。我们称之为Guest OS。
接下来,我们将首先看一个Type 1 hypervisor:
在这里插入图片描述此hypervisor设计中没有Host OS。hypervisor直接在硬件上运行,并完全控制硬件平台及其所有资源,包括CPU和物理内存。就像Type 2 的hypervisor一样,Type 1 hypervisor也可以托管虚拟机。这些虚拟机可以运行一个或多个完整的Guest OS。
Arm平台上最常用的两个开源管理程序是Xen(standalone,
Type 1)和KVM(hosted, Type 2)。

完全虚拟化和准虚拟化(Full virtualization and para-virtualization)
VM的经典定义是一个独立的、孤立的计算环境,与真实的物理机器无法区分。尽管可以在基于Arm的系统上完全模拟真实的机器,但这通常不是一件有效的事情。因此,这种模拟并不常见。例如,模拟真实以太网设备的速度很慢,因为Guest OS执行的对模拟寄存器的每次访问都必须由hypervisor在软件中处理。这种处理可能比访问物理设备上的寄存器要更耗时。
通常用于提高性能的首选方案是通知Guest OS。通过使访Guest OS意识到它正在虚拟机中运行,并通过提供虚拟设备,这些虚拟设备被设计为在hypervisor中模拟并从Guest OS访问时具有良好的性能,Guest OS可以实现良好的性能(即使是I/O)。
严格地说,全系统虚拟化模拟真实的物理机器。另一方面,Xen(开源项目)推广了“准虚拟化”一词,即Guest OS的核心部分被修改为在虚拟硬件平台上操作,而不是在物理机器上操作。进行此修改是为了提高性能。
如今,在包括Arm在内的大多数支持虚拟化硬件的体系结构上,Guest OS多未经修改即可运行。Guest OS认为它是在真实的硬件上运行的,但块存储和网络等I/O外围设备的驱动程序除外,这些驱动程序使用半虚拟化设备和设备驱动程序。这种半虚拟化I/O设备的例子是Virtio和Xen PV Bus。

虚拟机和虚拟CPU(Virtual machines and virtual CPUs)
理解虚拟机(VM)和虚拟CPU(vCPU)之间的区别很重要。虚拟机将包含一个或多个vCPU,如下图所示:
在这里插入图片描述
当我们了解本指南中的其他一些主题时,VM和vCPU之间的区别将变得非常重要。例如,一页内存可能被分配给一个虚拟机,因此该虚拟机中的所有vCPU都可以访问。但是,虚拟中断的目标是特定的vCPU,并且只能转到该vCPU。
严格来说,我们应该指的是虚拟处理元素(vPE),而不是vCPU。请记住,处理元件(PE)是实现Arm体系结构的机器的通用术语。本指南使用vCPU而不是vPE,因为vCPU是大多数人熟悉的术语。但是,在体系结构规范中,使用了术语vPE。

AArch64中的虚拟化

以EL2或更高版本运行的软件可以访问几个虚拟化控件:

  • Stage 2 translation
  • EL1/0 instruction and register access trapping
  • Virtual exception generation
    非安全(Non-Secure)和安全(Secure)状态下的异常级别(EL)如下所示:
    在这里插入图片描述在图中,Secure EL2显示为灰色。这是因为对处于安全状态的EL2的支持并不总是可用的。这将在“安全虚拟化”一节中进行讨论。
    体系结构中还有一些功能支持:
  • Secure virtualization
  • Hosted, or Type 2, hypervisors
  • Nested virtualization

Stage 2 translation

本章介绍Stage 2 translation和控制内存访问的方法。

什么是stage 2 translation
Stage 2 translation允许hypervisor控制虚拟机(VM)中的内存视图。具体来说,它允许hypervisor控制虚拟机可以访问哪些内存映射的系统资源,以及这些资源出现在虚拟机的地址空间中的位置。
这种控制内存访问的能力对于隔离和沙盒来说非常重要。Stage 2 translation可用于确保VM只能看到分配给它的资源,而不能看到分配给其他VM或hypervisor的资源。
对于存储器地址翻译,Stage 2 translation是翻译的第二阶段。为了支持这一点,需要一组新的转换表,称为阶段2表,如下所示:
在这里插入图片描述操作系统(OS)控制一组转换表,这些转换表从虚拟地址空间映射到它认为的物理地址空间。然而,该过程经历到真实物理地址空间的第二次转换。第二阶段由hypervisor控制。
操作系统控制的翻译称为stage 1 translation,而hypervisor控制的翻译则称为stage 2 translation。OS认为是物理存储器的地址空间被称为中间物理地址(IPA)空间。
stage 2段使用的翻译表的格式与stage 1使用的格式非常相似。然而,有些属性在stage 2以不同的方式处理,并且类型(Normal或Device)直接编码到表条目中,而不是通过MAIR_ELx寄存器。

VMIDs
为每个VM分配一个虚拟机标识符(VMID)。VMID用于标记翻译后备缓冲区(TLB)条目,以识别每个条目属于哪个VM。此标记允许多个不同VM的翻译同时出现在TLB中。
VMID存储在VTTBR_EL2中,可以是8位或16位。VMID由VTCR_EL2.VS位控制。对16位VMID的支持是可选的,并在Armv8.1-A中添加。
EL2和EL3 translation没有标记VMID,因为它们不受stage 2 translation的约束。

VMID与ASIDs的交互
TLB条目也可以用地址空间标识符(ASID)进行标记。操作系统为应用程序分配一个ASID,并且该应用程序中的所有TLB条目都标记有该ASID。这意味着不同应用程序的TLB条目能够共存于TLB中,而不存在一个应用程序使用属于不同应用程序中的TLB条目的可能性。
每个虚拟机都有自己的ASID命名空间。例如,两个虚拟机可能都使用ASID 5,但它们用于不同的用途。ASID和VMID的结合才是最重要的。

属性组合和覆盖
stage 1和stage 2的映射都包括属性,例如类型和访问权限。内存管理单元(MMU)将来自两个阶段的属性组合起来,以给出最终的有效值。MMU通过选择限制性更强的阶段来实现这一点:
在这里插入图片描述在本例中,设Device型比Normal类型的限制更大。因此,生成的类型为Device。如果我们颠倒示例,结果将是相同的,因此stage 1=Normal,阶stage 2=Device。
这种组合属性的方法适用于大多数用例,但有时hypervisor可能想要覆盖这种行为。例如,在VM的早期启动过程中。对于这些情况,有一些控制位会覆盖正常行为:

  • HCR_EL2.CD。这使得所有stage 1属性都Non-cacheable
  • HCR_EL2.DC。这将强制stage 1 的属性为Normal,Write-Back Cacheable。
  • HCR_EL2.FWB。这允许stage 2覆盖stage 1 属性,而不是常规的属性组合。

模拟内存映射输入/输出MMIO(Emulating Memory-mapped Input/Output)
与物理机器上的物理地址空间一样,虚拟机中的IPA空间包含用于访问内存和外围设备的区域,如下所示:
在这里插入图片描述
虚拟机可以使用外围区域来访问实际物理外围设备(通常称为直接分配的外围设备)和虚拟外围设备。
虚拟外围设备完全由hypervisor在软件中模拟,如下图所示:
在这里插入图片描述分配的外围设备是已分配给VM并映射到其IPA空间的真实物理设备。这允许在VM内运行的软件直接与外围设备交互。
虚拟外围设备是hypervisor序要在软件中模拟的外围设备。相应的stage 2 table entries被标记为故障。虚拟机中的软件认为它可以直接与外围设备对话,但每次访问都会触发stage 2 fault,hypervisor会在异常处理程序中模拟外围设备访问。
要模拟外围设备,hypervisor不仅需要知道哪个外围设备被访问,还需要知道该外围设备中的哪个寄存器被访问,访问是读还是写,访问的大小以及用于传输数据的寄存器。
Exception Mode(arm文档)指南介绍了FAR_ELx寄存器。在处理stage 1 faults时,这些寄存器会报告触发异常的虚拟地址。虚拟地址对hypervisor没有帮助,因为hypervisor通常不知道Guest O是如何配置其虚拟地址空间的。对于stage 2 faults,有一个额外的寄存器HPFAR_EL2,它报告中止的地址的IPA。由于IPA空间由hypervisor控制,因此它可以使用这些信息来确定需要模拟的寄存器。
对于触发stage 2 fault的单个通用寄存器加载或存储,提供了额外的综合征信息。该信息包括访问的大小以及源或目的地寄存器,并允许hypervisor确定对虚拟外围设备的访问类型。
此图说明trapping然后模拟访问的过程:
在这里插入图片描述
此过程在以下步骤中进行了描述:

  1. 虚拟机中的软件尝试访问虚拟外围设备。在本例中,这是一个虚拟UART的接收FIFO。
  2. 此访问在stage 2 translation时被阻止,导致路由到EL2的abort。
  • abort使用有关异常的信息填充ESR_EL2,包括访问的字节数、目标寄存器以及它是加载还是存储。
  • abort还用abort访问的IPA填充HPFAR_EL2。
  1. hypervisor使用ESR_EL2和HPFAR_EL2中的信息来识别访问的虚拟外围寄存器。此信息允许hypervisor模拟操作。然后,它通过ERET返回到vCPU。
  • 在LDR之后重新开始执行指令。

系统内存管理单元(SMMU)
到目前为止,我们已经考虑了来自处理器的不同类型的访问。系统中的其他主控器,例如DMA控制器,可以被分配给VM使用。我们也需要一些方法来将stage 2的保护扩展到这些主控器。
考虑一个具有不使用虚拟化的DMA控制器的系统,如下图所示:
在这里插入图片描述DMA控制器将通过驱动程序进行编程,通常在内核空间中。该内核空间驱动程序可以确保操作系统级别的内存保护不会被破坏。这意味着一个应用程序不能使用DMA来访问它不应该看到的内存。
让我们考虑相同的系统,但操作系统在VM中运行,如下图所示:
在这里插入图片描述
在此系统中,hypervisor使用stage 2来提供虚拟机之间的隔离。软件查看内存的能力受到hypervisor控制的stage 2页表的限制。
允许VM中的驱动程序直接与DMA控制器交互会产生两个问题:
Isolation:DMA控制器不受stage 2页表的约束,可能会被用来破坏VM的沙箱。
Address space: 有两个stages translation,内核认为是PA的是IPA。DMA控制器仍然可以看到PA,因此内核和DMA控制器具有不同的内存视图。为了克服这个问题,hypervisor可以捕获VM和DMA控制器之间的每次交互,从而提供必要的转换。当内存碎片化时,这一过程效率低下且存在问题。
捕获和模拟驱动程序访问的另一种选择是扩展stage 2机制,以覆盖其他主控制器,如我们的DMA控制器。当这种情况发生时,这些主控制器也需要一个MMU。这被称为系统内存管理单元(SMMU,有时也称为IOMMU):
在这里插入图片描述hypervisor将负责对SMMU进行编程,以便上游主控制器(在我们的示例中是DMA)看到与其分配到的VM相同的内存视图。
这个过程解决了我们发现的两个问题。SMMU可以强制虚拟机之间的隔离,确保外部主机不能被用来破坏沙箱。SMMU还向VM中的软件和分配给VM的外部主机提供存储器的一致视图。

指令的陷阱和模拟(Trapping and emulation of instructions)

有时,hypervisor需要模拟虚拟机(VM)中的操作。例如,VM内的软件可能试图配置与电源管理或高速缓存一致性相关的低级别处理器控制。通常,您不希望让虚拟机直接访问这些控件,因为它们可能被用来打破隔离,或影响系统中的其他虚拟机。
当执行给定的操作(如读取寄存器)时,陷阱会导致异常。hypervisor需要能够在不影响其他虚拟机的情况下,在虚拟机中捕获操作(如配置低级别控制的操作)并对其进行仿真。
该体系结构包括陷阱控件,用于陷阱VM中的操作并对其进行模拟。当设置陷阱时,执行通常允许的特定操作会导致异常级别更高。hypervisor可以使用这些陷阱来模拟虚拟机中的操作。
例如,执行等待中断(WFI)指令通常会使CPU进入低功耗状态。通过断言TWI位,如果HCR_EL2.TWI==1,则在EL0或EL1执行WFI将导致EL2异常。
在我们的WFI示例中,操作系统通常会将WFI作为空闲循环的一部分来执行。对于虚拟机中的来Guest OS,hypervisor可以捕获此操作并安排不同的vCPU,如下图所示:
在这里插入图片描述
呈现寄存器的虚拟值
使用陷阱的另一个示例是呈现寄存器的虚拟值。例如,ID_AA64MMFR0_EL1报告对处理器中与内存系统相关的功能的支持。作为引导的一部分,操作系统可能会读取此寄存器,以确定要启用内核中的哪些功能。hypervisor可能希望向Guest OS提供一个不同的值,称为虚拟值。
为此,hypervisor将启用覆盖寄存器读取的陷阱。对于陷阱异常,hypervisor会确定触发了哪个陷阱,然后模拟操作。在本例中,hypervisor使用ID_AA64MMFR0_EL1的虚拟值填充目标寄存器,如下所示:
在这里插入图片描述陷阱也可以用作惰性上下文切换的一部分。例如,操作系统通常会在引导期间初始化内存管理单元(MMU)配置寄存器(TTBR_EL1、TCR_EL1和MAIR_EL1),然后不会再次对其进行重新编程。hypervisor可以使用它来优化其上下文切换例程,只需恢复上下文开关上的寄存器而不保存它们。
然而,操作系统可能会做一些不寻常的事情,并在引导后重新编程寄存器。为了避免这导致任何问题,hypervisor可以设置HCR_EL2.TVM陷阱。此设置会导致对MMU相关寄存器的任何写入都会在EL2中生成陷阱,从而使hypervisor能够检测是否需要更新这些寄存器的保存副本。

MIDR和MPIDR
使用陷阱来虚拟化操作需要大量的计算。该操作为EL2生成一个陷阱异常,hypervisor确定所需的操作,对其进行仿真,然后返回给Guest OS。操作系统不经常访问功能寄存器,如ID_AA64MMFR0_EL1。这意味着,当将对这些寄存器的访问捕获到hypervisor中以模拟读取时,计算是可以接受的。
对于更频繁访问的寄存器,或者在性能关键代码中,您希望避免这种计算负载。这些寄存器及其值的示例包括:

  • MIDR_EL1。处理器的类型,例如Cortex-A53
  • MPIDR_EL1。亲和力,例如处理器2的core 1

hypervisor可能希望来Guest OS统查看这些寄存器的虚拟值,而不必捕获每个单独的访问。对于这些寄存器,该体系结构提供了捕获的替代方案:

  • VPIDR_EL2。这是MIDR_EL1的EL1读取返回的值。
  • VMPIDR_EL2。这是MPIDR_EL1的EL1读取返回的值。

hypervisor可以在进入虚拟机之前设置这些寄存器。如果在虚拟机中运行的软件读取MIDR_EL1或MPIDR_EL1,硬件将自动返回虚拟值,而不需要陷阱。

异常的虚拟化(Virtualizing exceptions)

中断由系统中的硬件用来向软件发送事件信号。例如,GPU可能会发送一个中断,以发出它已经完成渲染帧的信号。
使用虚拟化的系统更为复杂。某些中断可能由hypervisor本身处理。其他中断可能来自分配给虚拟机(VM)的设备,并且需要由该VM内的软件处理。此外,被中断作为目标的VM在接收到中断时可能没有运行。
这意味着您需要一些机制来支持hypervisor对EL2中某些中断的处理。还需要将其他中断转发到特定VM或VM中的特定虚拟CPU(vCPU)的机制。
为了启用这些机制,该体系结构包括对虚拟中断的支持:vIRQ、vFIQ和vSErrors。这些虚拟中断的行为与物理中断(IRQ、FIQ和SErrors)类似,但只能在EL0和EL1中执行时发出信号。在EL2或EL3中执行时不可能接收虚拟中断。

启用虚拟中断
要向EL0/1发送虚拟中断信号,hypervisor必须在HCR_EL2中设置相应的路由位。例如,要启用vIRQ信令,hypervisor必须设置HCR_EL2.IMO。此设置将物理IRQ异常路由到EL2,并启用虚拟异常到EL1的信令。
虚拟中断按中断类型进行控制。理论上,VM可以被配置为接收物理FIQ和虚拟IRQ。在实践中,这是不寻常的。VM通常只配置为接收虚拟中断。

生成虚拟中断
有两种机制用于生成虚拟中断:

  • 通过core内部,使用HCR_EL2中的控件。
  • 使用GICv2或更高版本的中断控制器。
    HCR_EL2中有三个位控制虚拟中断的生成:
  • VI=设置此位将注册一个vIRQ。
  • VF=设置此位注册一个vFIQ。
  • VSE=设置此位会注册一个vSError。
    设置这些位中的一个相当于中断控制器向vCPU断言中断信号。生成的虚拟中断要接受PSTATE屏蔽,就像常规中断一样。

这种机制使用起来很简单,但缺点是它只提供了一种生成中断本身的方法。然后需要hypervisor来模拟虚拟机中中断控制器的操作。概括地说,最好避免软件中的捕获和模拟操作涉及的开销对于频繁的操作(如中断)。

第二个选项是使用Arm的通用中断控制器(GIC)来生成虚拟中断。通过Arm GICv2,GIC可以通过提供物理CPU interface和虚拟CPU interface来发出物理和虚拟中断信号,如下图所示:
在这里插入图片描述这两个接口是相同的,只是其中一个发出物理中断信号,另一个发出虚拟中断信号。hypervisor可以将虚拟CPU interfaces映射到虚拟机中,从而允许该虚拟机中的软件直接与GIC通信。这种方法的优点是,hypervisor只需要设置虚拟接口,而不需要对其进行仿真。这种方法减少了需要将执行捕获到EL2的次数,从而减少了虚拟化中断的开销。

尽管Arm GICv2可以与Armv8-A设计一起使用,但更常见的是使用GICv3或GICv4。

中断转发到vCPU的示例
到目前为止,我们已经研究了如何启用和生成虚拟中断。让我们看一个示例,它显示了将虚拟中断转发到vCPU。在本例中,我们将考虑已分配给VM的物理外围设备,如下图所示:
在这里插入图片描述该图包含这些步骤:

  • 物理外围设备将其中断信号断言到GIC中。
  • GIC生成一个物理中断异常,IRQ或FIQ,通过HCR_EL2.IMO/FMO的配置将其路由到EL2。
  • hypervisor识别外围设备并确定其已分配给VM。它检查中断应该被转发到哪个vCPU。 hypervisor配置GIC将物理中断作为虚拟中断转发给vCPU。然后,GIC将断言vIRQ或vFIQ信号,但处理器在EL2中执行时将忽略该信号。
  • hypervisor将控制权返回给vCPU。
  • 现在处理器在vCPU(EL0或EL1)中,可以从GIC获取虚拟中断。此虚拟中断受PSTATE异常掩码的约束。

该示例显示了作为虚拟中断转发的物理中断。该示例与第2阶段翻译部分中描述的指定外围模型相匹配。对于虚拟外设,hypervisor可以创建虚拟中断,而无需将其链接到物理中断。

中断屏蔽和虚拟中断
在AArch64异常模型指南中,我们在PSTATE、PSTATE.I(用于IRQ)、PSTATE.F(用于FIQ)和PSTATE.A(用于SErrors)中引入了中断掩码位。当在虚拟化环境中操作时,这些掩码的工作方式略有不同。
例如,对于IRQ,我们已经看到设置HCR_EL2.IMO有两件事:

  • 将物理IRQ路由到EL2
  • 启用EL0和EL1中vIRQ的信令
    此设置也会更改PSTATE.I掩码的应用方式。而在EL0和EL1中,如果HCR_E2.IMO==1,PSTATE.I对vIRQ而不是pIRQ进行操作。

通用计时器的虚拟化

Arm体系结构包括通用定时器,这是每个处理器中可用的一组标准定时器。通用定时器由一组比较器组成,这些比较器与通用系统计数进行比较。比较器在其值等于或小于系统计数时产生中断。在下图中,我们可以看到系统中的通用定时器(橙色),以及比较器和计数器模块的组件。
在这里插入图片描述下图显示了一个示例系统,该系统具有一个托管两个虚拟CPU(vCPU)的hypervisor:
在这里插入图片描述在本例中,我们忽略了运行虚拟机监控程序在vCPU之间进行上下文切换的开销。
经过4ms的物理时间或墙上的时钟时间后,每个vCPU已经运行2ms。如果vCPU0将其比较器设置为T=0,以便在3ms后生成中断,您会认为中断已经触发吗?
或者,您希望在虚拟时间2ms(即vCPU所经历的时间)后中断,还是在墙上时钟时间2ms后中断?
Arm体系结构提供了这两种功能,具体取决于虚拟化的用途。让我们看看它是如何做到这一点的。
在vCPU上运行的软件可以访问两个定时器:

  • EL1物理计时器(EL1 Physical Timer)
  • EL1虚拟计时器(EL1 Virtual Timer)

EL1物理定时器与系统计数器模块生成的计数进行比较。使用这个计时器可以获得墙上的时钟时间。
EL1虚拟计时器与虚拟计数进行比较。虚拟计数是物理计数减去偏移量。hypervisor在寄存器中指定当前计划的vCPU的偏移量。这允许它在vCPU未计划运行时隐藏时间的流逝:
在这里插入图片描述为了说明这个概念,我们可以扩展前面的例子,如下图所示:
在这里插入图片描述在6ms的时间段内,每个vCPU可以运行3ms。hypervisor可以使用偏移寄存器来显示仅显示vCPU运行时间的虚拟计数。或者hypervisor可以将偏移量保持在0,这意味着虚拟时间与物理时间相同。

虚拟化主机扩展

下图显示了我们在虚拟化异常一节中看到的软件堆栈和异常级别的简化版本:
在这里插入图片描述

您可以看到独立的(Type 1)hypervisor如何映射到Arm Exception级别。hypervisor在EL2上运行,虚拟机(VM)在EL0/1上运行。如下图所示,这种情况对托管(Type 2)hypervisor来说问题更大:
在这里插入图片描述传统上,内核在EL1中运行,但虚拟化控制在EL2中。这意味着大部分主机操作系统都在EL1,一些存根代码在EL2中运行以访问虚拟化控件。这种安排可能是低效的,因为它可能涉及额外的上下文切换。
内核将需要处理在EL1和EL2上运行之间的一些差异,但这些差异仅限于少数子系统,例如早期启动。
在EL2上运行主机操作系统
VHE(Virtualization host extensions)由HCR_ EL2中的两个比特控制。这些位可以概括为:

  • E2H:控制是否启用VHE。
  • TGE:启用VHE时,控制EL0是来宾还是主机。
    下表总结了典型设置:
    在这里插入图片描述在从虚拟机退出到hypervisor的异常中,TGE最初为0。软件必须在运行主机内核的主要部分之前设置位。
    您可以在下图中看到这些典型设置:
    在这里插入图片描述虚拟地址空间
    下图显示了引入VHE之前EL0/EL1的虚拟地址空间的样子:
    在这里插入图片描述正如在内存管理中所讨论的,EL0/1有两个区域。按照惯例,上部区域称为内核空间,下部区域称为用户空间。然而,EL2仅在地址范围的底部具有单个区域。这种差异是因为,传统上,hypervisor不会托管应用程序。这意味着hypervisor不需要在内核空间和用户空间之间进行划分。
    EL0/1虚拟地址空间也支持地址空间标识符(ASID),但EL2不支持。这是因为hypervisor通常不会托管应用程序。
    为了让我们的Host OS在EL2中高效执行,我们需要添加第二个区域和ASID支持。设置HCR_EL2.E2H可以解决这些问题,如下图所示:
    在这里插入图片描述而在EL0中,HCR_EL2.TGE控制使用哪个虚拟地址空间:EL1空间或EL2空间。使用哪个空间取决于应用程序是在 Host OS(TGE1)下运行还是在来Guest OS(TGE0)下运行。

重定向寄存器访问
我们在虚拟化通用定时器一节中看到,启用VHE会更改EL2虚拟地址空间的布局。然而,MMU的配置仍然存在问题。
这是因为我们的内核将尝试访问_EL1寄存器,如TTBR0_EL1,而不是_EL2寄存器,如TTPR0_EL2。
要在EL2上运行相同的二进制文件,我们需要将访问从EL1寄存器重定向到EL2等效寄存器。设置E2H将执行此操作,从而将对_EL1系统寄存器的访问重定向到其EL2等效寄存器。此重定向如下图所示:
在这里插入图片描述然而,这种重定向给我们留下了一个新问题。hypervisor仍然需要访问实际的_EL1寄存器,以便实现任务切换。为了解决这个问题,引入了一组带有_EL12或_EL02后缀的新寄存器别名。当在EL2使用时,在E2H==1的情况下,这些提供对EL1寄存器的访问以进行上下文切换。您可以在下图中看到这一点:
在这里插入图片描述 异常
通常,HCR_EL2.IMO/FMO/AMO位控制物理异常是路由到EL1还是EL2。当在TGE==1的EL0中执行时,所有物理异常都被路由到EL2,除非它们被SCR_EL3路由到EL3。不管HCR_EL2路由比特的实际值如何,都是这种情况。这是因为应用程序是作为Host OS的子系统而不是Guest OS执行的。因此,任何异常都应路由到EL2中运行的Host OS。

嵌套虚拟化

理论上,hypervisor可以在虚拟机(VM)中运行。此概念称为嵌套虚拟化:
在这里插入图片描述我们将第一个hypervisor称为Host Hypervisor,将虚拟机中的hypervisor称作Guest Hypervisor。
在Armv8.3-A发布之前,可以通过在EL0中运行Guest Hypervisor来在VM中运行GuestHypervisor。然而,这需要大量的软件仿真,而且实现起来很复杂,导致性能较差。通过Armv8.3-A中添加的功能,可以在EL1中运行Guest Hypervisor。有了Armv8.4-A中添加的功能,这个过程甚至更高效,尽管它仍然涉及到主机虚拟机监控程序中的额外智能。

Guest Hypervisor访问虚拟化控件
我们不想让Guest Hypervisor直接访问虚拟化控件。这是因为提供直接访问可能会使虚拟机破坏其沙盒,或发现有关主机平台的信息。这个潜在的问题类似于前面关于捕获和模拟的示例中演示的问题。
Guest Hypervisor在EL1运行。HCR_EL2中的新控件允许Host Hypervisor序捕获Guest Hypervisor访问虚拟化控件的尝试:

  • HCR_EL2.NV实现对嵌套虚拟化的硬件支持
  • HCR_EL2.NV1启用一组额外的陷阱
  • HCR_EL2.NV2允许重定向到内存
  • VNCR_EL2当NV2==1时,指向内存中的结构
    Armv8.3-A增加了NV和NV1控制。从EL1对_EL2寄存器的访问通常是未定义的,并且访问会导致EL1异常。NV和NV1位导致EL1对_EL2寄存器的访问,以陷阱到EL2。这允许访Guest Hypervisor在EL1上运行,EL2上的Host Hypervisor模拟其某些操作。NV还捕获来自EL1的ERET。
    下图显示了来宾Guest Hypervisor的设置和进入虚拟机:
    在这里插入图片描述1.Guest Hypervisor对_EL2寄存器的访问被捕获到EL2。Host Hypervisor记录Guest Hypervisor正在设置的配置。
    2.Guest Hypervisor试图进入其Guest虚拟机(he Guest VM of the Guest),ERET被捕获到EL2
    3.Host Hypervisor检索访客的访客的配置,并将该配置加载到适当的寄存器中。然后,Host Hypervisor清除NV位并进入Guest的Guest。
    这种方法的问题在于,Guest Hypervisor对EL2寄存器的每个单独访问都必须被捕获。当任务在两个vCPU或VM之间切换时,会访问许多寄存器,并导致许多陷阱。每个陷阱都有一个异常条目和返回的开销。
    一个更好的解决方案是捕获EL2寄存器的配置,并且只捕获到ERET上的Host Hypervisor。Armv8.4-A可以实现此解决方案。当设置NV2时,EL1对_EL2寄存器的访问将重定向到内存中的结构。Guest Hypervisor可以根据需要多次读取和写入寄存器,而不需要单个陷阱。ERET仍然捕获到EL2,此时Host Hypervisor可以从内存中重新检索配置。
    下图说明了这一概念:
    在这里插入图片描述1.从EL1中的访客管理程序对_EL2寄存器的访问被重定向到存储器中的结构。结构的位置由Host Hypervisor使用VNCR_EL2指定
    2.Guest Hypervisor试图进入其Guest VM,该Guest VM是Guest的Guest VM并且ERET被捕获到EL2。
    3.Host Hypervisor检索Guest的Guest的配置,并将其加载到适当的寄存器中。然后,host hypervisor清除NV位并进入Guest的Guest。
    这种方法的优点是陷阱更少,因此进入Host Hypervisor的条目更少。

安全虚拟化

Armv7-A中引入了虚拟化。当时,Hyp模式相当于AArch32中的EL2,仅在非安全状态下可用。在引入Armv8.4-A时,添加了对处于安全状态的EL2的支持作为可选功能。
当处理器支持安全EL2时,需要使用SCR_EL3.EEL2位从EL3启用处理器。设置此位可以进入EL2,并在安全状态下使用虚拟化功能。
在安全虚拟化可用之前,EL3通常用于托管安全状态切换软件和平台固件的混合。这是因为我们喜欢尽量减少EL3中的软件量,这样EL3更容易安全。安全虚拟化使我们能够将平台固件移动到EL1中。虚拟化为平台固件和可信内核提供了单独的安全分区。下图说明了这一点:
在这里插入图片描述安全EL2和两个中间物理地址空间
Arm体系结构定义了两个物理地址空间:安全和非安全。在非安全状态下,虚拟机(VM)的stage 1转换的输出总是非安全的。因此,存在单个中间物理地址(IPA)空间供stage 2处理。
在安全状态下,VM的stage 1阶段转换可以输出安全地址和非安全地址。转换表描述符中的NS位控制输出安全地址空间还是非安全地址空间。如下图所示,这意味着stage 2阶段有两个IPA空间,即安全和非安全:
在这里插入图片描述与stage 1阶段的表不同,stage 2阶段的表条目中没有NS位。对于特定的IPA空间,所有转换都会产生安全物理地址或非安全物理地址。此转换由寄存器位控制。通常,非安全IPA转换为非安全PA,而安全IPA则转换为安全PA。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值