Timeline
Timeline
2025-10-16
init
This article introduces the exception model of the ARM64 architecture, discussing in detail exception levels, terminology definitions, and the classification of synchronous and asynchronous exceptions. It also summarizes the handling mechanisms of hardware and the operating system during exception entry and return phases, and explains the exception routing rules based on system configuration registers.
Reference documents:
Exception Levels of ARM64
- EL0Unprivileged mode, e.g., applications
- EL1Privileged mode, e.g., OS kernel
- EL2Virtualization monitor, e.g., hypervisor
- EL3Secure mode, e.g., secure monitor
Exception terminology
- Taking an exception: Handling an exception
- Returning from an exception: Returning from an exception
- Exception levels: Exception level
- Precise exception: Precise exception
- Synchronous and asynchronous exception: Synchronous and asynchronous exceptions
Types of exceptions
- Synchronous exceptions
- System calls, SVC, HVC, SMC, etc.
- Exceptions caused by the MMU
- SP and PC alignment checks
- Unallocated instructions
- Unallocated instruction opcodes
- Instructions requiring higher privilege than the current exception level.
- Disabled instructions.
- Any instruction when the PSTATE.IL field is set
- Debug exceptions
- Asynchronous exceptions
- IRQ interrupts
- FIQ interrupts
- SError(System error)
Synchronous exceptions are exceptions that are triggered as expected, while asynchronous exceptions are triggered unexpectedly.
Exception Entry
Process state or PSTATE is an abstraction of process state information
- When an exception occurs,the CPU hardwaredoes the following things
- PSTATE is saved to SPSR_ELx (The Saved Program Status Register)
- The return address is saved to ELR_ELx
- The DAIF field of the PSTATE register is set to 1, which effectively disables debug exceptions, system errors (SError), IRQ interrupts, and FIQ interrupts.
- The ESR_ELx (Exception Syndrome Register) is updated, containing the cause of the synchronous exception or SError.
- SP switches to SP_ELx
- It switches to the corresponding EL and then jumps to the exception vector table for execution.
- What does the operating system need to do after an exception occurs?
The operating system needs to set up the exception vector table so that the CPU, based on the type of exception, jumps to the appropriate entry in the exception vector table.
Each entry in the exception vector table stores a jump function for exception handling, which then jumps to the appropriate exception handler to process the exception.
The Exception Syndrome Register (ESR_ELn) contains information that allows the exception handler to determine the cause of the exception. It is updated only for synchronous exceptions and SError, not for IRQ or FIQ, because those interrupt handlers typically obtain status information from the registers of the Generic Interrupt Controller (GIC).
Exception return
- The operating system executes aeretstatement
- Restore the PC pointer from the ELR_ELx (Exception Link Register) register
- Restore the processor state from the SPSR_ELx (The Saved Program Status Register) register

Exception return address
- Two registers for return address
- x30: Return address of a subroutine. Use the ret instruction to return
- ELR_ELx: Exception return address. Use the eret instruction to return
- ELR_ELxThe register holds the exception return address
- For asynchronous exceptions, the return address is the next instruction after the interrupt occurred, or the first instruction not executed
- For synchronous exceptions that are not system calls, the return address is the instruction that triggered the synchronous exception
- For a system call, it returns the next instruction after the svc/hvc instruction
Asynchronous exception (interrupt)
The hardware has already set ELR to_the next instruction to be executed_,
eretthen it directly returns to continue execution without additional modification
Synchronous exception (non-system call)
The hardware sets ELR to_the instruction that triggered the exception_
If you fix the cause of the exception (e.g., a page fault), directlyeretwill re-execute this instruction
If you want to skip it (without retrying), you must manuallyELR_ELx += 4
system call(svc)
The hardware sets ELR to_the next instruction after svc_, so
eretwill directly return to the next one
Exception handling routing
When an exception occurs at a specific Exception Level (EL), which exception level the CPU should jump to in order to handle it
- When an exception occurs, it can behandled at the current EL or at a higher EL
- EL0 cannot be used to handle exceptions
- Synchronous exceptions can be handled at the current EL, for example, when a synchronous exception occurs at EL1
- Forasynchronous exceptions, they can be routed to EL1, EL2, or EL3 for handling, it is necessary to configureHCRthe Hypervisor Configuration Register andSCRthe Secure Configuration Register related registers
- If an exception is generated by an instruction fetch at EL0, it is treated as an exception at EL1, unless the HCR_EL2.TGE bit is set for the Non-secure state, in which case it is treated as an exception at EL2.

