Learn the architecture - AArch64 虚拟化

一、前言

        本指南介绍了 Armv8-A AArch64 中的虚拟化支持。涵盖的范围包括stage 2地址翻译,虚拟异常(virtual exceptions)和捕获(trapping)

        本指南介绍了一些基本的虚拟化理论,并提供了一些示例来说明虚拟机管理程序(hypervisor )如何使用这些功能。但是本指南不包含任何特定的hypervisor程序,以及如何实现hypervisor

二、虚拟化简介

        本章对虚拟化理论和hypervisor做一些基础性的介绍,如果已经对这些概念有了解,可以跳过本章

        本章中,hypervisor表示负责创建、管理和调度虚拟机 (VM) 的软件。

2.1 虚拟化为什么重要

        虚拟化是一项广泛使用的技术,支撑着几乎所有现代云计算和企业基础设施。开发人员使用虚拟化在一台机器上运行多个操作系统 (OS),并在不损坏主计算环境的情况下测试软件。

        虚拟化在服务器系统中很流行,并且支持虚拟化是大多数服务器级处理器的要求。这是因为虚拟化为数据中心提供了非常理想的功能,包括:

  •  隔离:虚拟化的核心是为单个物理系统上运行的多个虚拟机提供隔离。这种隔离允许在相互不信任的计算环境之间共享物理系统。例如,两个竞争对手可以共享数据中心中的同一台物理机器,而无法访问彼此的数据。
  • 高可用性:虚拟化允许在物理机器之间无缝且透明地迁移工作负载。此技术通常用于将工作负载从可能需要维护和更换的故障硬件平台迁移出去
  • 负载均衡:为了优化数据中心的硬件和功率预算,尽可能多地使用每个硬件平台非常重要。同样,这可以通过虚拟机迁移或通过在物理机上共同托管合适的工作负载来实现。这意味着尽可能多地利用物理机的容量。这为数据中心提供商提供了最佳的功率预算,并为租户提供了最佳的性能。
  • 沙箱:虚拟机可用于为可能干扰其运行的计算机的其他部分的应用程序提供沙箱。此类应用程序的示例包括遗留应用程序或正在开发的软件。在虚拟机中运行这些应用程序可以防止应用程序的错误或恶意部分干扰物理机上的其他应用程序或数据。

2.2 Standalone and hosted hypervisors

        hypervisor可以分为2类:Standalone hypervisor(type1)和hosted hypervisor(type 2)。

        我们将首先看看hosted hypervisor。在type 2的hypervisor配置中,主机操作系统可以完全控制硬件平台及其所有资源,包括 CPU 和物理内存。下图说明了type 2的hypervisor:

        如果您以前使用过 Virtual Box 或 VMware Workstation 等软件,那么您所运行的hypervisor就是这种类型。host os安装在平台上,hypervisor在host os内运行,利用现有功能来管理硬件。然后,hypervisor可以管理虚拟机,虚拟机本身运行guest os。 

        接下来是Standalone  也就是type 1的hypervisor

        您可以看到此hypervisor设计中没有host os。hypervisor直接运行在硬件上,并完全控制硬件平台及其所有资源,包括CPU和物理内存。独立hypervisor也可以托管虚拟机。这些虚拟机可以运行一个或多个完整的guest os。

        Arm 平台上最常用的两种开源hypervisor是 Xen(Standalone  ,type 1)和 KVM(hosted,type 2)。我们将使用这些虚拟机管理程序来说明本指南中的一些要点。然而,还有许多其他可用的虚拟机管理程序,包括开源的和闭源的。

2.3 全虚拟化和半虚拟化

        VM 的经典定义是独立的、隔离的计算环境,与真实的物理机器没有区别。尽管可以在基于 Arm 的系统上完全模拟真实机器,但这通常不是一件高效的事情。因此,这种模拟并不常见。例如,模拟真实的以太网设备很慢,因为 Guest OS 对模拟寄存器的每次访问都必须由hypervisor以软件方式处理。这种处理比访问物理设备上的寄存器要昂贵得多。

        通常用于提高性能的首选替代方案是让guest os知道运行在虚拟机,并为虚拟机提供性能良好的虚拟设备,即使对于I/O来说也可以获得良好的性能

        如今,在大多数具有虚拟化硬件支持的架构(包括 Arm)上,guest OS大多无需修改即可运行。guest OS认为它是在真实硬件上运行的,除了块存储和网络等 I/O 外围设备的驱动程序,这些驱动程序使用半虚拟化设备和设备驱动程序。此类半虚拟化 I/O 设备的示例包括 Virtio 和 Xen PV Bus。

