我是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)将CPSR
复制到SPSR
(我该怎么做ARM程序集?
5) 移至处理器 IRQ 模式(我可以在 ARM 程序集中执行此操作)。
6) 下一步是什么?
我们需要提供PIC的基址吗?
我正在使用 ARMV7 架构。
-
ARM 上的程序计数器指向正在获取的指令,而不是当前指令。
对于正常的子例程调用,这是完美的 - 当程序计数器被复制到链接寄存器时,它已经指向下一条指令。在中断处理程序中,它指向中断指令之后的指令,因此需要对此进行更正。
您也可以在出路时应用此更正,例如返回
SUBS pc, lr, #4
.请注意,如果中断的代码在 Thumb 模式下运行,则lr
仅提前两个字节,因此如果要在 Thumb 模式下支持用户代码,则需要查看spsr_IRQ
以找出要应用的偏移量。 -
在 ARM 上,由于注册银行业务,您已经有一个单独的堆栈。进入 IQ 模式时,寄存器
r13
又名sp
和r14
又名lr
将切换到r13_IRQ
和r14_IRQ
,这就是为什么您在退出中断处理程序时不需要为中断的应用程序恢复lr
的原因。需要在第一次中断发生之前设置此堆栈。内核启动代码在某个时候通过更改状态寄存器从初始
SVC
模式切换到IRQ
模式,此时r13_IRQ
寄存器变得可见,在那里写入初始堆栈指针并切换回SVC
模式。扩展堆栈帧的工作方式与 x86 基本相同,通过从堆栈指针中减去,例如使用
SUB sp,sp,#8
.粘贴的 x86 代码不仅扩展堆栈空间,它还构建一个基本指针链,这在希望调试器显示调用堆栈时非常有用。为此,您需要根据 ABI 填写一个完整的堆栈帧,将保存的返回地址保存在特定的插槽中等,我认为这是一个高级主题。如果您希望在从中断处理程序调用的 C 函数中使用调试器,则可以调用第一个 C 函数,
r12
设置为零,这将使基本指针链在处理程序函数处终止,而不是混淆调试器。 -
你把它倒过来了——这两个寄存器是存储的,不需要保存,除非你在处理程序中重新启用中断。您需要保存处理程序使用的任何寄存器,并在返回之前恢复它们,STore 多重完全降序 (STMFD) 指令是正确的。
-
这也是倒退。您希望保存
spsr_IRQ
寄存器,而不是覆盖它。同样,这是一个银行寄存器,因此只有在处理程序返回之前预计会有更多的中断(即清除PSR中的"中断禁用"位)时才需要执行此操作。 -
您已经处于
IRQ
模式。您可以通过在状态寄存器中设置新模式或使用带有S
后缀(MOVS
、SUBS
、ADDS
、...)的指令从lr
设置pc
来退出 IRQ 模式(在此上下文中,"设置状态寄存器"位表示"将 SPSR 复制到 PSR")。 -
之后,处理 IRQ 的原因,通常是询问中断控制器(位于 ARM 内核之外,因此它取决于模型)发生了什么,然后分支到适当的代码路径。根据时序约束,您可以处理整个事件,或者只是在空闲循环中快速记录发生了中断,并且下次系统空闲时应调用相应的函数。
从 IRQ 返回时,您需要清理 IRQ 堆栈,恢复任何未存入银行的寄存器,然后使用 MOVS
、SUBS
或类似的指令同时设置pc
和cpsr
。