在 CortexM 上中断 Load-Multiple/Store-Multiple

Interrupted Load-Multiple/Store-Multiple on CortexM

当 IRQ 中断 load/store 多条指令时,我遇到了与 Return-From-Interrupt 相关的问题。

当 IRQ 中断一个 load/store 多指令时,EPSR 的 ICI 字段指示 LDM/STM 指令应该在中断的 return 上继续。

中断入口异常帧(包含调用者保存的上下文)由硬件自动存储在当前堆栈中。

在我的例子中,内核软件然后保存被调用者保存的上下文并准备一个新的上下文,其中包括堆栈上的虚拟异常帧。 准备好新上下文后,执行 BX LR 指令,弹出虚拟异常帧。由于虚拟异常帧包含 return-地址(return 地址指向新的中断处理程序),执行转到新的中断处理程序。

在这种情况下,如果被中断的指令是 LDM/STM 指令,我会得到一个带有 INVSTATE 的 USAGE-FAULT 异常,因为 return-from-interrupt 上的硬件需要适当的 LDM/STM 指令,而 return 地址在我的例子中是一个不同的位置。

ARM 架构参考手册提到了可以为 CortexM 实现的三个设计选项。

在指令集属性寄存器2(ID_ISAR2)中,位[11:8]:

  1. None 支持。这意味着 LDM 和 STM 指令不是 可中断的。 ARMv7-M 保留。
  2. LDM 和 STM 指令可重新启动。
  3. LDM 和 STM 指令是可继续的。

我的硬件是使用选项 3 实现的。

我无法理解的是,如果我强制IPSR的ICI字段为0, 我的 LDM/STM 指令会重新启动还是会出现异常?

即使它重新启动(考虑中断的 STM 指令),它是否会在已经部分压入的寄存器之上压入,最终在这种情况下破坏堆栈,或者它会在重新启动操作之前调整堆栈指针。

ICI/IT 字段是 EPSR 的一部分,而不是 IPSR,如果您与 xPSR 交互,它不会产生巨大的差异。

如果STM或LDM指令被中断,EPSR被设置为指示可以继续执行的点,并且然后触发异常入口。因此,它是包含此信息的堆栈 PSR 值,就像它包含来自中断代码的 Thumb 位一样。如果您的新上下文在堆栈 PSR 的 ISI 位中为零,您应该不会因为您给出的原因而看到使用错误异常。 (在没有任何代码的情况下,我真的不能比这更具体了。)

如果 LDM 和 STM 实现为可重新启动或可继续,则不会,堆栈不会被此过程破坏。 (那将是一场噩梦!)如果 LDM 和 STM 可重新启动,则堆栈指针将简单地重置为它在 LDM/STM 开始时的值,并重新执行指令;如果它们是可继续的,则不会修改堆栈指针,但会执行部分 STM/LDM 以完成指令。

你没有具体提到你是如何实现上下文切换的,但我假设你是手动将 r4-r11 推送到进程堆栈,然后将 PSP 保存在某个地方并更新它以指向新的不同堆栈上的上下文,在弹出 r4-r11 并触发异常 return 之前 - 这当然是通常的处理方式。