2.4 VM和VCPU

        了解虚拟机 (VM) 和虚拟 CPU (vCPU) 之间的区别非常重要。一台VM将包含一个或多个vCPU,如下图所示:

        当我们查看本指南中的其他主题时,VM 和 vCPU 之间的区别将变得很重要。例如,一页内存可能分配给 VM,因此可供该 VM 中的所有 vCPU 访问。但是,虚拟中断针对的是特定的 vCPU,并且只能转到该 vCPU。

        严格来说,我们应该指的是虚拟处理元件 (vPE),而不是 vCPU。请记住,处理元件 (PE) 是实现 Arm 架构的机器的通用术语。本指南使用 vCPU 而不是 vPE,因为 vCPU 是大多数人熟悉的术语。然而,在架构规范中,使用了术语“vPE”。

三、AArch64中的虚拟化

        在EL2或更高level 上运行的软件可以有几种控制虚拟化的方式:

  • stage 2 地址翻译
  • EL1/0指令和寄存器访问捕获(trapping)
  • 生成虚拟异常

        非安全和安全状态下的异常级别如下所示:

        在图中,安全EL2显示为灰色, 这是因为安全状态下对EL2的支持是可选的。这部分内容在安全虚拟化章节讨论。

四、stage 2地址翻译

4.1 什么是stage 2地址翻译

        stage 2地址翻译允许hypervisor控制VM中的内存视图。具体来说,它允许hypervisor控制vm可以访问哪些被映射的系统资源,以及这些资源出现在VM地址空间中的位置。

        这种控制内存访问的能力对于隔离和沙箱非常重要。stage 2地址转换可用于确保VM只能看到分配给它的资源,而看不到分配给其他VM或者hypervisor的资源

        对于内存地址翻译,stage 2是翻译的第二阶段,为了支持这一功能,需要一组新的页表,成为stage 2页表,如下所示(VA->IPA->PA的地址转换过程):

        OS控制一组页表,这些页表从虚拟地址空间映射到它认为的物理地址空间(实际上的IPA),实际上,这个过程需要经过stage 2的转换才能映射到真实的物理地址空间。stage 2由hypervisor控制。OS控制的地址翻译称为stage 1地址转换,hypervisor控制的称为stage 2地址转换。OS认为的物理内存空间被称为IPA(中间物理地址)

4.2 VMID

        每个VM都分配有一个VMID,VMID用于标记TLB条目,以识别每个条目属于哪个虚拟机。此标记允许多个不同虚拟机的转换同时存在于TLB中。VMID存储在VTTBR_EL2中,可以是8位或者16位,VMID 由 VTCR_EL2.VS 位控制。对 16 位 VMID 的支持是可选的,已添加到 Armv8.1-A 中。

        EL2 和 EL3 翻译机制的翻译没有标记 VMID,因为它们不受第 2 阶段翻译的影响

4.3 VMID和ASID交互

        TLB条目也可以用ASID标记。操作系统会为应用程序分配一个 ASID,并且该应用程序中的所有 TLB 条目都用该 ASID 标记。这意味着不同应用程序的 TLB 条目能够在 TLB 中共存,而一个应用程序不可能使用属于另一个应用程序的 TLB 条目

        每个VM都有自己的 ASID 命名空间。例如,两个虚拟机可能都使用 ASID 5,但它们将其用于不同的用途。ASID 和 VMID 的组合才是最重要的。

4.4 属性组合和覆盖

        stage 1和stage 2地址翻译都包含属性,例如memory内存和访问权限,内存管理单元 (MMU) 将两个stage的属性组合起来,给出最终有效值。MMU 通过选择约束更强的stage来实现这一点,如下所示:

        在这个示例中,device memory比normal memory限制更多。因此,结果类型是device,如果我们颠倒示例,即stage 1=normal,stage 2 = device,结果是一样的。

        这种组合属性的方法适用于大多数情况,但有时hypervisor可能希望覆盖此行为。例如在虚拟机启动初期。对于这些情况,有一些控制位可以覆盖正常行为:

  • HCR_EL2.CD. 这使得所有第一阶段的属性都是non-cacheable。
  • HCR_EL2.DC. 强制stage 1属性为normal,Write-Back Cacheable.
  • HCR_EL2.FWB. 允许stage 2覆盖stage 1属性,而不是组合属性

        HCR_EL2.FWB 在 Armv8.4-A 中引入。

