ARMv8虚拟化基础知识(下)

本文涉及的产品
公网NAT网关,每月750个小时 15CU
简介: ARMv8虚拟化基础知识(下)

6 虚拟化异常


硬件使用中断发送信号给软件。比如,GPU使用中断通知它已经完成帧的渲染。

在支持虚拟化的系统中,这部分就更为复杂了。某些中断可能是hypervisor本身处理。其它的中断可能分配到VM中,由其中的软件进行处理。另外,当接收到中断时,中断的目标VM可能没在运行中。

这就意味着,你需要一些机制支持hypervisor处理EL2上的中断。另外,还需要一些机制,转发中断到特定的VM或者特定的vCPU上。

为了使能这些机制,ARMv8架构支持虚拟中断:vIRQvFIQvSError。这些虚拟中断的行为与物理中断(IRQFIQSError类似,但只能在EL0EL1上执行时发出信号。在EL2EL3上执行时,是不可能接收到虚拟中断的。

注意:安全状态的虚拟化支持是在ARMv8.4-A扩展中引入的。为了在安全EL0/1中,发出虚拟中断的信号,需要支持安全EL2并使能它。否则,在安全状态下是不会发送虚拟中断信号的。


6.1 使能虚拟中断


为了发送虚拟中断到EL0/1hypervisor必须设置HCR_EL2寄存器中相关的路由标志位。比如,为了使能vIRQ中断信号,必须设置HCR_EL2.IMO标志位。这种设置,将物理IRQ中断路由到EL2,然后,由hypervisor使能虚拟中断,发送信号到EL1

理论上,可以配置VM接收物理FIQ中断和虚拟IRQ中断。实际上,这是不同寻常的。VM通常只接收虚拟中断信号。


6.2 产生虚拟中断


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

  • 由CPU核内部产生,通过HCR_EL2中的一些控制位实现。
  • 使用GICv2或更新架构的中断控制器。(参考另一篇文章《GICv3-软件概述》的第8章)

让我们从机制1开始。HCR_EL2中,有3个标志位控制虚拟中断的产生:

  • VI:设置该标志位注册一个vIRQ中断。
  • VF:设置该标志位注册一个vFIQ中断。
  • VSE:设置该标志位注册一个vSError中断。

设置这些标志位,等价于中断控制器产生一个中断信号给vCPU。产生的虚拟中断收到PSTATE屏蔽,就像常规中断那样。

这种机制简单易用,但缺点就是,只提供了产生该中断自身的一种方法。hypervisor需要在VM中模拟中断控制器的操作。总的来说,通过陷入、模拟的方式涉及到开销问题,对于频繁的操作,尤其是中断,最好避免。

第二种方法是使用ARM提供的通用中断控制器(GIC),产生虚拟中断。从GICv2开始,通过提供物理CPU接口和虚拟CPU接口,中断控制器可以发送物理中断和虚拟中断两种信号。如下图所示:


640.png

两种接口是一样的,除了一个发送物理中断信号而另外一个发送虚拟中断信号之外。hypervisor可以将虚拟CPU接口映射到VM,这样,VM中的软件就可以直接和GIC通信。这种方法的优点是,hypervisor只需要配置虚拟接口即可,不需要模拟它。这种方法减少了需要陷入到EL2中执行的次数,因此也就减少了虚拟化中断的开销。

虽然,GICv2可以与ARMv8-A一起使用,但更常见的是使用GICv3GICv4


6.3 转发中断到vCPU的示例


到目前为止,我们已经看了虚拟中断是如何被使能和产生的。下面就让我们看一下,将虚拟中断转发到vCPU的示例。在该例子中,我们假设一个物理外设被分配给VM,如下所示:


640.png

步骤如下:

  1. 物理外设发送中断信号到GIC
  2. GIC产生物理中断异常,可以是IRQFIQ,被路由到EL2(设置HCR_EL2.IMO/FMO标志位)。hypervisor识别外设,并确定已经分配给VM。然后,判断中断应该被转发到哪个vCPU
  3. hypervisor配置GIC,将物理中断以虚拟中断的形式转发给vCPU。然后,GIC发送vIRQvFIQ信号。但是,当在EL2上执行时,处理器会忽略掉这类虚拟中断信号。
  4. hypervisor将控制权返还给vCPU
  5. 此时,处理器处于vCPU中(EL0EL1),就可以接收来自GIC的虚拟中断。这个虚拟中断同样受制于PSTATE异常掩码的屏蔽。

该示例展示了一个物理中断,如何被转发为虚拟中断的过程。这个例子对应于在讲解Stage-2地址转换一节时的直通设备。对于虚拟外设,hypervisor能够产生虚拟中断,而无需将其连接到一个物理中断上。


6.4 中断掩码和虚拟中断


在异常模型中,我们介绍了PSTATE中的中断掩码位,PSTATE.I用于IRQPSTATE.F用于FIQ,且PSTATE.A用于SError。当在虚拟化环境中工作时,这些掩码的工作方式有些不同。

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

  • 路由物理IRQ中断到EL2
  • 使能在EL0EL1中的vIRQ中断信号的发送

此设置还会改变应用PSTATE.I掩码的方式。当在EL0EL1时,如果HCR_E2.IMO==1PSTATE.IvIRQ进行操作,而非pIRQ


7 虚拟化通用定时器


ARM架构提供了通用定时器,是每个处理器中一组标准化的定时器。通用定时器包含一组比较器,每个比较器与通用系统计数器进行比较。当比较器的值等于或小于系统计数器时,就会产生一个中断。下图中,我们可以通用定时器(橙色),由一组比较器和计数器模块组成。


640.png

下图展示了一个具有两个vCPUhypervisor的示例系统:

640.png


在示例中,我们忽略hypervisorvCPU之间执行上下文切换时花费的开销。

4ms物理时间(挂钟时间)内,每个vCPU运行了2ms。如果vCPU0T=0时设置比较器,让其3ms之后产生中断,中断会按照预期产生吗?

或者,你希望在虚拟时间(vCPU所经历的时间)2ms之后中断,还是在挂钟时间2ms之后中断?

ARM架构提供了这两种功能,具体使用依赖于虚拟化的用途。让我们看一下硬件架构是如何做到的。

运行在vCPU上的软件可以访问2个定时器:

  • EL1物理定时器
  • EL1虚拟定时器

EL1物理定时器与系统计数器产生的计数进行比较。可以使用这个定时器给出挂钟时间,即物理CPU的执行时间。

挂钟时间,英文名称为wall-clock time,也可以理解为物理CPU的执行时间。

EL1虚拟定时器与虚拟计数进行比较。虚拟计数等于物理计数减去偏移量。hypervisor在一个寄存器CNTOFF_EL2中,为当前被调度的vCPU指定偏移量。这就允许它隐藏该vCPU未被调度执行时流逝的时间。

640.png


为了阐述这个概念,我们扩展前面的示例,如下图所示:

640.png


6ms的时间周期内,每个vCPU都运行了3mshypervisor可以使用偏移量寄存器让虚拟计数仅仅表示vCPU的运行时间。或者,hypervisor可以设置偏移量为零,这意味着虚拟时间等于物理时间。

本示例中,展示的系统计数是1ms。实际上,这个频率是不现实的。我们推荐系统计数器使用1MHz50MHz之间的频率(也就是1us→20ns计数时间间隔)。


8 虚拟化主机扩展


下图展示了一个软件和异常级别对应关系的简化版本:

640.png


可以看到独立hypervisor和ARM异常级别的对应关系。hypervisor运行在EL2上,VM运行在EL0/1上。对于托管型hypervisor这种架构是有问题的。

640.png


我们知道,通常情况下,内核运行在EL1,但是虚拟化的控制操作在EL2。这意味着,Host OS内核的大部分代码位于EL1,一小部分代码运行于EL2(用于控制虚拟化)。这种设计效率不高,因为它涉及到额外的上下文切换。

想要使内核运行在EL2,需要处理运行在EL1EL2上的一些差异。但是,这些差异被限制到少数子系统中,比如早期引导阶段。

支持DynamIQ异构技术的处理器(Cortex-A55Cortex-A75Cortex-A76)支持虚拟化主机扩展(VHE)。


8.1 在EL2运行Host OS


VHEHCR_EL2寄存器的两个位进行控制:

  • E2H:控制是否使能VHE功能;
  • TGE:当使能了VHE,控制EL0Guest还是Host

下表总结了典型的设置:


执行 E2H TGE
Guest内核(EL1) 1 0
Guest应用(EL0) 1 0
Host内核(EL2) 1 1*
Host应用(EL0) 1 1

当发生异常,从VM退出,进入hypervisor时,TGE最初为0。软件必须在运行Host OS内核主要部分之前设置该位。

典型设置如下图所示:

640.png


8.2 虚拟地址空间


下图展示了在引入VHE之前,EL0/1的虚拟地址空间布局如下:


640.png

在内存管理模型中,EL0/EL1具有两个区域。习惯上,上面的区域称为内核空间,下面的区域称为用户空间。但是,从右侧的图中可以看出,EL2只有底部的一个地址空间。造成这种差异是因为,一般情况下,hypervisor不会直接托管应用程序。这意味着,hypervisor无需划分内核空间和用户空间。

分配上面的区域给内核空间,下面的区域给用户空间,仅仅是约定。ARM架构没有强制这么做。

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

为了允许EL2上有效执行Host OS,我们需要添加第二个区域和ASID的支持。使能HCR_EL2.E2H可以解决这个问题,如下图所示:


640.png

EL0中,HCR_EL2.TGE控制使用哪个虚拟地址空间:EL1空间,还是EL2空间。具体使用哪个空间依赖于应用程序运行在Host OSTGE==1),还是Guest OSTGE==0)。


