Handling exceptions

When an exception occurs, the current program flow is interrupted. The Processing Element (PE) will update the current state and branch to a location in the vector table. Usually this location will contain generic code to push the state of the current program onto the stack and then branch to further code. This is illustrated here:

This image relates to handling exceptions in Armv8-A.

Exception terminology

The state that the processor is in when the exception is recognized is known as the state the exception is taken from. The state the PE is in immediately after the exception is the state the exception is taken to. For example, it is possible to take an exception from AArch32 EL0 to AArch64 EL1.

The Armv8-A architecture has instructions that trigger an exception return. In that case, the state that the PE is in when that instruction is executed is the state that the exception return from. The state after the exception return instruction has executed is the state that the exception return to.

Each exception type targets an Exception level. Asynchronous exceptions can be routed to different exception levels.

Taking an exception

When an exception is taken, the current state must be preserved so that it can be returned to. The PE will automatically preserve the exception return address and the current PSTATE.

The state stored in the general-purpose registers must be preserved by software. The PE will then update the current PSTATE to the one defined in the architecture for that exception type, and branch to the exception handler in the vector table.

The PSTATE the exception was taken from is stored in the System register SPSR_ELx, where <x> is the number of the Exception level that the exception was taken to. The exception return address is stored in ELR_ELx, where <x> is the Exception level that the exception was taken to.

Routing asynchronous exceptions

The three physical interrupt types can be independently routed to one of the privileged Exception levels, EL1, EL2 or EL3. The diagram below uses IRQs as an example:

This diagram relates to handling exceptions in Armv8-A.

This routing is configured using SCR_EL3 and HCR_EL2. Routing configurations made using SCR_EL3 will override routing configurations made using HCR_EL2. These controls allow different interrupt types to be routed to different software.

Exceptions that are routed to a lower Exception level than the level being executed are implicitly masked. The exception will be pended until the PE changes to an Exception level equal to, or lower than, the one routed to.

Determining which Execution state an exception is taken to

The Execution state of an Exception level that an exception is taken to is determined by a higher Exception level. Assuming all Exception levels are implemented the following table shows how the Execution state is determined.

Exception level taken to:  Exception state determined by:
Non-secure EL1   HCR_EL2.RW
 Secure EL1  SCR_EL3 or HCR_EL2 if Secure EL2 is enabled
 EL3  Reset state of EL3
Returning from an exception

Software can initiate a return from an exception by executing an ERET instruction from AArch64. This will cause the Exception level returned to be configured based on the value of SPSR_ELx, where <x> is the level being returned from. SPSR_ELx contains the target level to be returned to and the target Execution state.

Note that the Execution state specified in SPSR_ELx must match the configuration in either SCR_EL3.RW or HCR_EL2.RW, or this will generate an illegal exception return.

On execution of the ERET instruction, the state will be restored from SPSR_ELx, and the program counter will be updated to the value in ELR_ELx. These two updates will be performed atomically and indivisibly so that the PE will not be left in an undefined state.

Exception stacks

When executing in AArch64, the architecture allows a choice of two stack pointer registers; SP_EL0 or SP_ELx, where <x> is the current Exception level. For example, at EL1 it is possible to select SP_EL0 or SP_EL1.

During general execution, it is expected that all code uses SP_EL0. When taking an exception, SP_ELx is initially selected. This allows a separate stack to be maintained for initial exception handling. This is useful for maintaining a valid stack when handling exceptions caused by stack overflows.

Previous Next