4.5 MMIO

        与物理机上的物理地址空间一样,VM 中的 IPA 空间包含用于访问内存和外设的区域,如下所示:

        VM可以使用 外围设备区域来访问真实物理外围设备(通常称为直接分配的外围设备)和虚拟外围设备。

        虚拟外设由hypervisor在软件中完全模拟,如下图所示:

        分配的外设是已分配给VM并映射到其IPA空间的真实物理设备。这允许虚拟机内运行的软件直接与外围设备交互。 

        虚拟外设是hypervisor将在软件中模拟的外设。相应的stage 2页表条目将被标记为fault。 VM 中的软件认为它可以直接与外设通信,但每次访问都会触发stage 2故障,hypervisor会在异常处理程序中模拟外设访问。

        为了模拟外围设备,hypervisor不仅需要知道访问了哪个外围设备,还需要知道访问了该外围设备的哪个寄存器、访问是读还是写、访问的大小以及用于传输数据的寄存器。

        异常模型指南介绍了 FAR_ELx 寄存器。当处理stage 1 fault时,这些寄存器报告触发异常的虚拟地址。虚拟地址对hypervisor没有帮助,因为hypervisor通常不知道来宾操作系统如何配置其虚拟地址空间。对于stage 2 fault,有一个附加寄存器 HPFAR_EL2,它报告中止地址的 IPA。由于 IPA 空间由管理程序控制,因此它可以使用此信息来确定需要模拟的寄存器。

        对于触发stage 2 fault的单个通用寄存器load or store,提供了附加校正子信息。该信息包括访问的大小以及源或目标寄存器,并允许hypervisor确定对虚拟外设进行的访问的类型。

        下图说明了捕获然后模拟访问的过程:

该过程描述了以下步骤:

  •  VM 中的软件尝试访问虚拟外设。在此示例中,这是虚拟 UART 的接收 FIFO。
  • 此访问在stage 2转换时被阻止,触发了路由到EL2的abort异常
    • abort异常会使用ESR_EL2记录有关异常的信息,包括访问的字节数,目标寄存器以及是load还是store
    • abort还会使用IPA填充到HPFAR_EL2
  • hypervisor使用ESR_EL2 和HPFAR_EL2 的信息来识别访问的虚拟外设寄存器。此信息允许hypervisor模拟操作。然后通过ERET返回到vCPU
    • 从LDR之后的执行重新开始执行

4.6 SMMU

        到目前为止,我们已经考虑了来自处理器的不同类型的访问。系统中的其他masters(例如 DMA 控制器)可能会被分配供 VM 使用。我们还需要某种方法将stage 2的保护扩展到这些master。

        考虑一个不使用虚拟化的 DMA 控制器的系统,如下图所示:

        DMA 控制器将通过驱动程序进行编程,通常在内核空间中。该内核空间驱动程序可以确保操作系统级别的内存保护不被破坏。这意味着一个应用程序无法使用 DMA 来访问它不应该看到的内存。 

        让我们考虑相同的系统,但操作系统在虚拟机中运行,如下图所示:

         在这个系统中,hypervisor使用stage 2地址转换来提供虚拟机之间的隔离。软件查看内存的能力受到hypervisor控制的stage 2页表的限制。

        允许 VM 中的驱动程序直接与 DMA 控制器交互会产生两个问题:

  • 隔离:DMA 控制器不受stage 2页表的约束,并且可用于破坏虚拟机的沙箱。
  • 地址空间:通过两个转换阶段,内核认为是 PA 的实际上是 IPA。DMA 控制器仍然看到 PA,因此内核和 DMA 控制器对内存有不同的看法。为了解决这个问题,hypervisor可以捕获虚拟机和 DMA 控制器之间的每次交互,从而提供必要的转换。当内存碎片化时,这个过程效率低下且存在问题。

        捕获和模拟驱动程序访问的替代方法是扩展stage 2机制以覆盖其他主设备,例如我们的 DMA 控制器。当这种情况发生时,那些master也需要一个MMU。这称为系统内存管理单元(SMMU,有时也称为 IOMMU):

         hypervisor负责对 SMMU 进行编程,以便上游主机(在我们的示例中为 DMA)看到与其被分配到的 VM 相同的内存视图。

        此过程解决了我们发现的两个问题。SMMU可以强制VM之间的隔离,确保外部master无法用于破坏沙箱。SMMU还为VM中的软件和分配给VM的外部master提供了一致的内存视图。

        虚拟化不是SMMU的唯一使用场景,还有许多其他的情况未涵盖在本指南的范围内。

