Temporarily disable interrupts on ARM

glglgl picture glglgl · Oct 13, 2016 · Viewed 10.1k times · Source

I am starting working with the ARM platform (specifically the TI TMS570 family).

I have some code with critical regions where I don't want an exception to occur. So I want to save the IRQ and FIR enabled flags on entering the regions and restore them on exiting.

How do I do that?

Answer

Notlikethat picture Notlikethat · Oct 13, 2016

To temporarily mask IRQs and FIQs at the CPU, the nicest option for ARMv7 is to use cps:

// assembly code assuming interrupts unmasked on entry

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

Some compilers provide a set of __disable_irq() etc. intrinsics usable from C code, but for others (like GCC) it's going to be a case of dropping to assembly.

If you want critical sections to be nested, reentrant, taken in interrupt handlers or anything else which requires restoring the previous state as opposed to just uncondionally unmasking at the end, then you'll need to copy that state out of the CPSR before masking anything, then restore it on exit. At that point the unmasking probably ends up simpler to handle the old-fashioned way of a direct read-modify-write of the CPSR. Here's one idea off the top of my head:

// 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