1661 字
8 分钟
中断处理的全流程及状态转换
2025-09-10
无标签

好的,这是一个非常具体且深入的技术问题。在 ARM 64 (AArch 64) 架构下,这个流程严重依赖于 ARM 的虚拟化扩展和 GIC(通用中断控制器)的虚拟化支持。

整个过程可以分解为几个关键的状态和阶段。我们从虚拟机正在运行的稳定状态开始。

基础背景:ARM 64 虚拟化环境#

  • 异常级别 (Exception Levels, EL):
    • EL 0: 用户空间 (Guest 和 Host 都在用)。
    • EL 1: 操作系统内核空间 (Guest OS 内核运行在此)。
    • EL 2: Hypervisor 模式 (KVM 本身的代码运行在此)。
  • GIC (Generic Interrupt Controller): ARM 的中断控制器。现代版本(GICv 3 及以上)包含强大的虚拟化扩展 (VGIC),这是实现高性能中断虚拟化的硬件基础。
  • 状态前提: KVM (在 EL 2) 已经配置好 CPU 和 GIC,使得大部分物理中断在发生时,会直接触发 CPU 从 Guest 模式 (EL 1) 陷入 (Trap) 到 Hypervisor 模式 (EL 2),而不是直接打扰到 Guest OS。

中断处理的全流程及状态转换#

状态一: 虚拟机正常运行 (Guest Running in EL 1)#

  • CPU 状态: CPU 处于“非主机模式 (Non-host mode)”,正在 EL 1 执行 Guest OS 的内核代码或在 EL 0 执行 Guest 的用户程序。
  • KVM 状态: KVM 处于“休眠”状态,它已将控制权交给 vCPU,自身不消耗 CPU 时间。
  • GIC 状态: 物理 GIC 被 KVM 配置,将发往虚拟机的物理中断路由配置为直接触发到 EL 2 的异常。Guest OS 看到的是一个虚拟 GIC CPU 接口 (Virtual CPU Interface),它认为自己正在和真实的硬件交互。

步骤 1: 物理中断产生 (Physical IRQ Occurs)#

一个物理设备(例如,主机网卡收到一个指定给该虚拟机的网络包)完成了一项操作,通过物理线路向 GIC 的**分发器 (Distributor)**发送了一个中断信号。


步骤 2: 中断陷入 Hypervisor (Trap to EL 2)#

  1. GIC 路由: GIC 的物理硬件根据 KVM 的配置,将这个中断信号路由给目标 CPU。
  2. 触发异常: 由于 CPU 当前在 Guest 模式 (EL 1),这个中断信号不会被 Guest OS“看到”,而是会触发一次硬件异常,强制 CPU 从 EL 1 陷入 (Trap) 到 EL 2。
  3. 硬件保存状态: CPU 硬件会自动保存 Guest OS 的上下文(比如程序计数器 ELR_EL1 和处理器状态 SPSR_EL1 会被存入到 EL 2 的特定寄存器 ELR_EL2SPSR_EL2 中)。这确保了将来可以精确地返回到 Guest被中断的地方。

状态二: KVM 被唤醒并处理中断 (KVM Active in EL 2)#

  • CPU 状态: CPU 现在处于“主机模式 (Host mode)”,在 EL 2 级别上开始执行 KVM 预先注册好的异常处理代码。这就是 ARM 64 架构下的“VM Exit”。
  • KVM 动作:
    1. 识别中断: KVM 代码首先会查询物理 GIC 的寄存器,搞清楚是哪个物理中断发生了(中断号是多少)。
    2. 处理和决策:
      • 如果这是一个透传设备 (Passthrough device) 的中断,KVM 会查询一个映射表,找到它对应应该注入给 Guest 的虚拟中断号 (vIRQ)。
      • 如果这是一个**模拟设备 (Emulated device, e.g., virtio)**的中断,这个物理中断可能是发给 Host OS 的(例如一个 TAP 网络设备)。Host OS 的驱动处理完数据后,会通知用户空间的 QEMU 进程。QEMU 随后会通过 ioctl 系统调用请求 KVM:“请帮我给这个虚拟机注入一个 vIRQ”。
    3. 准备注入: 无论哪种情况,KVM 现在都明确了要给 Guest 一个虚拟中断。

步骤 3: KVM 注入虚拟中断 (Virtual Interrupt Injection)#

这是 ARM 64 GIC 虚拟化扩展最关键的地方。KVM 不会去手动修改 Guest OS 的内存来模拟一个中断。它会使用硬件特性:

  1. 使用列表寄存器 (List Registers): KVM 会找到一个空闲的 GIC 列表寄存器 (例如 GICH_LR_EL2)。这是一个特殊的硬件寄存器,像一个“邮箱”。
  2. 填充“邮箱”: KVM 向这个列表寄存器里写入虚拟中断的信息,包括:
    • vIRQ ID: 虚拟中断号。
    • 状态: Pending (待处理)。
    • 优先级等。
    • 物理 ID: 有时也包含源物理中断 ID,用于某些高级功能。

这个操作的本质是 KVM 在硬件层面告诉 CPU:“当你稍后返回 Guest 模式时,请把这个虚拟中断呈现给它。”


步骤 4: 从 Hypervisor 返回虚拟机 (Return to Guest)#

  1. KVM 在 EL 2 的工作完成,执行 ERET(Exception Return)指令。
  2. 硬件恢复状态: CPU 硬件会利用之前保存在 ELR_EL2SPSR_EL2 里的信息,精确地恢复 Guest OS 的所有状态,CPU 从 EL 2 返回到 EL 1。这就是 ARM 64 的“VM Entry”。

状态三: Guest OS 接收并处理中断 (Guest Handles vIRQ in EL 1)#

  • CPU 状态: CPU 回到了“非主机模式”,继续在 EL 1 执行 Guest OS 的代码,仿佛什么都没发生过。
  • GIC 状态: 就在 ERET 指令执行后,CPU 的虚拟 CPU 接口因为列表寄存器里有内容,会立刻向 Guest OS 报告一个中断。
  • Guest OS 动作:
    1. Guest OS 感知到了一个中断,它完全不知道刚才发生过一次惊心动魄的 EL 2 之旅。从它的视角看,这就是一次来自它“自己的”GIC 的普通硬件中断。
    2. Guest OS 像在物理机上一样,保存当前上下文(这次是它自己的内部保存),查询自己的中断向量表,找到这个 vIRQ 对应的中断服务程序 (ISR)(这个 ISR 是由 Guest 内部的设备驱动注册的)。
    3. 跳转并执行 ISR,处理设备事件(比如从 virtio 队列里读取网络包)。

总结流程图#

+--------------------------------+
| 状态一: Guest运行中 (EL1)        |
+--------------------------------+
             |
             | 1. 物理中断 (Physical IRQ) 发生
             V
+--------------------------------+
| 2. 硬件异常,陷入EL2 (Trap)      |
+--------------------------------+
             |
             |
             V
+--------------------------------+
| 状态二: KVM被唤醒 (EL2)          |
|  - 识别物理IRQ                 |
|  - 决策注入哪个vIRQ              |
|  - 3. 填充GIC列表寄存器        |
+--------------------------------+
             |
             | 4. 执行ERET指令返回
             V
+--------------------------------+
| 状态三: Guest恢复运行 (EL1)      |
|  - 硬件呈现vIRQ                |
|  - Guest OS像处理普通中断一样  |
|    跳转到自己的ISR             |
+--------------------------------+

这个流程的核心优势在于,利用硬件虚拟化扩展,将重量级的 VM Exit/Entry 次数降到最低,并且中断注入的过程由硬件辅助完成,极大地提升了虚拟化 I/O 的性能。

中断处理的全流程及状态转换
https://scudays.github.io/posts/icsas/虚拟化/中断处理的全流程及状态转换/
作者
Days
发布于
2025-09-10
许可协议
CC BY-NC-SA 4.0