五、指令的捕获和模拟

        有时,hypervisor需要模拟虚拟机 (VM) 内的操作。例如,VM 内的软件可能会尝试配置与电源管理或缓存一致性相关的控制寄存器。通常,您不希望让 VM 直接访问这些控制寄存器,因为它们可能被用来破坏隔离或影响系统中的其他 VM

        当执行给定操作(例如读取寄存器)时,trap会导致异常。hypervisor需要能够捕获虚拟机中的操作(例如配置系统控制寄存器的操作)并模拟这些操作,而不会影响其他虚拟机。

        该架构包括trap控制,可让您捕获虚拟机中的操作并模拟这些操作。设置trap后,执行通常允许的特定操作会导致更高异常级别的异常。hypervisor可以使用这些trap来模拟虚拟机中的操作。

        例如:执行等待中断 (WFI) 指令通常会使 CPU 进入低功耗状态。通过置位TWI位,如果 HCR_EL2.TWI==1,则在 EL0 或 EL1 处执行 WFI 将导致 EL2 异常。

        trap不仅仅适用于虚拟化,还有 EL3 和 EL1 控制的trap。然而,trap对于虚拟化软件特别有用。本指南仅讨论通常与虚拟化相关的trap。

        在我们的 WFI 示例中,操作系统通常会将 WFI 作为空闲循环的一部分来执行。使用虚拟机中的 Guest OS,hypervisor可以捕获此操作并改为安排不同的 vCPU,如下图所示:

5.1 显示寄存器的虚拟值

        使用trap的另一个示例是显示寄存器的虚拟值。例如,ID_AA64MMFR0_EL1 报告处理器对内存系统相关功能的支持。操作系统可能会在启动过程中读取此寄存器,以确定要启用内核中的哪些功能。hypervisor可能希望向客户操作系统显示一个不同的值,称为虚拟值。

        为此,hypervisor会启用涵盖寄存器读取的trap。在发生trap异常时,hypervisor会确定触发了哪个trap,然后模拟该操作。在此示例中,虚拟机管理程序使用 ID_AA64MMFR0_EL1 的虚拟值填充目标寄存器,如下所示:

        trap还可以用作lazy  context switching的一部分。例如,操作系统通常会在启动期间初始化内存管理单元 (MMU) 配置寄存器 (TTBR<n>_EL1、TCR_EL1 和 MAIR_EL1),然后不会再次对其进行重新编程。hypervisor可利用这一点来优化其上下文切换,方法是仅在上下文切换时恢复寄存器而不保存它们。

        但是,操作系统可能会在启动后执行一些不寻常的操作并重新编程寄存器。为了避免这导致任何问题,hypervisor可以设置 HCR_EL2.TVM trap。此设置会导致对 MMU 相关寄存器的任何写入都会在 EL2 中生成trap,这允许虚hypervisor检测是否需要更新其保存的这些寄存器的副本。

        该架构使用术语“捕获”和“路由”来表示独立但相关的概念。概括地说,当执行给定操作(例如读取寄存器)时,捕获会导致异常。路由是指异常生成后被带到的异常级别。

