今天来看看虚拟中断。
在一个非虚拟化的系统中,操作系统可以直接访问GIC的寄存器,并且处理GIC的物理中断接口(physical interrupt interface)。
但是在一个虚拟化的系统中,不是这样。Guest OS并不知道它运行在虚拟系统中,其接收的中断来自GIC的虚拟中断接口(virtual interrupt interface),但是OS本身并不知道;实际上是hypervisor接管了GIC的寄存器访问和物理中断接口,且hypervisor要负责产生虚拟中断给Guest OS。
还有另外一种方式产生虚拟中断,就是通过配置HCR_EL2,由内部CPU核产生。在HCR_EL2里面有三个bit用来产生虚拟中断:
- VI:设置该bit产生一个vIRQ
- VF:设置该bit产生一个vFIQ
- VSE:设置该bit产生一个vSerror
设置这些bit位就相当于中断控制器向vCPU发送中断信号。生成的虚拟中断受PSTATE掩蔽的影响,就像常规中断一样。这种机制使用起来很简单,但缺点是hypervisor需要模拟中断控制器的操作。换言之,软件中的trap和emulate操作的开销比较大,影响性能。
通过GIC就能避免上面的问题。GIC的物理CPU接口和虚拟CPU接口是等同的,区别只是一个发送物理中断信号,另一个发送虚拟中断信号。
来看一个例子:
- 外部中断到达GIC;
- GIC产生一个物理IRQ给CPU;
- CPU转换到EL2,hypervisor通过物理CPU接口读取中断;
- Hypervisor写GIC的List寄存器产生虚拟中断;
- GIC通过vIRQ发送中断给CPU;
- CPU从EL2返回到EL1或者EL0;
- Guest OS读取中断,CPU执行中断处理程序。
在GICv4中,增加了对虚拟机直接注入虚拟中断的支持。支持GICv4的IP是GIC-700.目前的虚拟中断直接注入支持产生LPI,也就是说系统中要有ITS组件。
- Hypervisor会事先通过ITS命令配置ITS,重新映射虚拟core和物理core,虚拟中断和物理中断。
- 当ITS接到消息中断后,先要查表得到虚拟的INTID和虚拟PE,然后发给相应的redistributor。
- Redistributor会去检查内部的寄存器,查看vPE是否在自己这边注册过。
- 如果注册过,发虚拟中断给vPE;
- 如果没有,发中断给hypervisor。
GIC-700也支持软件通过将vPE和SGI-INTID写入GITS_SGIR寄存器的方式来直接注入SGI。对于PPI和SPI的直接注入,目前尚不支持。