11-28-2025

64 bit ARM architecture -- Interrupts

Forget everything you learned about interrupts for 32 bit ARM. This is now a totally different world. We have 4 sorts of interrupts:
Synchronous interrupts - caused directly by executing an instruction (divide by zero, address fault, ...)
IRQ
FIQ
SError (System Error)- previously called an external abort - some error that can't be blamed on the current instruction.

The GIC

Both 32 bit and 64 bit ARM systems use a GIC (Generic Interrupt Controller). The RK3328 I am working with right now uses a GIC-400. The 32 bit Allwinner H3 also uses a GIC-400, and so does the Allwinner H5 according to my notes. The Rockchip RK3399 uses a GIC-500, perhaps because it has 6 cores of two different sorts. The GIC-500 implements GICv3 whereas the GIC-400 implements GICv2. The 8 core Samsung chip in the Fire3 also uses the GIC-400.

The following article discusses some compatibility issues with the two controllers.

This is moot for me right now as I am working with the RK3328 which clearly calls out the GIC-400 and specifies the document as: IHI0048B_gic_architecture_specification.pdf

Interrupt stack

ARM 64 has two different sets of vectors for exceptions coming from the same EL. They differ in which SP is being used. One set is for when "the EL is using SP_EL0" and the other set is for when "the EL is using SP_ELx".
A bit in the SPSR_ELx registers governs how the processor is running.

The VBAR registers

We have VBAR_el3, VBAR_el2, and VBAR_el1. No VBAR for el0 and it is not intended nor expected to handle interrupts. For each EL, the VBAR points to a 2K block of interrupt vectors. The block does not hold addresses, but code! There are actually 16 "vectors" arranged as 4 sets of 4. One set for each of the following situations: Within each of these sets or blocks we have 4 exception vectors: With 2K all told, each block is 512 bytes, so each vector gets 128 bytes, which is enough for 32 instructions. Yes aarch64 instructions are 32 bits (4 bytes) in size. The usual case is that the entire exception handler won't fit into 32 instructions, so it will use the "bl" instruction to call a subroutine outside of the vector area.

How are interrupts routed between different EL

The thoughtful reader may now be wondering with 3 different vector tables, just what governs which level and table handles an interrupt. MORE

Linux system calls

This is the typical case from EL0 to EL1 when linux is running. Linux does something like this to make a system call:
load registers
svc #0
This will generate a synchronous exception. The claim is that the SVC number (here 0) will be in the lower 16 bits of ESR_EL0 where "ESR" is the "exception syndrome register". This is a 64 bit register.

How does the synchronous exception handler know that this is a SVC call?
We have at least these different synchronous exceptions:

Bits 31:26 of the ESR give us "EC" (exception class), which tell us what sort of synchronous exception we are handling. 0b010101 indicates an SVC instruction executed in aarch64 state.
Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org