5.2 MIDR和MPIDR

        使用trap来虚拟化操作需要大量计算。该操作会生成 EL2 trap异常,hypervisor会确定所需的操作,对其进行模拟,然后返回给客户机。功能寄存器(例如 ID_AA64MMFR0_EL1)不经常被操作系统访问。这意味着,当将这些寄存器的访问捕获到hypervisor中以模拟读取时,计算是可以接受的。

        对于访问频率较高的寄存器或性能关键代码,您需要避免此类计算负载。这些寄存器及其值的示例包括:

  • MIDR_EL1。处理器的类型,例如 Cortex-A53
  • MPIDR_EL1. 亲和性,例如处理器 2 的核心 1

        hypervisor可能希望guest os能够查看这些寄存器的虚拟值,而不必捕获每个单独的访问。对于这些寄存器,该架构提供了一种替代捕获的方法:

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

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

        VMPIDR_EL2 和 VPIDR_EL2 没有定义的复位值。它们必须在首次进入 EL1 之前由启动代码初始化。这在裸机环境中尤其重要。

六、虚拟化异常

        系统中的硬件使用中断向软件发出事件信号。例如,GPU 可能会发送中断来表示它已完成渲染一帧。

        使用虚拟化的系统更为复杂。某些中断可能由虚拟机管理程序本身处理。其他中断可能来自分配给虚拟机 (VM) 的设备,需要由该 VM 内的软件处理。此外,中断所针对的 VM 可能在收到中断时未运行。

        这意味着您需要机制来支持管理程序处理 EL2 中的某些中断。您还需要将其他中断转发到特定 VM 或 VM 内的特定虚拟 CPU (vCPU) 的机制。

        为了启用这些机制,该架构包括对虚拟中断的支持:vIRQ、vFIQ 和 vSError。这些虚拟中断的行为与其物理对应中断(IRQ、FIQ 和 SError)类似,但只能在 EL0 和 EL1 中执行时发出信号。在 EL2 或 EL3 中执行时不可能接收虚拟中断。

         回顾一下,Armv8.4-A 引入了对安全状态下虚拟化的支持。要在 Secure EL0/1 中发出虚拟中断信号,需要支持并启用 Secure EL2。否则,安全状态下不会发出虚拟中断信号。

6.1 启用虚拟中断

        要将虚拟中断信号发送到 EL0/1,hypervisor必须在 HCR_EL2 中设置相应的路由位。例如,要启用 vIRQ 信号,hypervisor必须设置 HCR_EL2.IMO。此设置将物理 IRQ 异常路由到 EL2,并允许将虚拟异常信号发送到 EL1。

        拟中断由中断类型控制。理论上,VM 可以配置为接收物理 FIQ 和虚拟 IRQ。实际上,这种情况并不常见。VM 通常仅配置为接收虚拟中断。

6.2 生成虚拟中断

        产生虚拟中断的机制有两种:

  • 由core内部使用 HCR_EL2 控制
  • 使用 GICv2 或更高版本的中断控制器。

        让我们从机制 1 开始。HCR_EL2 中有3个bit控制虚拟中断的生成:

  • VI = 设置此位注册一个 vIRQ
  • VF = 设置该位会注册 vFIQ
  • VSE = 设置此位会注册一个 vSError。

        设置这些位之一相当于中断控制器向 vCPU 发出中断信号。生成的虚拟中断受到 PSTATE 屏蔽,就像常规中断一样。

        这种机制使用简单,但缺点是它只提供了一种产生中断本身的方法。然后,hypervisor需要模拟虚拟机中中断控制器的操作。回顾一下,软件中的捕获和模拟操作涉及开销,最好避免频繁操作(例如中断)。

        第二种选择是使用 Arm 的通用中断控制器 (GIC) 来生成虚拟中断。从 Arm GICv2 开始,GIC 可以通过提供物理 CPU 接口和虚拟 CPU 接口来发出物理和虚拟中断信号,如下图所示:

        physical cpu interface和 virtual CPU interface 这两个接口是相同的,只是一个接口发出物理中断信号,另一个接口发出虚拟中断信号。hypervisor可以将虚拟 CPU 接口映射到 VM,从而允许该 VM 中的软件直接与 GIC 通信。这种方法的优点是hypervisor只需要设置虚拟接口,而不需要模拟它。这种方法减少了执行需要被捕获到 EL2 的次数,因此减少了虚拟化中断的开销。

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

6.3 将中断转发到vCPU的示例

        到目前为止,我们已经了解了如何启用和生成虚拟中断。让我们看一个示例,该示例展示了将虚拟中断转发到 vCPU。在此示例中,我们将考虑已分配给 VM 的物理外设,如下图所示

该图说明了这些步骤: 

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

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

