我们在 该文章 中分析了 PL2 的异常,提出了以下问题
什么虚拟化相关的情况下会进入 host_PL1
TODO
什么虚拟化相关的情况下会进入 host_PL2
1. 虚拟机开启时,ioctl KVM_RUN 进入 hyp_hvc
2. 中断应该会进入 hyp_irq
3. 内存异常应该会进入 hyp_dabt // TODO
什么虚拟化相关的情况下会进入 guest_PL1
1. 优化后的中断应该会进入 vector_irq // TODO
2. 优化后的内存访问异常应该会进入 vector_dabt // TODO
————————————————
版权声明:本文为CSDN博主「__pop_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011011827/article/details/120470296
现在有了答案:
guest间的核间中断,外设(都是qemu和kvm仿真的)的中断发生时,会进行如下动作
1. 进入 host_PL2 hyp_irq
2. host_PL2 hyp_irq 中 分发服务器开始动作(对应的 CPU的GIC hypervisor控制接口上的列表寄存器(list register)进行编程)
3. 进入 guest_PL1 vector_irq
4. guest_PL1 vector_irq 中 做 中断处理程序
5. guest_PL1 vector_irq 中 确认 ACK和EOI
6. 进入 guest 正常运行时
本篇文章着重从 irq 角度 分析 , 会牵涉到 host_PL2 的 hyp_irq 和 guest_PL1 的 vector_irq
- 实体机上的 GIC
ARM 有一个 GIC
GIC的作用
将中断从设备转发到CPU上,CPU通过查询GIC来探测该中断的来源。
用于生成处理器间中断(IPI)从一个CPU核到另一个CPU核。
GIC分为
分发服务器
一个系统只有一个
通过内存映射接口(MMIO)来进行访问的
被用来配置GIC,例如,配置中断的CPU核与一个中断进行关联,禁止或者使能系统中的所有中断,发送IPI到另外一个CPU核。
CPU接口
一个cpu对应一个
通过内存映射接口(MMIO)来进行访问的
用于确认(ACK)和发出中断接口信号(EOI)。
CPU 对 中断的处理流程 : 当一个CPU核接收到一个中断时
CPU:
将读取GIC的CPU接口上的一个特殊寄存器,该寄存器将标记中断,并返回中断数量。
GIC:
在CPU将从ACK寄存器中读取到的值写入CPU接口的EOI寄存器之前,中断不会再次被转发到CPU中。
- ARM 针对中断虚拟化的探讨
// 中断方案的探讨
中断可被配置为使CPU核陷入HOST的HYP模式(PL2)或者guest的svc模式(PL1) // 注意 : PL2也有svc
guest_PL1
将所有中断捕获到内核模式中,并让其被在内核模式下运行的操作系统软件直接处理是很高效的,
但是其不能再虚拟机上下文中工作,因为hypervisor失去对硬件的控制
host_PL2
将所有中断捕获到HYP模式可确保hypervisor保留控制权,但是需要在软件中模拟虚拟中断,以便向虚拟机发出事件信号。
这种方式就很麻烦且开销很大,因为处理中断的每一步和虚拟中断的处理,例如ACK和EOI操作都必须通过hypervisor来完成。
开销
1. 进入 host_PL2 的 hyp_irq
2. host_PL2 的 hyp_irq : 分发服务器 将 陷入 guest_PL1 的 vector_irq
3. guest_PL1 的 vector_irq:做处理
4. guest_PL1 的 vector_irq :进入 host_PL2的hyp_irq , 做 ACK和EOI
5. host_PL2的hyp_irq : 返回 guest_PL1 的 vector_irq
6. guest_PL1 的 vector_irq : 返回 guest_PLx 的 正常运行时
现有问题:
必须满足 : 让 host_PL2 参与 中断, 且 开销要 相比现在的方案开销(现在是一次中断,两次host_PL2进入)要 降低
解决方案:
VGIC(一次中断,一次host_PL2进入)
- ARM 针对虚拟化对 GIC的扩展 VGIC
VGIC方案 : GIC v2.0 以虚拟化GCI(VGIC)的形式提供了中断硬件虚拟化的支持
不需要 在 hypervisor软件中进行 模拟来 创建 虚拟中断(而是直接写寄存器)
不需要 再次陷入 hypervisor 做 ACK和EOI(而是直接在guest_PL1直接做)
VGIC分为
分发服务器
一个系统只有一个,由软件模拟
虚拟机对分发服务器的所有访问仍然必须捕获到hypervisor中
被用来配置GIC,例如,配置中断的CPU核与一个中断进行关联,禁止或者使能系统中的所有中断,发送IPI到另外一个CPU核。
CPU接口
一个cpu对应一个,由硬件实现
通过 CPU的GIC hypervisor控制接口上的列表寄存器 来进行访问的,访问时不会陷入 hypervisor
用于确认(ACK)和发出中断接口信号(EOI)
VGIC的处理方式
1. 进入 host_PL2 的 hyp_irq
2. host_PL2 的 hyp_irq : 分发服务器 将 陷入 guest_PL1 的 vector_irq // 这里通过 VGIC hypervisor控制接口中写入特殊寄存器(list registers) 加速
3. guest_PL1 的 vector_irq:做处理
4. guest_PL1 的 vector_irq : 做 ACK和EOI // 这里直接在 guest_PL1 的 vector_irq 做 ACK 和 EOI 加速
5. guest_PL1 的 vector_irq : 返回 guest_PLx 的 正常运行时
CPU 对 中断的处理流程,当一个虚拟CPU发送了一个虚拟IPI到另外一个虚拟CPU
CPU:
1.陷入host的PL2 hypervisor
2.模拟软件中的分发服务器访问并对接收到的CPU的GIC hypervisor控制接口上的列表寄存器(list register)进行编程
3.陷入guest 的 guest_PL1
4.在guest_PL1让guest操作系统 确认 ACK和EOI
CPU 对 中断的处理流程,当一个CPU核接收到一个中断时 // 模拟虚拟设备通常通过软阿健API将虚拟中断引入到hypervisor
CPU:
1. 陷入 host的 hypervisor
2. 在host_PL2 利用 虚拟中断VGIC将模拟设备的虚拟中断号写入到列表寄存器(list register)中。
3. 陷入guest 的 的内核模式
4. 在guest_PL1让guest操作系统 确认 ACK和EOI
VGIC 其他细节
虚拟分发服务器
会向用户空间暴露一个接口 // 因此用户空间中的模拟设备可以向虚拟分发服务器发出虚拟中断
并向虚拟机暴露一个与物理GIC分发服务器相同的MMIO接口。
是否切换
当将一个虚拟机调度到一个物理核上运行时,必须切换list寄存器的上下文
但是在虚拟机和hypervisor之间进行切换时,List寄存器的上下文则不需切换。
一旦系统hypervisor在切换到虚拟机时向list寄存器写入了虚拟中断,那么当切换回hypervisor时,它也必须重新读取list寄存器。