Refer to Table D1-10 of the ARMv8.6 architecture
- SCR_EL3: Secure Configuration Register
- HCR_EL2: Hypervisor Configuration Register
The table in this image (Table D1-10) isthe interrupt/exception routing rule table when both EL3 (Secure Monitor mode) and EL2 (Virtualization Monitor mode) are implemented in the ARM architecture, core is used to define the target privilege level (EL0~EL3) that the processor ultimately jumps to after an interrupt (IRQ/FIQ) or exception (such as Abort exception) is triggered under different system states (register configurations).

- Row 1: SCR=0, NS EEL2a=0, EA IRQ FIQ=0, RW=0
- Input conditions: Security configuration is default (SCR=0), Non-secure EL2 exception entry disabled (NS EEL2a=0), no active interrupts/exceptions (EA IRQ FIQ=0), read-write permission is 0; HCR TGE, E2H are arbitrary values (X).
- Routing result:
- Triggered from EL0: jumps to “FIQ IRQ Abt” (i.e., the native handler entry for the corresponding interrupt/exception, not intercepted by a higher EL);
- Triggered from EL1: same as EL0, jumps to “FIQ IRQ Abt”;
- Triggered from EL2:
n/a(Not applicable, as EL2 does not enable this scenario when NS EEL2a=0); - Triggered from EL3: jumps to “C” (usually refers to the exception handler entry in Secure state; in ARM architecture, “C” often represents the secure-related default target).
- Row 2: SCR=0, NS EEL2a=0, EA IRQ FIQ=0, RW=1
- Input conditions: Only RW (read-write permission) is changed from 0 to 1, others are the same as Row 1.
- Routing result:
- Triggered from EL0/EL1: jumps to “EL1” (i.e., the exception is intercepted and handled by EL1 (kernel mode), rather than the native interrupt entry, because RW=1 corresponds to higher-privilege kernel processing logic);
- Triggered from EL2:
n/a(Same as row 1, EL2 not enabled); - Triggered from EL3: Jump to ‘C’ (secure state entry unchanged).
- Row 3: SCR=0, NS EEL2a=0, EA IRQ FIQ=1
- Input conditions: EA IRQ FIQ=1 (active interrupt/exception triggered), other configurations same as previous two rows; HCR TGE and E2H are arbitrary values.
- Routing result:
- Triggered from EL0/EL1: Jump to ‘EL3’ (active interrupt/exception intercepted by the highest security level EL3, consistent with the ARM security architecture logic that ‘high-priority exceptions are handled by EL3’);
- Triggered from EL2:
n/a(EL2 not enabled); - Triggered from EL3: Jump to ‘EL3’ (exception triggered by EL3 itself, handled within EL3, no jump to other levels).
- Row 4: SCR=0, NS EEL2a=1, EA IRQ FIQ=0, HCR TGE=0, E2H=0, RW=0
- Input conditions: NS EEL2a=1 (non-secure EL2 exception entry enabled), no active interrupts/exceptions (EA IRQ FIQ=0), virtualization mode disabled (HCR TGE=0), EL2 does not intercept EL1 exceptions (E2H=0).
- Routing result:
- Triggered from EL0: Jump to “FIQ IRQ Abt” (native interrupt entry);
- Triggered from EL1: Jump to “FIQ IRQ Abt” (EL2 does not intercept, because E2H=0);
- Triggered from EL2: Jump to “C” (exception triggered from non-secure EL2, routed to secure entry “C”);
- Triggered from EL3: Jump to “C” (handled internally in secure state, target unchanged).
Stack Selection
- Each Exception Level (EL) has a corresponding stack pointer register SP_ELx
- SP_EL0, SP_EL1, SP_EL2, SP_EL3
- The stack must be 16-byte aligned. Hardware can detect whether the stack pointer is aligned
- When an exception occurs and jumps to the target exception level, the hardware automatically selects SP_ELx
- The operating system is responsible for allocationEnsuring that the stack corresponding to each Exception Level (EL) is available
Execution Mode
Execution Mode for Exception Handling
- When an exception occurs, switching to a higher EL, which mode does this EL run in? AArch64 or AArch32
- **HCR_EL2.RW(Hypervisor Configuration Register)**Records which mode EL1 should run in
- 1 indicates aarch64
- 0 indicates aarch32
- **HCR_EL2.RW(Hypervisor Configuration Register)**Records which mode EL1 should run in

- After an exception occurs, the execution mode can change
- An aarch32 application is running, and when an interrupt arrives, it may jump to EL1 in aarch64 execution state to handle the interrupt
Execution mode on exception return
- When returning from an exception, the SPSR (Saved Program Status Register) records:
- Which EL to return to?SPSR.M[3:0]
- Execution mode of the target EL on return?SPSR.M[4]
- 0 indicates aarch64
- 1 indicates aarch32