6.4 中断屏蔽和虚拟中断

        在 AArch64异常模型指南中,我们介绍了 PSTATE 中的中断掩码位,IRQ 的 PSTATE.I、FIQ 的 PSTATE.F 和 SError 的 PSTATE.A。在虚拟化环境中运行时,这些掩码的工作方式略有不同。

        例如,对于 IRQ,我们已经看到设置 HCR_EL2.IMO 会产生两件事:

  • 将物理 IRQ 路由到 EL2
  • 在 EL0 和 EL1 中启用 vIRQ 信号

        此设置还会改变 PSTATE.I 掩码的应用方式。在 EL0 和 EL1 中,如果 HCR_E2.IMO==1,则 PSTATE.I 对 vIRQ 而非 pIRQ 进行操作。

6.5 虚拟化通用定时器

        Arm 架构包括通用定时器(Generic Timer),它是每个处理器中可用的一组标准化定时器。通用定时器由一组比较器组成,这些比较器与公共system counter进行比较。当比较器的值等于或小于system counter时,比较器会生成中断。在下图中,我们可以看到系统中的通用定时器及其比较器和计数器模块的组件

下图显示了一个具有托管两个虚拟 CPU (vCPU) 的管理程序的示例系统: 

        在示例中,我们忽略了运行hypervisor来切换vcpu的开销

        经过4 毫秒的物理时间(或墙钟)后,每个 vCPU 已运行 2 毫秒。如果 vCPU0 在T=0时刻设置为在 3ms 后生成中断,您是否期望中断已触发?或者,您想要在 2 毫秒的虚拟时间(vCPU 经历的时间)之后,还是在 2 毫秒的墙钟时间之后中断?

        Arm 架构提供了同时执行这两项操作的能力,具体取决于虚拟化的用途。让我们看看它是如何做到这一点的。

        在 vCPU 上运行的软件可以访问两个timer:

  • EL1物理Timer
  • EL1虚拟Timer

        EL1物理timer与system counter生成的计数进行比较,使用此timer可以提供wall clock

        EL1虚拟timer与虚拟system counter比较,虚拟计数器是物理计数减去偏移量。hypervisor在寄存器中指定当前调度的vCPU的偏移量。这允许它在vCPU未调度运行时隐藏时间的流逝。

        为了说明这个概念,我们可以扩展前面的示例,如下图所示 

        在 6 毫秒的时间内,每个 vCPU 运行 3 毫秒。hypervisor可以使用偏移寄存器来呈现仅显示 vCPU 运行时间的虚拟计数。或者hypervisor可以将偏移量保持为 0,这意味着虚拟时间与物理时间相同。 

        该示例显示system counter的频率为 1ms。实际上,这个频率值不太可能出现。我们建议您将系统计数设置为使用 1MHz 到 50MHz 之间的频率。

七、Virtualization host extensions(VHE 虚拟化主机扩展)

        下图显示了我们在虚拟化异常部分中看到的软件堆栈和异常级别的简化版本

        您可以看到独立hypervisor如何映射到 Arm 异常级别。hypervisor在 EL2 上运行,虚拟机 (VM) 在 EL0/1 上运行。

        VHE之前的hosted hypervisors如下图所示:

        传统上,内核在 EL1 上运行,但虚拟化控制在 EL2 中。这意味着大多数主机操作系统都在 EL1 上,而一些代码在 EL2 中运行以访问虚拟化控制。这种安排可能效率低下,因为它可能涉及额外的上下文切换。 

        内核需要处理在 EL1 和 EL2 上运行之间的一些差异,但这些差异仅限于少数子系统,例如早期启动。

        DynamIQ 处理器(Cortex-A55、Cortex-A75 和 Cortex-A76)支持虚拟化主机扩展 (VHE)。

7.1 在EL2上运行host os

        VHE 由 HCR_EL2 中的两个位控制。这些位可以概括为:

  • E2H:控制是否启用VHE
  • TGE:当VHE启用时,控制EL0是Guest还是Host

下表总结了典型的设置:

HCR_EL2中执行:E2HTGE
Guest kernel(EL1)10
Guest App(EL0)10
Host kernel(EL2)11
Host App(EL0)11

         当从 VM 退出到hypervisor时发生异常,TGE 最初为 0。软件必须在运行host kernel的主要部分之前设置该位

        可以在下图中看到这些典型设置:

