在ARM上临时禁用中断

8

我开始使用ARM平台(具体来说是TI TMS570系列)。

我有一些关键区域的代码,不希望发生异常。因此我想在进入这些区域时保存IRQ和FIR使能标志,并在退出时恢复它们。

我该如何做到这一点?

2个回答

14

为了在CPU上临时屏蔽IRQ和FIQ,对于ARMv7来说最好的选择是使用cps

// assembly code assuming interrupts unmasked on entry

cpsid if  // mask IRQ and FIQ
...       // do critical stuff
cpsie if  // unmask

一些编译器提供了一组可从C代码中使用的__disable_irq()等内嵌函数,但对于其他编译器(如GCC),则需要降到汇编级别。

如果您希望关键部分可以嵌套、可重入、在中断处理程序中执行或任何其他需要恢复先前状态而不是仅在结尾无条件解锁的情况下,则需要在屏蔽任何内容之前将该状态从CPSR中复制出来,然后在退出时恢复它。此时,解锁可能最好采用老式方式,即直接读取修改写入CPSR。以下是我脑海中的一个想法:

// int enter_critical_section(void);
enter_critical_section:
mrs r0, cpsr
cpsid if
and r0, r0, #0xc0  // leave just the I and F flags
bx lr

// void leave_critical_section(int flags);
leave_critical_section:
mrs r1, cpsr
bic r1, r1, r0
msr cpsr_c, r1
bx lr

值得注意的是,在Cortex-R上,根据您所处的模式,有各种不同的PSR寄存器。您需要确保使用正确的寄存器!请参阅Cortex-R技术参考手册。 - Realtime Rik
@RealtimeRik 各种各样的?当然,APSR是“从用户模式可访问的CPSR部分”的别名,但它仍然是完全相同的寄存器。你不是在想M-profile吧(它确实有3个单独的PSR,以及所有可能组合的别名)? - Notlikethat
不,我在考虑Cortex-R。如果您在用户模式下执行所有这些操作,则CPSR保持不变。但是,例如,在中断或监管模式下访问它时,情况将会有所不同。 - Realtime Rik
@RealtimeRik,禁用中断与用户模式无关。CPSR是当前程序状态的表示,除了M字段的值,它在不同模式下没有任何区别。而这个值恰好是用来确定当前处于哪种模式的! - Notlikethat

0

您可以在Halcogen生成的代码(sys_core.h)中使用_disable_interrupt_(); _enable_interrupt_();


2
感谢您的回答。总的来说,您是正确的,但是如果由于某种原因中断已经被禁用怎么办?那么当这可能不是真正想要的时候,我会在最后启用它们。所以根据Notlikethat的建议保存CPSR并恢复相关部分似乎是至关重要的。 - glglgl
我只发布一个字符串。实际上,我进行嵌套级别计数。此外,如果您在中断内部,则不需要禁用中断。 - vromanov
1
这取决于我是否知道自己是否在中断内部。假设我有类似队列框架之类的东西,我需要确保更改是原子性的。然后我需要在开始时无条件地禁用中断,并恢复之前的情况,因为库函数不知道它是否从中断中调用。 - glglgl
#define MODE_BITS 0x1F #define FIQ_MODE 0x11 #define IRQ_MODE 0x12静态内联布尔型函数isFromInterrupt(void){ register uint32_t cpsr = getCPSRValue(); register uint32_t mode = cpsr&MODE_BITS; return(mode == FIQ_MODE)||(mode == IRQ_MODE); } - vromanov
2
这似乎比我只存储CPSR并部分恢复它的另一个解决方案要复杂得多。 - glglgl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接