The ARMv8-A architecture has four Exception levels, EL0, EL1, EL2, and EL3. Processor execution can only move between Exception levels by taking, or returning from, an exception.
- When the processor moves from a higher to a lower Exception level, the Execution state can stay the same, or it can switch from AArch64 to AArch32.
- When moving from a lower to a higher Exception level, the Execution state can stay the same or switch from AArch32 to AArch64.
An exception causes a change of program flow. Execution restarts in the Exception level to which the Exception is taken, from the exception vector that corresponds to the exception taken. That is, the exception vector holds the first instruction of the exception handler.
When an event that causes an exception occurs, the processor hardware automatically performs several actions:
- The SPSR_ELn is updated (where n is the Exception level where the exception is taken), to store the PSTATE information that is required to correctly return at the end of the exception.
- PSTATE is updated to reflect the new processor status (and this can mean that the Exception level is raised, or it can stay the same).
The address to return to at the end of the exception is stored in ELR_ELn.
The _ELn suffix on register names denotes that there are multiple copies of these registers existing at different Exception levels. This means, for example, that SPSR_EL1 is a different physical register to SPSR_EL2.
The processor branches to a vector table which contains entries for each exception type. The vector table contains a dispatch code, which typically identifies the cause of the exception, and selects and calls the relevant function to handle it.
When the handler code completes execution it returns to the high-level handler, which then executes the ERET instruction to return to the application.
The target Execution State (that is, AArch32 or AArch64) and Exception level for asynchronous exceptions are configured using two system registers, SCR_EL3 and HCR_EL2.