7.2 虚拟地址空间

         下图展示了在引入 VHE 之前 EL0/EL1 的虚拟地址空间:

        

        如内存管理中所述,EL0/1 有两个区域。按照惯例,上部区域称为内核空间,下部区域称为用户空间。但是,EL2 仅在地址范围的底部有一个区域。这种差异是因为传统上,hypervisor不会托管应用程序。这意味着hypervisor不需要在内核空间和用户空间之间进行划分。 

        EL0/1 虚拟地址空间还支持地址空间标识符 (ASID),但 EL2 不支持。这是因为hypervisor通常不会托管应用程序。

        为了让我们的主机操作系统在 EL2 中高效执行,我们需要添加第二个区域和 ASID 支持。设置 HCR_EL2.E2H 解决了这些问题,如下图所示:

         在EL0 中,HCR_EL2.TGE 控制使用哪个虚拟地址空间:EL1 空间或 EL2 空间。使用哪个空间取决于应用程序是在host os(TGE==1)还是guest os(TGE==0)下运行。 

7.3 重定向寄存器访问

        我们在上一节看到,启用 VHE 会更改 EL2 虚拟地址空间的布局。然而,我们仍然遇到MMU配置的问题。这是因为我们的内核将尝试访问 _EL1 寄存器,例如 TTBR0_EL1,而不是 _EL2 寄存器,例如 TTBR0_EL2。

        要在 EL2 上运行相同的二进制文件,我们需要将访问从 EL1 寄存器重定向到 EL2 等效寄存器。设置 E2H 将执行此操作,以便对 _EL1 系统寄存器的访问重定向到其 EL2 等效寄存器。这种重定向如下图所示:

        但是,这种重定向给我们带来了一个新问题。hypervisor仍然需要访问真实的 _EL1 寄存器,以便实现任务切换。为了解决这个问题,引入了一组带有 _EL12 或 _EL02 后缀的新寄存器别名。当在 EL2 中使用时,如果 E2H==1,这些寄存器可以访问 EL1 寄存器以进行上下文切换。您可以在下图中看到这一点: 

        当 E2H==1 时从 EL2 访问 EL1 寄存器:

        通常,HCR_EL2.IMO/FMO/AMO 位控制物理异常是否路由到 EL1 或 EL2。当在 TGE==1 的情况下在 EL0 中执行时,所有物理异常都将路由到 EL2,除非它们被 SCR_EL3 路由到 EL3。无论 HCR_EL2 路由位的实际值如何,情况都是如此。这是因为应用程序是作为主机操作系统的子级而不是客户操作系统执行的。因此,任何异常都应路由到在 EL2 中运行的主机操作系统。

八、嵌套虚拟化

        理论上,虚拟机管理程序可以在虚拟机 (VM) 内运行。这个概念称为嵌套虚拟化:

        我们将第一个虚拟机管理程序称为host hypervisor,将 VM 内的虚拟机管理程序称为guest hypervisor。 

        在 Armv8.3-A 发布之前,可以通过在 EL0 中运行 Guest Hypervisor 。然而,这需要大量的软件模拟,并且实施起来很复杂,并且性能较差。通过 Armv8.3-A 中添加的功能,可以在 EL1 中运行 Guest Hypervisor。通过 Armv8.4-A 中添加的功能,该过程更加高效,尽管它仍然涉及host hypervisor中的额外开销。