8.3 重定向寄存器访问


前面我们已经知道,使能VHE会改变EL2虚拟地址空间的布局。但是,我们还有一个问题,MMU的配置。这是因为,我们的内核会访问_EL1寄存器,如TTBR0_EL1,而不是_EL2寄存器,如TTBR0_EL2

为了在EL2运行相同的二进制代码,我们需要将对EL1寄存器的访问重定向到EL2的等价寄存器上。使能E2H,就能实现这个功能。如下图所示:

640.png


但是,这种重定向给我们带来了新问题。hypervisor仍然需要访问真实的_EL1寄存器,以便实现任务切换。为了解决这个问题,一组寄存器别名被引入,后缀为_EL12_EL02。当在EL2使用时(E2H==1),访问这些别名寄存器就会访问真实的EL1寄存器,以便实现上下文切换。如下图所示:

640.png


8.4 异常


通常,HCR_EL2.IMO/FMO/AMO路由标志位控制着物理异常被路由到EL1还是EL2。当在EL0上执行(TGE==1)时,所有的物理异常路由到EL2,除非通过SCR_EL3寄存器控制路由到EL3。这种情况下,与HCR_EL2路由标志位的实际值无关。这是因为应用程序作为Host OS的子进程在执行,而不是作为Guest OS。因此,异常应该被路由到运行在EL2上的Host OS中。


