You copied the Doc URL to your clipboard.

Interrupt handling

ARM commonly uses interrupt to mean interrupt signal. On ARM A-profile and R-profile processors, that means an external IRQ or FIQ interrupt signal. The architecture does not specify how these signals are used. FIQ is often reserved for secure interrupt sources.

Both A-profile and R-profile processors cores have two physical interrupt pins, IRQ, and FIQ. An FIQ can mask IRQs, but an IRQ cannot mask FIQs. Historically, the architecture had features to permit lower-latency processing of FIQs.

When the processor takes an exception to AArch64 Execution state, all the PSTATE.DAIF interrupt masks are set automatically. This means that further interrupts are disabled. If software is to support nested interrupts, for example, to allow a higher priority interrupt to interrupt the handling of a lower priority source, then software must explicitly re-enable interrupts using the following instruction:

MSR DAIFClr, #imm

The immediate value is in fact a 4-bit field. There are also masks for:

  • A (for SError)
  • D (for Debug)
c_interrupt_handler.png

An assembly language IRQ handler might look like this:

IRQ_Handler
// Stack all corruptible registers and save PCS corruptible interrupts
STP X0, X1, [SP, #-16]!	       // SP = SP -16
STP X2, X3, [SP, #-16]!	       // SP = SP – 16
...					 // PUSH the rest of the corruptible registers
 
BL read_irq_source		      // a function to work out why we took an
					    // interrupt and clear the request
BL C_irq_handler			 // the C interrupt handler
// restore from stack the corruptible
// registers
LDP X2, X3, [SP], #16		  // S = SP + 16
LDP X0, X1, [SP], #16		  // S = SP + 16
… 
ERET
            

However, from a performance point of view, the following sequence can be used:

IRQ_Handler
SUB SP, SP, #<frame_size> 	   // SP = SP - <frame_size>
STP X0, X1, [SP], +16		  // Store X0 and X1 at the base of the frame
STP X2, X3, [SP], +16		  // Store X2 and X3 at the base of the frame 
// + 16 bytes
...					// more register storing
...
// Interrupt handling

BL read_irq_source		    // a function to work out why we took an 
					   // interrupt and clear the request
BL C_irq_handler			// the C interrupt handler
// restore from stack the corruptible 
// registers 
LDP X0, X1, [SP, #-16]!		// Load X0 and X1 at the base of the frame
LDP X2, X3, [SP, #-16]!		// Load X2 and X3 at the base of the frame + 
					   // 16 bytes
...					// more register loading
ADD SP, SP, #<frame_size> 	   // Restore SP at its original value
… 
ERET

The nested handler requires a little extra code. It must preserve on the stack the contents of SPSR_EL1 and ELR_EL1. IRQs must be re-enabled after determining (and clearing) the interrupt source. However, as the link register for subroutine calls is different to the link register for exceptions, it is possible to avoid having to do anything special with LR or modes.

nested_interupts.png
Was this page helpful? Yes No