You copied the Doc URL to your clipboard.

Exception handlers

The processor handles exceptions using Interrupt Service Routines (ISRs), fault handlers, and system handlers.

Interrupt Service Routines

Handle interrupt exceptions for IRQ0-IRQ239.

Fault handlers

Handle fault exceptions for HardFault, MemManage fault, UsageFault, and BusFault.

System handlers

Handle system exceptions for NMI, PendSV, SVCall, SysTick, and system faults.

Writing exception handlers

Programmers should note the following points when writing exception handlers for the ARMv8-M processor in C code or Assembly language.

The following general points should be noted when writing exception handlers:

  • The ARMv8-M NVIC supports level-sensitive and pulse-sensitive IRQs. For interrupt sources that generate level-sensitive requests, clear the interrupt source. Some system handlers, such as SysTick, do not need to be cleared.
  • Be careful of Main stack overflows. Take care with the additional stack requirements on the Secure Main stack in systems that support both Secure and Non-secure interrupts.
  • There is no requirement to set the STKALIGN bit as in ARMv7‑ Bit[9] in the Configuration and Control Register is a RES1 bit.

The following points should be noted if writing exception handlers in C code:

  • The ISR function must be type void and cannot accept arguments.
  • The __irq keyword is optional but is recommended for clarity. For example,

__irq void SysTickHandler (void) { }

  • No special assembly language entry or exit code is required.

The following points should be noted if writing exception handlers in Assembler language:

Handlers must manually save and restore any non-scratch registers which are used, such as R4­R11, and the LR.

  • Handlers must maintain 8-byte stack alignment if making function calls.
  • Handlers must return from interrupt using EXC_RETURN with the proper instruction.
    • LDR PC
    • LDM and POP, which includes loading the PC
    • BX LR

Preemption

When the processor is executing an exception handler, an exception can preempt the exception handler if its priority is higher than the priority of the exception being handled.

Processor preemption is based around the execution Priority Level. To determine the current priority level, one has to check the IPSR register. If no interrupt is active (IPSR[ISR_NUMBER=0]), then the priority is the value stored in BASEPRI. If an interrupt is active, then the priority is determined by reading the priority bits of the active interrupt (IPSR[ISR_NUMBER]).

At reset the core has a priority level of MAX_LEVEL+1 (256). This means that any enabled interrupt (with even the lowest priority level) which is asserted will interrupt the core.

If an exception occurs with the same priority as the exception being handled, the handler is not preempted, irrespective of the exception number. However, the status of the new interrupt changes to pending.

When one exception preempts another the exceptions are called nested exceptions.

For example, consider the following exceptions where all have software configurable priority numbers:

  • A has the highest priority.
  • B has medium priority.
  • C has lowest priority.

Example sequence of events:

  1. Exception B occurs. The processor takes the exception and starts executing the handler for this exception. The execution priority is priority B.
  2. Exception A occurs. Because its priority is higher than the execution priority, it preempts exception B and the processor starts executing the Exception A handler. Execution priority is now priority A.
  3. Exception C occurs. Its priority is less than the execution priority so its status is pending.
  4. The handler for exception A reduces the priority of exception A, to a priority lower than priority C. The execution priority falls to the highest priority of all active exceptions. This is priority B.

Exception C remains pending because its priority is lower than the current execution priority.

Only a pending exception with higher priority than priority B can preempt the current exception handler. Therefore, a new exception with lower priority than exception B cannot take precedence over the preempted exception B.

Late-arriving

The late-arriving mechanism speeds up preemption. If a higher priority exception occurs during state saving for a previous exception, the processor switches to handle the higher priority exception and initiates the vector fetch for that exception. It is IMPLEMENTATION DEFINED whether a processor does this.

There are several combinations of security states where the state saving might be affected by a late-arriving interrupt.

If a higher priority late-arriving Secure exception occurs during entry to a Non-secure exception when the Background Security state is Secure, it is IMPLEMENTATION DEFINED whether the stacking of the additional state context is rolled back.

The processor can accept a late arriving exception until the first instruction of the exception handler of the original exception enters the execute stage of the processor. On return from the exception handler of the late-arriving exception, the normal tail-chaining rules apply.

Tail-chaining

The ARMv8-M architecture tail-chaining mechanism speeds up exception servicing. On completion of an exception handler, if there is a pending exception that meets the requirements for exception entry, the stack pop is skipped and control transfers to the new exception handler.

Exception entry

Exception entry occurs when there is a pending exception with higher priority than the currently-executing context, in which case the new exception preempts this context.

Sufficient priority means that the exception has more priority than any limits set by the mask registers. An exception with less priority than this is pending but is not handled by the processor.