9 嵌套虚拟化


理论上,hypervisor还可以运行在一个VM之中。这个被称为嵌套虚拟化


640.png

我们称第一个hypervisorHost Hypervisor,在VM内部的hypervisorGuest Hypervisor

ARMv8.3-A扩展之前,就可以通过在EL0中运行Guest Hypervisor而实现在VM中运行一个Guest Hypervisor。但是,这要求大量的软件模拟,导致比较差的性能。通过ARMv8.3-A扩展的特性,可以在EL1上运行Guest Hypervisor。添加了ARMv8.4-A扩展之后,这个过程更加有效率,尽管仍然需要Host Hypervisor中的一些操作。


9.1 Guest Hypervisor访问虚拟化控制寄存器


我们不想Guest Hypervisor直接访问虚拟化控制寄存器。因为直接访问可能潜在允许VM破坏沙箱,或获取主机平台的信息。这种潜在的问题与我们前面讨论陷入和模拟一节时面临的问题一样。

Guest Hypervisor运行在EL1HCR_EL2中新添加的标志位允许Host Hypervisor捕获Guest Hypervisor对虚拟化控制寄存器的访问:

  • HCR_EL2.NV:硬件嵌套虚拟化总开关
  • HCR_EL2.NV1:使能一组额外的陷入(trap)
  • HCR_EL2.NV2:使能对内存的重定向
  • VNCR_EL2NV2==1):指向内存中的一个结构

ARMv8.3-A添加了NVNV1控制位。从EL1访问_EL2寄存器,通常是未定义的,这种访问会造成到EL1的异常。而NVNV1控制位则将这种异常陷入到EL2。这就允许运行在EL1上的Guest Hypervisor,使用运行在EL2上的Host Hypervisor模拟某些操作。NV标志位还能捕获EL1ERET指令。

