在ARM体系结构中,处理器内部有通用计时器,通用计时器包含一组比较器,用来与系统计数器进行比较,一旦通用计时器的值小于等于系统计数器时便会产生时钟中断。
大家看到这里是不是想起了前面讲GIC时提到的PPI(private peripheral interrupt)。系统计数器往往会放在always-on的电源域内,要求输入时钟不可间断且频率不变。
看下图,如果一个hypervisor之上虚拟了两个vCPU,那么,物理世界中经历了4ms的时间(wall time),但每个vCPU实际运行了2ms时间(virtual time)。
如果你设置了vCPU0在2ms以后产生中断,在物理时间中就是3ms的时刻vCPU0才真正的运行完2ms的时间。换句话说,对于vCPU0的2ms时间中断,你是希望发生在物理时间中2ms时刻处还是3ms时刻处呢?
ARM体系结构同时支持上述两种设置,这取决于使用何种虚拟化方案。运行在vCPU上的软件可以访问下面两种时钟:
- EL1物理计时器(physical timer)
- EL1虚拟计时器(virtual timer)
EL1物理计时器会与系统计数器模块直接比较,使用的是物理世界的时间。
而与EL1虚拟计时器比较的是虚拟计数器。虚拟计数器是在物理计数器的基础上减去一个偏移。Hypervisor负责为当前调度运行的vCPU指定对应的偏移寄存器。这样,vCPU0没有运行的物理时间就会被减去。
看下面的时序图会更清晰,蓝色代表vCPU0,绿色代表vCPU1。在整个的6ms时间内,vCPU0和vCPU1各运行了3ms的时间。
Hypervisor可以通过偏移寄存器显示虚拟计数,该计数仅显示vCPU运行的时间。或者虚拟机监控程序可以将偏移量保持在0,这意味着虚拟时间与物理时间相同。
理论上,hypervisor可以运行在VM中,就是嵌套虚拟化。第一层的hypervisor称为Host Hypervisor,VM里面的hypervisor称为Guest Hypervisor。
在Armv8.3-A之前,VM的Guest Hypervisor可以运行在EL0。然而,这需要大量的软件仿真,而且实现起来很复杂,导致性能低下。
在Armv8.3-A,Guest Hypervisor可以运行在EL1。到了Armv8.4-A,增加了一些特性,这个过程的效率变高了一些,但是仍然需要Host Hypervisor参与做一些额外的工作。不再赘述了。
虚拟化是在Armv7-A中引入的,Hyp模式(相当于AArch32中的EL2)仅在非安全状态下可用。在Armv8.4-A中,作为可选功能添加了对处于安全状态的EL2的支持。
在安全虚拟化可用之前,EL3通常用于托管安全状态切换软件和平台固件的混合。这是因为我们希望尽量减少EL3中的软件数量,从而使EL3更容易安全。安全虚拟化允许将平台固件移动到EL1中。虚拟化为平台固件和可信内核提供了单独的安全分区。
ARM体系结构定义了两个物理地址空间:安全和非安全。在非安全状态下,虚拟机(VM)的stage 1转换的输出始终是非安全的。
因此,有一个中间物理地址(IPA)空间供satge 2处理。
在安全状态下,VM的stage 1转换可以输出安全和非安全地址。转换表描述符中的NS位控制是否输出安全或非安全地址空间。
如下图所示,这意味着stage 2有两个IPA空间,安全和非安全。
与stage 1表格不同,stage 2表格条目中没有NS位。
对于特定IPA空间,所有转换都会产生安全物理地址或非安全物理地址。
此转换由寄存器位控制。通常,非安全IPA转换为非安全PAs,安全IPA转换为安全PAs。
老秦谈芯