第六篇讨论了 RISC-V KVM 的 trap/exit 处理路径。本篇进入中断:当一个中断到达 host 时,Linux KVM/RISC-V 如何判断它是否、何时、以及怎样投递给 Guest Linux?
1. 为什么中断虚拟化很难
CPU 和内存虚拟化解决的是执行和地址空间问题。
中断虚拟化解决的是事件投递问题。
Guest Linux 需要看到自己的中断:
- timer interrupt
- IPI
- virtio device interrupt
- UART interrupt
- external interrupt
但真实中断首先属于 host。
Host 需要决定:
- 这个中断是不是给某个 guest 的?
- guest 当前能不能接收?
- 目标 vCPU 是哪个?
- vCPU 正在运行还是被调度出去了?
- 是否需要触发一次 guest exit 或 host wakeup?
所以中断虚拟化既是架构问题,也是调度问题。
2. RISC-V 中断模型的几个基本对象
RISC-V 中断可以先粗略分成几类:
- software interrupt
- timer interrupt
- external interrupt
在传统 RISC-V 平台上,经常会看到:
- CLINT:core-local interruptor,常用于 timer 和 software interrupt
- PLIC:platform-level interrupt controller,用于外部中断
在更新的中断架构中,还会看到:
- AIA:Advanced Interrupt Architecture
- IMSIC:Incoming MSI Controller
- APLIC:Advanced Platform-Level Interrupt Controller
不同平台和 QEMU 配置可能使用不同模型。
本篇先建立概念,不把每个寄存器展开。
3. Guest 看到的中断不是 Host 原样转交
Guest Linux 看到的 interrupt controller 是 QEMU/KVM 为它构造的虚拟硬件。
这意味着:
real host interrupt | v Host Linux interrupt handling | v KVM/QEMU decide guest delivery | v virtual interrupt pending state | v Guest Linux interrupt handlerGuest 并不知道背后真实硬件如何投递中断。
它只需要看到符合 RISC-V 平台约定的中断行为。
4. virtual interrupt pending state
中断不是一个函数调用。
如果 guest 当前关中断,或者 vCPU 没有运行,中断不能简单地“立刻执行”。
KVM 需要维护虚拟中断状态,例如:
- 哪些 interrupt pending
- 哪些 interrupt enabled
- 目标 vCPU 是谁
- 是否需要唤醒 vCPU thread
- 是否需要在下一次 guest entry 前注入
可以简化为:
event happens | v mark virtual interrupt pending | v when guest is ready | v inject interrupt into Guest Linux这就是 virtual interrupt injection 的基本直觉。
5. timer interrupt
Timer 是最重要的 guest 中断之一。
Guest Linux 依赖 timer 做调度和时间管理。
Guest 设置 timer 的路径可能是:
Guest Linux | | SBI set_timer v KVM handles SBI timer call | | program host timer v host timer fires | | mark guest timer interrupt pending v Guest receives virtual timer interrupt这里有两个转换。
第一,guest 的 timer deadline 要转换成 host 能理解的 timer 事件。
第二,host timer 到期后,要转换成 guest 可见的 virtual timer interrupt。
Timer 虚拟化的质量会直接影响 guest scheduler 的行为。
6. IPI 虚拟化
IPI 是 inter-processor interrupt。
Guest 多核系统中,一个 vCPU 可能需要向另一个 vCPU 发送 IPI。
例如:
- TLB shootdown
- reschedule
- wakeup
- stop CPU
路径大致是:
Guest vCPU0 sends IPI | | SBI or interrupt controller path v KVM records target vCPU interrupt | v wake or mark vCPU1 pending | v Guest vCPU1 receives virtual IPI这里的难点是目标 vCPU 可能并不在运行。
它可能在 host 上睡眠,也可能正在另一个 pCPU 上运行。
KVM 需要和 host scheduler 协作,确保虚拟 IPI 最终能被目标 vCPU 看见。
7. external interrupt 与 virtio
virtio 设备完成请求后,通常需要通知 guest。
例如 virtio-blk 完成一次读请求。
简化路径:
host I/O completes | v QEMU or vhost marks virtqueue used | v virtual device interrupt pending | v KVM injects external interrupt | v Guest virtio driver handles completion如果设备模型在 QEMU 用户态,QEMU 可能需要通过 irqfd、eventfd 或 KVM API 通知 KVM。
如果数据面走 vhost,部分路径可能在内核中完成,减少 QEMU 参与。
这就是中断虚拟化和 I/O 虚拟化交叉的地方。
8. PLIC 虚拟化
PLIC 是传统 RISC-V 外部中断控制器。
Guest 可能看到一个虚拟 PLIC。
它需要支持类似的语义:
- interrupt source
- priority
- pending
- enable
- threshold
- claim/complete
如果 PLIC 由 QEMU 设备模型模拟,那么 guest 对 PLIC MMIO 寄存器的访问可能会返回 QEMU。
Guest PLIC MMIO access | v KVM MMIO exit | v QEMU virtual PLIC model这种路径语义清楚,但频繁 MMIO 会有开销。
9. AIA 与 IMSIC 为什么重要
AIA 是 RISC-V 较新的高级中断架构。
IMSIC 提供更适合 MSI 和虚拟化的中断投递模型。
从虚拟化角度看,AIA/IMSIC 的价值在于:
- 更适合多核和 MSI 设备
- 更容易做中断直投或硬件辅助
- 可以减少部分中断路径的软件开销
- 对高性能虚拟化更友好
不需要一开始就记住所有细节。
先建立方向:
PLIC 更像传统平台级中断控制器,AIA/IMSIC 更面向现代多核和虚拟化场景。
后续如果系列深入设备直通和高性能中断,可以单独写 AIA。
10. 中断注入与 guest entry
KVM 往往会在进入 guest 前检查是否有 pending virtual interrupt。
如果有,并且 guest 当前允许接收,KVM 会准备相应状态,让 guest 在恢复执行后进入中断处理。
简化流程:
before guest entry | | check pending interrupt | check guest interrupt enable v prepare injection state | v enter guest | v Guest trap handler receives interrupt这说明中断注入和 vCPU run loop 紧密相关。
不是只有“中断发生时”才处理,中断状态也会在 guest entry/exit 边界被维护。
11. posted interrupt 的直觉
在高性能虚拟化里,一个重要优化方向是减少中断导致的 VM exit。
posted interrupt 的直觉是:
如果硬件能把某些中断直接投递到正在运行的 guest,就可以减少 host 软件介入。
不同架构具体机制不同。
在 RISC-V 场景下,AIA/IMSIC 等能力会影响未来中断虚拟化效率。
本系列后续如果写设备直通和高性能 I/O,可以把 posted interrupt、MSI、IOMMU 放在一起讨论。
12. 中断与 vCPU 调度
中断虚拟化离不开 vCPU 调度。
如果目标 vCPU 正在运行,KVM 可以尝试尽快注入。
如果目标 vCPU 睡眠,KVM 可能需要唤醒对应 QEMU vCPU thread。
如果目标 vCPU 被 host 抢占,中断延迟会受 host 调度影响。
所以 guest 看到的 interrupt latency 实际上受多层因素影响:
- host scheduler
- vCPU placement
- CPU overcommit
- interrupt controller model
- QEMU/KVM exit path
- device backend
这也是为什么虚拟机实时性和低延迟调优非常复杂。
13. 源码阅读入口
RISC-V KVM 中断路径可以先看:
arch/riscv/kvm/vcpu.carch/riscv/kvm/vcpu_timer.carch/riscv/kvm/vcpu_sbi.carch/riscv/kvm/aia.c,如果内核版本包含相关实现arch/riscv/include/asm/kvm_host.h- QEMU 的
hw/intc/和hw/riscv/virt.c
阅读时可以问:
- guest timer interrupt 在哪里被设置 pending?
- IPI 如何找到目标 vCPU?
- guest external interrupt 由谁注入?
- PLIC 或 AIA 是 QEMU 模拟还是 KVM 加速?
- vCPU entry 前如何检查 interrupt state?
- interrupt pending state 如何和 guest CSR 对应?
14. 本篇小结
这一篇把 RISC-V 虚拟化中的中断拆成几条路径。
第一,timer interrupt 通常与 SBI 和 host timer 相关。
第二,IPI 需要 KVM 管理 vCPU 之间的虚拟中断投递。
第三,virtio 等设备中断常常跨越 QEMU、vhost、KVM 和 guest driver。
第四,PLIC、AIA、IMSIC 决定了外部中断虚拟化的架构基础。
第五,中断延迟不只取决于硬件,还取决于 vCPU 调度和 exit 路径。
可以把本篇压缩成一句话:
RISC-V 中断虚拟化的核心不是简单转发中断,而是在 host 调度、KVM 状态机和 guest interrupt model 之间维护一个可信的事件投递系统。
15. 下一篇预告:SBI 在 RISC-V Guest 中如何被虚拟化
下一篇专门看 SBI。
会讨论:
- SBI 为什么是 RISC-V 软件栈的关键接口
- Guest Linux 常用哪些 SBI extension
- timer、IPI、HSM、system reset 的虚拟化路径
- KVM 如何 dispatch SBI call
- 哪些 SBI call 可以在 KVM 处理
- 哪些可能需要 QEMU 或 firmware 参与