下图展示了Guest Hypervisor设置和进入虚拟机的过程:


640.png


  1. Guest Hypervisor访问_EL2寄存器会陷入到EL2Host Hypervisor会记录Guest Hypervisor的配置信息。
  2. Guest Hypervisor尝试进入它的Guest VMGuestGuest VM),这种尝试就是调用ERET指令,而ERET指令会被EL2捕获。
  3. Host Hypervisor检索GuestGuest的配置,并加载该配置信息到合适的寄存器中。然后,Host Hypervisor清除NV标志位,并进入GuestGuest执行。

这种方法的问题是,Guest Hypervisor每次访问EL2寄存器都会陷入。在两个vCPUVM之间执行任务切换时,需要访问许多寄存器,导致大量的陷入异常。而异常进入和退出会带来开销。

一个更好的方法是获取EL2寄存器的配置,只有在调用ERET指令时陷入到Host Hypervisor。引入ARMv8.4-A扩展后,这成为可能。当设置了NV2标志位后,EL1访问_EL2寄存器被重定向到内存中的一个数据结构。Guest Hypervisor可以根据需要读写这些寄存器,而无需任何陷入。当然,调用ERET指令仍然会陷入到EL2,此时,Host Hypervisor重新检索内存中的配置信息。后面的过程与前面的方法一致,如下图所示:


640.png


  1. Guest Hypervisor访问_EL2寄存器被重定向到内存中的一个数据结构。数据结构的位置由Host Hypervisor使用VNCR_EL2寄存器指定。
  2. Guest Hypervisor调用ERET指令,尝试进入它的Guest VMGuestGuest VM)。ERET指令被EL2捕获。
  3. Host Hypervisor检索GuestGuest的配置,并加载该配置信息到合适的寄存器中。然后,Host Hypervisor清除NV标志位,并进入GuestGuest执行。

这种方法的优点是陷入更少,因此,进入Host Hypervisor的次数也更少。


10 安全空间的虚拟化


虚拟化是在ARMv7-A架构引入的。那时的Hyp模式等价于AArch32状态的EL2,只有在非安全状态可用。ARMv8.4-A扩展添加了对安全EL2的支持,是一个可选配置。

如果处理器支持安全EL2,需要在EL3中使能SCR_EL3.EEL2标志位。设置该标志位允许进入EL2,且使能安全状态下的虚拟化。

在安全虚拟化可用之前,EL3通常运行安全状态切换软件和平台固件。这是因为我们想要尽量减少EL3 中的软件数量,让EL3更容易安全。安全虚拟化允许我们将平台固件移动到EL1。虚拟化为平台固件可信内核提供单独的安全分区。下图说明了这一点:

640.png


10.1 Secure EL2和两个IPA空间


ARM架构定义了两个物理地址空间:SecureNon-secure。在非安全状态中,VMStage-1地址转换的输出总是非安全的。因此,Stage-2地址转换只有一个IPA空间需要处理。

安全状态下,VMStage-1地址转换的输出可以是安全地址,也可以是非安全地址。地址转换表中描述符中的NS标志位控制输出是安全,还是非安全地址空间。这意味着对于Stage-2地址转换有两个IPA空间需要处理,如下图所示:

640.png


Stage-1页表不同,Stage-2页表项中没有NS位。对于特定的IPA 空间,所有转换都可以产生安全物理地址非安全物理地址。这种转换由一个寄存器位控制。通常,非安全IPA转换为非安全PA,而安全IPA转换为安全PA


11 虚拟化的成本