| M[3:0] | Target mode | Description |
|---|---|---|
0000 | EL0t | EL0, using SP_EL0 |
0100 | EL1t | EL1, using SP_EL0 |
0101 | EL1h | EL1, using SP_EL1 |
1000 | EL2t | EL2, using SP_EL0 |
1001 | EL2h | EL2, using SP_EL2 |
1100 | EL3t | EL3, using SP_EL0 |
1101 | EL3h | EL3, using SP_EL3 |
Experiment 1: Switch to running in EL1

Hint
To switch from EL2 to EL1, the following things need to be done
Set the HCR_EL2 (Hypervisor Configuration Register) register, the most important being the RW field at Bit 31, which indicates which execution environment EL1 will run in, aarch32 or aarch64(Similarly, the execution state of EL2 is determined by SCR_EL3)
- HCR_EL2 belongs to the General System Control Register

HCR_EL2 
HCR_EL2.RW Set the SCTLR_EL1 (System Control Register), to set the endianness and disable the MMU

SCTLR_EL1.EE 
SCTLR_EL1.E0E 
SCTELR_EL1.M Set the SPSR_EL2 (Saved Program Status Register) register, set the mode M field to EL1h, and also disable all DAIF of PSTATE
- SPSR_ELxbelongs toSpecial-purpose Register

SPSR_EL2 
SPSR_EL2.M 
PSTATE.DAIF at EL2 
SPSR_EL1 
SPSR_EL.M
| M[3:0] | target mode | Description |
|---|---|---|
0000 | EL0t | EL0, using SP_EL0 |
0100 | EL1t | EL1, using SP_EL0 |
0101 | EL1h | EL1, using SP_EL1 |
1000 | EL2t | EL2, using SP_EL0 |
1001 | EL2h | EL2, using SP_EL2 |
1100 | EL3t | EL3, using SP_EL0 |
1101 | EL3h | EL3, using SP_EL3 |

Set the exception return register elr_el2 to return to the el1_entry assembly function
Executeeret
(3,4 are actually classic steps for exception return, returning from EL2 to EL1)
First, determine which exception level to jump to based on the current exception level

Note that the elr_el2 register must be set before executing eret

Exception vectors
Each exception level (EL) has its own exception vector table, except EL0
The base address of the exception vector table needs to be set in the**VBAR_ELx(Vector Base Address Register)**register
VBAR_EL1 register:

VBAR_ELx
Bits 0~10 are reserved, so theaddress is 2KB aligned

- Row (Exception taken from)
Defines the “current execution state” when an exception is taken, divided into 4 scenarios:
- Current Exception level with SP_EL0: The current exception level uses the
SP_EL0stack pointer (e.g., an exception triggered when using the user-level stack pointer at EL1). - Current Exception level with SP_ELx, x>0: The current exception level uses the
SP_ELx(x≥1, e.g., EL1 usesSP_EL1, EL2 usesSP_EL2triggers an exception when accessing kernel-level stack pointers, etc.). - Lower Exception level(AArch64): Triggered from a lower exception level, and the lower level is in AArch64 execution state (e.g., when switching from EL0/EL1 to a higher EL, and the original level is in 64-bit mode).
- Lower Exception level(AArch32): Triggered from a lower exception level, and the lower level is in AArch32 execution state (e.g., switching from EL0/EL1 in 32-bit mode to a higher EL).
- Column (Offset for exception type)
Classified by exception type, corresponding to different offsets:
- Synchronous: Synchronous exception (e.g., instruction execution errors, software-triggered exceptions, occurring synchronously with the instruction stream).
- IRQ or vIRQ: Normal interrupt (IRQ) or virtual interrupt (vIRQ, in virtualization scenarios).
- FIQ or vFIQ: Fast interrupt (FIQ, typically higher priority) or virtual fast interrupt (vFIQ, in virtualization scenarios).
- SError or vSError: System error (SError, such as bus errors and other severe errors) or virtual system error (vSError, in virtualization scenarios).
- Offset values (e.g., 0x000, 0x080, etc.): Based on the combination of row (trigger state) and column (exception type), provides an offset relative to the vector table base address. The processor can find the entry address of the exception handler by base address + offset.

- Overall Structure of the Exception Vector Table
InAArch64 EL1and above execution levels, the exception vector table (Vector Table) is stored in **VBAR_ELx**The address pointed to by the Vector Base Address Register.
This table contains a total of4 “blocks”, corresponding to different exception sources:
- **From the current SP (SP0)**triggered exception
- **From the current SP (SPx)**triggered exception (x≠0, e.g., SP_EL1)
- **From the next lower privilege level (e.g., EL0)**exception
- **From the current privilege level (e.g., within EL1)**exception
Each block further contains4 exception types:
- Synchronous exception(synchronous exceptions, e.g., SVC instruction, data access exceptions)
- IRQ(Normal Interrupt)
- FIQ(Fast Interrupt)
- SError(System Error, usually a hardware exception)
So in total:
4 blocks × 4 exceptions = 16 entries
Size of each entry
ARMv8-A specifies:
- Each entry is fixed at 128 bytes(0x80) (size of 32 instructions).
- 16 entries × 128 bytes = 2048 bytes = 2KB。
- So the total size of the vector table is2KB。
That is, the exception vector table must be2KB-alignedregion.
The exception vector table actually consists of 4 groups of 4 entries
Exception handling in the Linux 5.0 kernel

