下图呈现了一个简化的软件栈和异常级别:
你可以看到一个独立的hypervisor是如何映射到ARM异常级别。hypervisor运行在EL2而虚拟机运行在EL0/1。这种情况在托管hypervisor上存在问题,如下图所示:
通常,内核运行在EL1,但虚拟控制在EL2。这意味着大多数host OS运行在EL1,通过EL2的stub代码来访问虚拟化控制。这种安排效率低下,因为它可能涉及增加的上下文切换。
内核需要处理运行在EL1和EL2的不同,但这被严格要求在一些子系统上,比如早期的启动。
NOTE: Cortex-A75/Cortex-A76支持VHE。
HCR_EL2的两位控制VHE。这些位总结如下:
下面表总结了典型设置:
从虚拟机退出到hypervisor的异常,TGE初始化为0。软件在运行host内核之前设置该位。
你可以看到这些典型设置如下图所示:
下图显示了在VHE引入前EL0/EL1的虚拟地址空间的布局:
如在内存管理中所讨论,EL0/1有两个区域。上面区域是内核空间,下面区域是用户空间。但是,EL2仅有一个位于下面区域。通常不同点为hypervisor不会host应用。这意味着hypervisor不需要在内核空间和用户空间切分。
NOTE: 内核空间的分配在上面区域,而用户空间在下面区域。它并不是ARM架构强制要求的。
EL0/1虚拟地址空间也支持ASID,但EL2不支持。这是因为hypervisor通常不host应用。
为了允许host OS可有效的执行在EL2上,我们需要增加第二区域和ASID支持。设置HCR_EL2.E2H可以解决这些问题,如下图所示:
在EL0中,HCR_EL2.TGE控制使用哪个地址空间:或EL1空间或EL2空间。哪个空间被使用依赖于应用运行在host OS(TGE=1)还是guest OS(TGE=0)。
我们在虚拟化通用定时器章节使用VHE改变EL2虚拟地址空间的布局。但是,我们仍对配置MMU存在问题。这是因为内核将尝试访问EL1寄存器,像TTBR0_EL1而不是EL2寄存器像TTBR0_EL2。
为了在EL2上执行相同的二进制,我们需要重定向从EL1寄存器到EL2。设置E2H将做该操作,因此访问EL1系统寄存器将被重定向到EL2。重定向如下图所示:
但是,该重定向给我们留下新的问题。hypervisor仍需要访问真实的EL1寄存器,因此它实现上下文切换。为解决此问题,新的一组寄存器EL12和EL02被引入。当在EL2使用E2H=1时这访问EL1寄存器来上下文切换。你可以看如下图:
通常HCR_EL2.IMO/FMO/AMO位控制是否物理异常被路由到EL1或EL2。当执行在EL0且TGE=1时,所有物理异常都路由到EL2,若它们没有被SCR_EL3路由到EL3。这是这种情况无论HCR_EL2路由位的实际值。这是因为应用作为host OS的子任务,而不是guest OS。因此任何异常应该被路由到运行到EL2的host OS。