虚拟化的成本是当hypervisor需要为VM服务时,需要在VMhypervisor之间切换时花费的时间。在ARM系统中,这种成本的最低限是:

  • 3164位通用目的寄存器(X0→X30
  • 32128浮点/SIMD寄存器(V0→V31
  • 2个堆栈指针寄存器(SP_EL0SP_EL1

通过LDPSTP指令,hypervisor只需要32个指令保存和恢复这些寄存器。

真正的虚拟化性能损失依赖于硬件平台和hypervisor的设计。


12 小测验


  • 问:Type-1hypervisorType-2型的区别是什么?
  • 答:Type-2型运行在Host OS之上,Type-1型没有Host OS
  • 问:安全状态和非安全状态有多少个IPA空间?
  • 答:安全状态有2个IPA空间:安全非安全。非安全状态有一个IPA空间。
  • 问:在哪个异常级别中可以使用虚拟中断?
  • 答:虚拟中断只有在EL0EL1中执行,并且只有设置HCR_EL2中相应的路由标志位才能启用。
  • 问:SMMU是什么?如何使用SMMU进行虚拟化?
  • 答:SMMU是系统MMU,为非处理器的主控制器提供地址翻译服务。在虚拟化中,SMMU可以给主控制器(如DMA控制器)和VM一样的内存视角。
  • 问:HCR_EL2.EH2标志位如何影响MSR TTBRO_EL1,x0EL2上的执行?
  • 答:当E2H==0,该指令写TTBR0_EL1寄存器;当E2H==1,写操作被重定向到TTBR0_EL2
  • 问:VMID是什么?它的作用是什么?
  • 答:VMID是虚拟机标识符。用来标记VMTLB项,以便来自不同VMTLB项可以在TLB中共存。
  • 问:陷入(Trap)是什么?它如何用于虚拟化?
  • 答:陷入可以造成合法操作触发异常,并将该操作陷入到更高特权级的软件上。在虚拟化中,陷入允许hypervisor检测某个操作何时执行,然后模拟这些操作。


13 其它参考文章


与本文相关的一些参考文章:

  • 内存管理
  • 异常模型
  • ARM虚拟化:性能和架构的意义:关于基于ARM架构的系统虚拟化成本的背景读物
  • Arm community:ARM官方论坛,可以提问问题,查找文章和博客

下面是一些其它主题的参考内容:


13.1 虚拟化的介绍


  • Xen项目
  • KVM的通用知识


13.2 虚拟化概念


  • GICv3/v4软件概述
  • Virtio的背景知识


14 接下来的计划


打算开发一个轻量级的hypervisor,只实现对VM的分区隔离。hypervisor本身不参与主动调度VM的执行。计划如下:

  1. 在QEMU模拟器上实现一个hypervisor,支持裸机程序(EL1)的运行
  2. 在QEMU模拟器上实现一个hypervisor,支持Linux的运行
  3. 实现两个虚拟机之间的通信
  4. 选择一个硬件平台运行,初步选择RK3399
  5. 使用Rust语言重写该hypervisor

另外,读者也可以按照Spawn a Linux virtual machine on Arm using QEMU (KVM) 这篇文章,基于ARM模拟平台建立开源的XENKVMhypervisor

相关文章
|
Cloud Native 虚拟化 云计算
《Docker基础知识解析:容器与虚拟化的区别与优势,选择最佳方案优化云计算应用》
《Docker基础知识解析:容器与虚拟化的区别与优势,选择最佳方案优化云计算应用》
425 0
|
存储 持续交付 虚拟化
Docker 基础知识解析:容器与虚拟化的区别与优势
Docker 基础知识解析:容器与虚拟化的区别与优势
584 0
|
Go 虚拟化 云计算
Docker 基础知识解析:容器与传统虚拟化对比:资源利用、启动时间、隔离性和部署效率
Docker 基础知识解析:容器与传统虚拟化对比:资源利用、启动时间、隔离性和部署效率
412 0
|
存储 负载均衡 监控
六、分享优秀的Armv8 虚拟化技术地址
六、分享优秀的Armv8 虚拟化技术地址
207 0
|
存储 缓存 负载均衡
|
Linux 虚拟化 KVM
虚拟化学习笔记-基础知识
版权声明:转载请注明出处:http://blog.csdn.net/dajitui2024 https://blog.csdn.net/dajitui2024/article/details/79396678 ...
1393 0
|
数据可视化 Linux 虚拟化
《循序渐进Linux(第2版) 基础知识 服务器搭建 系统管理 性能调优 虚拟化与集群应用》——4.7 文本编辑工具vi
vi是Linux下标准的文本编辑程序,也是Linux系统命令行下最经常使用的文本文件可视化编辑器,类似于DOS命令edit。那么什么是可视化呢?其实就是让用户在编辑文本文件的时候能够看到它们。这听起来似乎很普通,但是在命令行的字符界面下,可视化编辑确实起了很大的作用。
2105 0
|
3月前
|
存储 Linux 调度
OpenStack如何支持虚拟化技术?
【8月更文挑战第21天】
180 0