8.1 guest hypervisor 访问虚拟化控制

        我们不想让guest 管理程序直接访问虚拟化控件。这是因为直接访问可能会让虚拟机突破其沙箱,或者发现有关主机平台的信息。此潜在问题与前面有关捕获和模拟的示例中演示的问题类似。

         guest hypervisor在 EL1 上运行。HCR_EL2 中的新控件允许host hypervisor捕获guest hypervisor访问虚拟化控件的尝试:

  • HCR_EL2.NV 启用嵌套虚拟化的硬件支持
  • HCR_EL2.NV1 启用一组额外的trap
  • HCR_EL2.NV2 启用内存重定向
  • VNCR_EL2 当NV2==1时,指向内存中的一个结构

        Armv8.3-A 添加了 NV 和 NV1 控件。从 EL1 访问 _EL2 寄存器通常是未定义的,并且访问会导致 EL1 异常。 NV 和 NV1 位导致 EL1 对 _EL2 寄存器的访问转而捕获到 EL2。这允许来宾管理程序在 EL1 上运行,而主机管理程序在 EL2 上模拟其某些操作。 NV 还捕获来自 EL1 的 ERET。

        下图显示了 Guest Hypervisor 设置并进入 VM:

  •  Guest Hypervisor 对 _EL2 寄存器的访问会被捕获到 EL2 中。Host Hypervisor 会记录 Guest Hypervisor 正在设置的配置。
  • Guest Hypervisor尝试进入其Guest VM(Guest的Guest VM),ERET被困到EL2
  • host hypervisor检查 Guest 的 Guest 配置,并将此配置加载到适当的寄存器中。然后host hypervisor清除 NV 位并进入 Guest 的 Guest。      

        这种方法的问题在于,Guest Hypervisor 对 EL2 寄存器的每次单独访问都必须被捕获。当任务在两个vCPU或VM之间切换时,会访问许多寄存器,并导致许多陷阱。每个陷阱都有异常进入和返回的开销。

        更好的解决方案是捕获 EL2 寄存器的配置,并仅捕获到 ERET 上的host hypervisor。 Armv8.4-A 可以实现此解决方案。当设置 NV2 时,EL1 对 _EL2 寄存器的访问将被重定向到内存中的结构。guest hypervisor可以根据需要多次读写寄存器,而不会出现任何trap。 ERET 仍然陷入 EL2,此时host hypervisor可以从内存中重新检索配置

        下图说明了这个概念:

  •  EL1 中的 Guest Hypervisor 对 _EL2 寄存器的访问被重定向到内存中的结构。结构的位置由 Host Hypervisor 使用 VNCR_EL2 指定
  • Guest Hypervisor 尝试进入其 Guest VM,即 Guest 的 Guest VM,ERET 被捕获到 EL2。
  • 主机虚拟机管理程序检索 Guest 的 Guest 配置,并将其加载到适当的寄存器中。然后,主机虚拟机管理程序清除 NV 位并进入 Guest 的 Guest。

        这种方法的优点是陷阱较少,因此host hypervisor的条目也较少。

九、安全虚拟化

        Armv7-A 引入了虚拟化,当时 Hyp 模式(相当于 AArch32 中的 EL2)仅在 Non-secure 状态下可用,Armv8.4-A 推出时,添加了 Secure 状态下对 EL2 的支持作为可选功能。

        当处理器支持 Secure EL2 时,需要使用 SCR_EL3.EEL2 位从 EL3 启用处理器。设置此位可进入 EL2,并允许在安全状态下使用虚拟化功能。

        在安全虚拟化可用之前,EL3 通常用于托管安全状态切换软件和平台固件的混合体。这是因为我们希望尽量减少 EL3 中的软件数量,以便 EL3 更易于保护。安全虚拟化允许我们将平台固件移入 EL1。虚拟化为平台固件和可信内核提供了单独的安全分区。下图说明了这一点:

9.1 secure EL2和2个IPA地址空间

        Arm 架构定义了两个物理地址空间:安全和非安全。在非安全状态下,虚拟机 (VM) stage 1地址转换的输出始终为非安全。因此,stage 2需要处理单个中间物理地址 (IPA) 空间。

        在安全状态下,虚拟机的stage 1转换可以输出安全和非安全地址。转换表描述符中的 NS 位控制输出的是安全还是非安全地址空间。如下图所示,这意味着第 2 阶段有两个 IPA 空间,分别是安全和非安全:

  •         与stage 1页表不同,stage 2页表条目中没有 NS 位。对于特定的 IPA 空间,所有转换都会产生安全物理地址或非安全物理地址。该转换由寄存器位控制。通常,非安全 IPA 会转换为非安全 PA,安全 IPA 会转换为安全 PA。

十、虚拟化的成本

        虚拟化成本取决于虚拟机管理程序需要为虚拟机 (VM) 提供服务时在虚拟机 (VM) 和虚拟机管理程序之间切换所需的时间。在 Arm 系统上,此类成本的下限为:

  • 31x 64 位通用寄存器 (X0..X30)
  • 32 个 128 位浮点/SIMD 寄存器 (V0..V31)
  • 两个堆栈指针(SP_EL0、SP_EL1)
  • 十一、参考文档

  • Documentation – Arm Developer
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值