2

我是 ARM 新手,正在学习 ARM 中的中断处理。我已阅读有关如何在 ARM 中设置 IRQ 处理程序的信息,但不确定如何在 ARM 程序集中编写它。以下是我对设置 IRQ 处理程序的理解。

_IRQ_HANDER:

1)SUB lr, lr, #4(不确定它做了什么)。

2) 将设置单独的堆栈应在 IRQ 模式下使用。我知道在 x86 中我们设置了如下堆栈:

push ebp
mov esp,ebp
sub esp,8

这将保留 8 个字节的堆栈空间。

但不确定我如何在 ARM 中做同样的事情?

3)存储非银行寄存器,我们可以这样做:

  STMFD !sp {r13,r14}

4)复制CPSRSPSR(我怎样才能做到ARM组装?)

5) 切换到处理器 IRQ 模式(我可以在 ARM 程序集中执行此操作)。

6) 下一步是什么?

我们需要给出PIC的基地址吗?

我正在使用 ARMV7 架构。

4

1 回答 1

6
  1. ARM 上的程序计数器指向正在获取的指令,而不是当前指令。

    对于普通的子程序调用,这是完美的——当程序计数器被复制到链接寄存器时,它已经指向下一条指令。在中断处理程序中,它指向被中断指令之后的指令,因此需要对其进行更正。

    您也可以在退出时应用此更正,例如通过返回SUBS pc, lr, #4。请注意,如果被中断的代码在 Thumb 模式下运行,lr则只有两个字节,因此如果您想在 Thumb 模式下支持用户代码,您需要查看spsr_IRQ以找出要应用的偏移量。

  2. 在 ARM 上,由于寄存器存储,您已经有一个单独的堆栈。进入 IQ 模式时,寄存器r13akaspr14akalr切换到r13_IRQand ,这就是为什么在退出中断处理程序时r14_IRQ不需要为被中断的应用程序恢复的原因。lr

    这个堆栈需要在第一个中断发生之前建立。内核启动代码在某些时候通过更改状态寄存器从初始SVC模式切换到IRQ模式,此时r13_IRQ寄存器变为可见,将初始堆栈指针写入那里并切换回SVC模式。

    扩展堆栈帧的工作方式与 x86 上基本相同,通过从堆栈指针中减去,例如使用SUB sp,sp,#8.

    您粘贴的 x86 代码不仅仅是扩展堆栈空间:它还构建了一个基本指针链,如果您希望调试器显示调用堆栈,这很有用。为此,您需要根据 ABI 填写完整的堆栈帧,并将返回地址保存在特定插槽等中,我认为这是一个高级主题。如果您希望在从中断处理程序调用的 C 函数中使用调试器,您可以调用第一个r12设置为零的 C 函数,这将使基指针链在您的处理程序函数处终止,而不是混淆调试器。

  3. 你有它 - 这两个寄存器被存储并且不需要保存,除非你在处理程序中重新启用中断。您需要保存处理程序使用的任何寄存器,并在返回之前恢复它们,STore Multiple Full Descending (STMFD) 指令对此是正确的。

  4. 这也是倒退。您想保存spsr_IRQ寄存器而不是覆盖它。同样,这是一个存储寄存器,因此您只需要在您的处理程序返回之前预期更多中断时才需要这样做(即您清除 PSR 中的“中断禁用”位)。

  5. 您已经处于IRQ模式中。您可以通过在状态寄存器中设置新模式来离开 IRQ 模式,或者使用带有S后缀 ( MOVS, SUBS, ADDS, ...) 的指令来pc设置lrSPSR 到 PSR")。

  6. 之后,您处理 IRQ 的原因,通常是通过询问中断控制器(它位于 ARM 内核之外,因此它取决于模型)发生了什么,然后分支到适当的代码路径。根据时序限制,您可以处理整个事件,或者只是快速记录空闲循环,即发生了中断,并且下次系统空闲时应该调用适当的函数。

从 IRQ 返回,您需要清理 IRQ 堆栈,恢复所有非分组寄存器,然后使用MOVS,SUBS或类似指令同时设置pccpsr

于 2013-11-11T15:57:56.113 回答