.align 11 aligns the exception vector table by2k size alignment
kernel_ventry is a macro, simplified code as follows

align 7 means alignment by 2 to the power of 7, which is 128 bytes
The sub instruction subtracts an S from the stack pointer sp_FRAME_SIZE, where S_FRAME_SIZE is called the register frame size, which is the size of the struct pt_regs data structure
“\()” indicates concatenation
For example: when an EL1 IRQ interrupt occurs, this statement becomes “b el1_irq”
kernel_entryis the first-level entry point jumped to by the exception vector table, and its responsibilities are:
- Save context: Save the CPU state (general-purpose registers) onto the stack.
- Establish stack frame: Prepare stack space for the exception handler (C code).
- Switch stack(If needed): For example, when transitioning from user mode to kernel mode, the stack must be switched to the kernel stack.
- Call the C-level exception dispatch function。
Take the FIQ occurring at EL1 as an example


Save exception context
- Stack frame: The Linux kernel defines astruct pt_regsdata structure to describe the arrangement of saved registers on the kernel stack, typically used to save interrupt context and other information.

orig_x0, syscallno, orig_addr_limit, unused, stackframe[0], stackframe[1] are all software-defined saved items.

Experiment 2: Set up an exception vector table and create a synchronous exception

FAR Fault Address Register (at EL1)
Its function is:
- Whena synchronous exception occurs, the processor writes thevirtual addressthat caused the exception into the
FAR_ELxcorresponding register. EL1corresponds to the kernel mode (operating system level), soFAR_EL1stores thevirtual address at the time of the exception under EL1。
Common scenarios
- Page Fault
If the CPU triggers an exception when accessing a non-existent or illegal virtual address,FAR_EL1this address is saved, and the kernel can use it to decide whether to allocate a new page or kill the process. - Alignment Fault
If the access address does not comply with alignment rules,FAR_EL1that address will also be saved. - Watchpoint/Breakpoint Exception
FAR_EL1It may also be used to store the address that triggered the exception.
Related Registers
ESR_EL1(Exception Syndrome Register)
Saves the exception’scause code(such as page fault, permission error, misalignment, etc.).FAR_EL1
Saves thespecific virtual address。
entry.S
1 | #define BAD_SYNC 0 |
kernel.cdefined in

inkernel_maintriggered intrigger_alignment

inboot.Sset the exception vector table in

Experiment 3: Debug: Find the instruction that triggers an exception on Raspberry Pi 4


This instruction loads the value at address current PC + MY_LABEL into x6
Equivalent to:
1 | x6 = *(PC-relative 地址 + MY_LABEL) |
For LDR Xt,The target address must be 8-byte aligned (because Xt is a 64-bit register).
It can be changed to w6, requiring only 4-byte alignment, because MY_LABEL is defined as 0x20.
Exception Analysis
ESR_ELx (Exception Syndrome Register)
ESR_ELx is updated only for synchronous exceptions and SError, not for IRQ or FIQ, because these interrupt handlers typically obtain status information from the registers of the Generic Interrupt Controller (GIC).

- The ESR register contains four fields in total.
- Bits 32~63 are reserved bits.
- Bits 26~31 are theException Class (EC), this fieldindicates the type of exception that occurred,and is also used toindex the ISS field.
- Bit 25, IL, indicates the instruction length of a synchronous exception instruction, Instruction Length
- Bit 0~24,ISS (Instruction Specific Syndrome) specific exception instruction encoding. This exception instruction encoding table depends on different exception types,different exception types have different encoding formats

Common exception type corresponding encodings

The first indicates an instruction exception from a lower exception level, the second indicates an instruction exception at the current exception level

Encoding method of the ISS field




FAR (Fault Address Register)

The FAR register storesthe virtual address at the time of the exception
Experiment 4: Parsing data exception information


esr.h
1 |
|
Function: Parse the value of the ESR_ELx register to facilitate exception handling.
Structure:
- High 6 bits →EC(Exception Class)
- IL, ISV → Instruction length/validity
- ISS → Instruction Specific Syndrome
- FSC → Data access exception code
- WNR, EA, CM → Access attributes
kernel.c
1 | static const char *const bad_mode_handler[] = {"Sync Abort", "IRQ", "FIQ", |
Code that triggers a data exception:

