关于RISC-V 中断处理的分析
我的研究方向是 RISC-V 的虚拟化,需要对 RISC-V 非常熟悉
涉及到 PLIC 的模拟、中断注入虚拟机,等就需要对 RISC-V 的不同中断类型都有比较深的理解
以下为个人的总结,如果不妥/不严谨之处,欢迎指出
中断类型
RISC-V 特权级手册中指出:
在 RISC-V 中有四种类型中断:软件中断、时钟中断、外部中断、计数器溢出中断,其中计数器溢出中断主要用在性能分析,这里主要分析最常用的软件中断、时钟中断、外部中断

中断的产生
软件中断:硬件不会主动产生,需要软件主动触发,通过 clint、aclint 等可以进行发送 IPI,写MMIO的对应区域,目标 hart 的 xSIP 位会被置位,收到软件中断。
时钟中断:处理器中的 time 和 timecmp 寄存器进行比较,time 是一个自增的寄存器,其频率和硬件设计有关,当 time >= timecmp 时会自动设置当前 hart 的 sTIP 位,产生了时钟中断。
外部中断:外部中断由中断控制器(如PLIC)传递,所有外设的中断线连接在 PLIC 上,PLIC 连接 hart,并可以配置是 M-mode hart 还是 S-mode hart。当中断源来临时,首先到达 PLIC,PLIC 中的对应 pending bit 置位,经过 PLIC 仲裁,将目标 hart 的 xEIP 置位,hart 收到了外部中断。
下图来自:https://mes0903.github.io/risc-v/PLIC/
但注意标准的 PLIC 不会像 VS/U 发送中断,标准的 PLIC 只可以投递到 M-mode/S-mode hart,所以虚拟化环境中 PLIC 实现不了外部中断直达虚拟机,必须经过 hypervisor 注入。
当中断无法直接在 VM 的寄存器中表现出来,必须由 hypervisor 进行软件层面的模拟。RISC-V 的 Hypervisor Extension 提供了一定支持。

中断的处理
软件中断:需要软件手动 clear 相关的 xSIP 位。
时钟中断:需要设置 timecmp 的值,使其大于 time,则硬件会自动消除 xTIP,即时钟中断 pending 位由硬件置 0。
外部中断:也是由硬件自动修改,读写中断控制器的相关位,硬件会自动消除 xEIP。
Note:只有软件中断需要手动写寄存器清除 pending 位,其余不可以。
中断控制器 PLIC 的中断处理 claim/complete
以下内容主要来自 PLIC Spec version1.0.0
以下内容为个人认为比较有用的细节,进一步理解 PLIC
-
由 PLIC 生成的中断通知会出现在 mip/seip 寄存器的 meip/seip 位中,分别对应 M/S 特权模式。
-
通知仅会出现在低特权级的
xip
寄存器中,如果外部中断已被委托到低特权级模式。 -
每个中断目标(interrupt target)在 PLIC core 中都有一个外部中断挂起(EIP, External Interrupt Pending)位 ,用于指示该目标是否有等待处理的挂起中断。EIP 的值会作为中断通知 传递给目标。如果目标是一个 RISC-V 的 hart 上下文,那么这个中断通知会出现在
mip
/sip
寄存器中的meip
/seip
位,具体取决于该 hart 上下文的特权级。 -
每个中断源在任何时刻最多只能有一个中断请求挂起,这通过设置该源的 IP 位来表示。网关只有在接收到来自同一源的前一个中断请求的处理完成通知后,才会将新的中断请求转发到 PLIC 核心。
-
PLIC 硬件仅支持中断的多播(multicasting),即所有启用的目标(targets)都会接收到某个活动中断的通知。
Claim 中断
PLIC 可以通过读取 claim/complete register 来执行中断 claim 操作,该寄存器会返回最高优先级的 pending 中断 ID,如果没有挂起中断,则返回 ID 0。成功 claim 之后,PLIC 会原子地清除对应的 pending bit。
在目标 claim 了最高优先级的 pending 中断并清除了对应的 IP 位后,其他较低优先级的 pending 中断可能会变得可见。因此,EIP 位可能在 claim 后不会被清除。中断处理程序可以在 return 之前检查本地的 meip/seip 位,以便在不中断当前上下文的情况下高效地处理其他中断,而不必恢复中断上下文并重新触发另一个 trap。
一个 hart 执行 claim 操作时,即使 EIP 位未设置,也是合法的。特别地,hart 可以将阈值寄存器设置为最大值,以禁用中断通知,并通过定期的 claim 请求来轮询 active 中断,虽然实现轮询的一个更简单的方法是清除对应特权模式下的外部中断使能寄存器 xie。
这句话我不是特别确定,没见过具体的例子,大概意思是,可以通过轮询的方式来处理 claim 中断,而不是等待 PLIC 通知。允许主动查询是否有中断进行处理。
Complete 中断
当 PLIC 执行完一个中断处理程序后,它会通过将从 claim 接收到的中断 ID 写入 claim/complete 寄存器来信号化它已完成中断处理。PLIC 不会检查该完成 ID 是否与目标的上一个 claim ID 相同。如果完成 ID 不匹配当前为目标启用的中断源,完成操作将被静默忽略。
在一个中断处理程序完成对中断的处理后,必须向相关的网关发送一个中断完成消息。只有在接收到完成消息后,网关才会将其他中断转发给 PLIC 核心。
个人小结
一个中断有多个状态:
- pending:表示这个中断挂起,等待被 claim
- active:表示这个中断被 claim,正在处理,还未 complete
当一个中断被 claim(由 pending 进入 active),若没有别的 pending 中断,meip/seip 就会为 0,当完成中断后则返回。
当一个中断被 claim,此时有别的中断 pending,meip/seip 则可能不为 0,完成中断后则返回,但是由于 meip/seip 仍为1,马上又会产生 trap,进入中断处理程序(对于不支持中断嵌套的系统来说)。