10.1. Exception handling registers

Chapter 4 describes how the current state of the processor is stored within separate PSTATE fields. If an exception is taken, the PSTATE information is saved in the Saved Program Status Register (SPSR_ELn) which exists as SPSR_EL3, SPSR_EL2 and SPSR_EL1.

Figure 10.2. When exceptions are taken from AArch64

To view this graphic, your browser must support the SVG format. Either install a browser with native support, or install an appropriate plugin such as Adobe SVG Viewer.


Figure 10.3. When exceptions are taken from AArch32

To view this graphic, your browser must support the SVG format. Either install a browser with native support, or install an appropriate plugin such as Adobe SVG Viewer.


The SPRSR.M field (bit 4) is used to record the execution state (0 indicates AArch64 and 1 indicates AArch32).

Table 10.1. PSTATE fields

PSTATE fieldsDescription
NZCVCondition flags
QCumulative saturation bit
DAIFException mask bits
SPSelSP selection (EL0 or ELn), not applicable to EL0
EData endianness (AArch32 only)
ILIllegal flag
SSSoftware stepping bit

The exception bit mask bits (DAIF) allow the exception events to be masked. The exception is not taken when the bit is set.

D

Debug exceptions mask.

A

SError interrupt Process state mask, for example, asynchronous External Abort.

I

IRQ interrupt Process state mask.

F

FIQ interrupt Process state mask.

The SPSel field selects whether the current Exception level Stack Pointer or SP_EL0 should be used. This can be done at any Exception level, except EL0. This is discussed later in the chapter.

The IL field, when set, causes execution of the next instruction to trigger an exception. It is used in illegal execution returns, for example, trying to return to EL2 as AArch64 when it is configured for AArch32.

The Software Stepping (SS) bit is covered in Chapter 18 Debug. It is used by debuggers to execute a single instruction and then take a debug exception on the following instruction.

Some of these separate fields (CurrentEL, DAIF, NZCV and so on) are copied into a compact form in SPSR_ELn when taking an exception (and the other way around when returning).

When an event which causes an exception occurs, the processor hardware automatically performs certain actions. The SPSR_ELn is updated, (where n is the Exception level where the exception is taken), to store the PSTATE information required to correctly return at the end of the exception. PSTATE is updated to reflect the new processor status (and this may mean that the Exception level is raised, or it may stay the same). The return address to be used at the end of the exception is stored in ELR_ELn.

Figure 10.4. Exception handling

To view this graphic, your browser must support the SVG format. Either install a browser with native support, or install an appropriate plugin such as Adobe SVG Viewer.


Remember that the _ELn suffix on register names denotes that there are multiple copies of these registers existing at different Exception levels. For example, SPSR_EL1 is a different physical register to SPSR_EL2. Additionally, in the case of a synchronous or SError exception, ESR_ELn is also updated with a value which indicates the cause of the exception.

The processor has to be told when to return from an exception by software. This is done by executing the ERET instruction. This restores the pre-exception PSTATE from SPSR_ELn and returns program execution back to the original location by restoring the PC from ELR_ELn.

We have seen how the SPSR records the necessary state information for an exception return. We will now look at the link register(s) used to store the program address information. The architecture provides separate link registers for function calls and for exception returns.

As we saw in Chapter 6 The A64 instruction set, register X30 is used (in conjunction with the RET instruction) to return from subroutines. Its value is updated with the address of the instruction to return back to, whenever we execute a branch with link instruction (BL or BLR.)

The ELR_ELn register is used to store the return address from an exception. The value in this register (actually several registers, as we have seen) is automatically written upon entry to an exception and is written to the PC as one of the effects of executing the ERET instruction used to return from exceptions.

Note

When returning from an exception, you will see an error if the value in the SPSR conflicts with the settings in the System Registers.

ELR_ELn contains the return address which is preferred for the specific exception type. For some exceptions, this is the address of the next instruction after the one which generated the exception. For example, when an SVC (system call) instruction is executed, we simply wish to return to the following instruction in the application. In other cases, we may wish to re-execute the instruction that generated the exception.

For asynchronous exceptions, the ELR_ELn points to the address of the first instruction that has not been executed, or executed fully, as a result of taking the interrupt. Handler code is permitted to modify the ELR_En if, for example, it was necessary to return to the instruction after an aborting a synchronous exception. The ARMv8-A model is significantly simpler than that used in ARMv7-A, where for backward compatibility reasons, it was necessary to subtract 4 or 8 from the Link register value when returning from certain types of exception.

In addition to the SPSR and ELR registers, each Exception level has its own dedicated Stack Pointer register. These are named SP_EL0, SP_EL1, SP_EL2 and SP_EL3. These registers are used to point to a dedicated stack that can, for example, be used to store registers which are corrupted by the exception handler, so that they can be restored to their original value before returning to the original code.

Handler code may switch from using SP_ELn to SP_EL0. For example, it may be that SP_EL1 points to a piece of memory which holds a small stack that the kernel can guarantee to always be valid. SP_EL0 might point to a kernel task stack which is larger, but not guaranteed to be safe from overflow. This switching is controlled by writing to the [SPSel] bit, as shown in the following code:

  MSR SPSel, #0  // switch to SP_EL0
  MSR SPSel, #1  // switch to SP_ELn
Copyright © 2015 ARM. All rights reserved.ARM DEN0024A
Non-ConfidentialID050815