ARM Technical Support Knowledge Articles

What happens if an interrupt occurs as it is being disabled?

Applies to: ARM7TDMI

Answer

If an interrupt is received by the core during execution of an instruction that disables interrupts, the ARM7 family will still take the interrupt. This occurs for both IRQ and FIQ interrupts.

For example, consider the follow instruction sequence:

     MRS    r0, cpsr
ORR r0, r0, #I_Bit:OR:F_Bit ;disable IRQ and FIQ interrupts
MSR cpsr_c, r0

If an IRQ interrupt is received during execution of the MSR instruction, then the behavior will be as follows:

  • The IRQ interrupt is latched
  • The MSR cpsr, r0 executes to completion setting both the I bit and the F bit in the CPSR
  • The IRQ interrupt is taken because the core was committed to taking the interrupt exception before the I bit was set in the CPSR.
  • The CPSR (with the I bit and F bit set) is moved to the SPSR_irq

This means that, on entry to the IRQ interrupt service routine, one can see the unusual effect that an IRQ interrupt has just been taken while the I bit in the SPSR is set. In the example above, the F bit will also be set in both the CPSR and SPSR. This means that FIQs are disabled upon entry to the IRQ service routine, and will remain so until explicitly re-enabled. FIQs will not be re-enabled automatically by the IRQ return sequence.

Although the example shows both IRQ and FIQ interrupts being disabled, similar behavior occurs when only one of the two interrupt types is being disabled. The fact that the core processes the IRQ after completion of the MSR instruction which disables IRQs does not normally cause a problem, since an interrupt arriving just one cycle earlier would be expected to be taken. When the interrupt routine returns with an instruction like:

     SUBS    pc, lr, #4

the SPSR_IRQ is restored to the CPSR. The CPSR will now have the I bit and F bit set, and therefore execution will continue with all interrupts disabled.

However, this can cause problems in the following cases:

Problem 1: A particular routine may be called as an IRQ handler, or as a regular subroutine. When the routine is called as a regular subroutine, the calling code must first disable interrupts. The routine determines how it was called by examining the I bit of the SPSR and returns using the appropriate instruction. If the routine is entered due to an IRQ being received during execution of the MSR instruction which disables IRQs, then the I bit in the SPSR will be set. The routine would therefore assume that it could not have been entered via an IRQ.

Problem 2: FIQs and IRQs are both disabled by the same write to the CPSR. In this case, if an IRQ is received during the CPSR write, FIQs will be disabled for the execution time of the IRQ handler. This may not be acceptable in a system where FIQs must not be disabled for more than a few cycles.

Workaround:

There are 3 suggested workarounds. Which of these is most applicable will depend upon the requirements of the particular system.

  1. Add code similar to the following at the start of the interrupt routine.

         SUB     lr, lr, #4       ; Adjust LR to point to return
    STMFD sp!, {..., lr} ; Get some free regs
    MRS lr, SPSR ; See if we got an interrupt while
    TST lr, #I_Bit ; interrupts were disabled.
    LDMNEFD sp!, {..., pc}^ ; If so, just return immediately.
    ; The interrupt will remain
    ; pending since we haven't
    ; acknowledged it and will be
    ; reissued when interrupts are next
    ; enabled.
    ; Rest of interrupt routine

    This code will test for the situation where the IRQ was received during a write to disable IRQs. If this is the case, the code returns immediately - resulting in the IRQ not being acknowledged (cleared), and further IRQs being disabled.

    Similar code may also be applied to the FIQ handler, in order to resolve the first issue.

    This is the recommended workaround, as it overcomes both problems mentioned above. However, in the case of problem two, it does add several cycles to the maximum length of time FIQs will be disabled.

  2. Disable IRQs and FIQs using separate writes to the CPSR, eg:

         MRS     r0, cpsr
    ORR r0, r0, #I_Bit ;disable IRQs
    MSR cpsr_c, r0
    ORR r0, r0, #F_Bit ;disable FIQs
    MSR cpsr_c, r0

    This is the best workaround where the maximum time for which FIQs are disabled is critical (it does not increase this time at all). However, it does not solve problem one, and requires extra instructions at every point where IRQs and FIQs are disabled together.

  3. Re-enable FIQs at the beginning of the IRQ handler. As the required state of all bits in the c field of the CPSR are known, this can be most efficiently be achieved by writing an immediate value to CPSR_c, for example:

         MSR     cpsr_c, #I_Bit:OR:irq_MODE  ;IRQ should be disabled
    ;FIQ enabled
    ;ARM state, IRQ mode

    This requires only the IRQ handler to be modified, and FIQs may be re-enabled more quickly than by using workaround 1. However, this should only be used if the system can guarantee that FIQs are never disabled while IRQs are enabled. It does not address problem one.

Article last edited on: 2008-09-09 15:47:36

Rate this article

[Bad]
|
|
[Good]
Disagree? Move your mouse over the bar and click

Did you find this article helpful? Yes No

How can we improve this article?

Link to this article
Copyright © 2011 ARM Limited. All rights reserved. External (Open), Non-Confidential