When the processor takes an exception, unless the exception is a tail-chained or a late-arriving exception, the processor pushes information onto the current stack. This operation is called stacking and the block of data written to the stack is referred as the stack frame. The basic stack frame contains eight words of data.

When using floating-point routines, or where an exception causes a change of security state, the processor might automatically stack additional registers to form an extended stack frame.

Note

Where stack space for floating-point state or security state is not allocated, the stack frame is the same as that of ARMv8-M implementations without an FPU.

Immediately after stacking, the Stack Pointer indicates the lowest address in the stack frame. ARMv8-M requires that the stack frame is doubleword-aligned, and will automatically decrement the stack pointer if necessary to enforce this.

The stack frame includes the return address. This is the address of the next instruction in the interrupted program. This value is restored to the PC at exception return so that the interrupted program resumes.

In parallel to the stacking operation the processor performs a vector fetch that reads the exception handler start address from the vector table. When stacking is complete, the processor starts executing the exception handler. At the same time, the processor writes an EXC_RETURN value to the LR. This indicates which Stack Pointer corresponds to the stack frame and what operational mode the processor was in before the entry occurred.

If no higher priority exception occurs during exception entry, the processor starts executing the exception handler and automatically changes the status of the corresponding pending interrupt to active.

If another higher priority exception occurs during exception entry, the processor starts executing the exception handler for this exception and does not change the pending status of the earlier exception. This is the late arrival case.

When an exception occurs the processor automatically transitions to the security state associated with that exception. This transition avoids the need for an SG instruction at the start of the Secure exception handlers, which would result in them being directly callable from the Non-secure state. If the exception and the exception vector target address are associated with different security states, a SecureFault is raised unless the exception is associated with the Non-secure state and targets an SG instruction. The Baseline profile has no SecureFault, so uses a HardFault exception instead.

Stack frame

For processors that do not implement the Security Extension, the stack frame format is divided into two sections, integer caller saved, and floating-point caller saved registers. To accommodate the additional state that must be preserved when an exception causes a transition from the Secure to the Non-secure state the format is extended.

The only mandatory section of the stack frame is the integer caller saved registers, with all other sections being optionally created depending on the state transitions being performed. ARMv8-M-profile cores contain hardware to automatically stack and unstack the caller saved register state around exceptions, as defined in the ARM procedural calling standard. This reduces interrupt latency and enables extra optimizations like tail chaining. The approach taken by the ARMv8-M architecture with Security Extension is to extend this mechanism to stack extra register contents if an exception causes a transition from the Secure to the Non-secure state. Some events also cause the processor to clear the registers. This prevents Secure data being visible to a Non-secure exception handler.

The following figure shows the structure of the stack frame:

stack_frame.png

Stack limit

Multiple nested interrupts or other techniques might be used to overflow the Secure stack, and therefore potentially overwrite other Secure data in memory.

To protect against this possibility, there are two stack limit registers, MSPLIM_S and PSPLIM_S. These registers limit the extent to which the Main and Process Secure Stack Pointers respectively can descend. Violation of the stack limit raises a synchronous UsageFault.

The ARMv8-M architecture with Main Extension also provides Non-secure stack limit registers.

Exception return

An exception return occurs when the processor is in Handler mode and executes a suitable instruction that loads the EXC_RETURN value into the PC.

An exception return also occurs when there is no pending exception with sufficient priority to be serviced and the completed exception handler was not handling a late-arriving exception.

The processor pops the stack and restores the processor state to the state it had before the interrupt occurred.

Any of the following instructions cause an exception return when the processor is in Handler mode:

  • An LDM or POP instruction that loads the PC.
  • An LDR instruction with PC as the destination.
  • A BX instruction using any register.

Exception type

Value of ReturnAddress

NMI

Next instruction to be executed

(Allows return after handling the NMI)

Hardfault (precise)

Instruction causing the fault

(Usually a fatal error so return is unlikely)

Hardfault (imprecise)

Next instruction to be executed

(Usually a fatal error so return is unlikely)

IRQ

Next instruction to be executed

(Allows return after handling the IRQ)

SVC

Next instruction after the SVC instruction

(allows return after handling the SVC)

SysTick (SysTick included)

Next instruction to be executed

(Allows return after handling the SysTick)

PendSV

Next instruction to be executed

(Allows return after handling the PendSV)

The processor can also return from an exception with the following instructions when the PC is loaded with the value 0xFFFF_FFxx (EXC_RETURN). However, the value of 0xFFFF_FFxx is an illegal address for execution (execute never memory). 

The core only uses this to identify that it is returning from an exception.

Was this page helpful? Yes No