AArch64/ARM64 Tutorial

Chapter 18: Exception Basics, Exception Levels

We call a CPU crash an Exception. However, not all Exceptions are CPU crashes. There are only 2 methods to stop the regular execution flow of the CPU. That is Branches and Exceptions. With Branches, you can see how the direction of the execution flow will change. The change is predictable.

With Exceptions, it's wildly different. General speaking, for most cases, an exception occurs "out of nowhere". Not that it is random, but exceptions will override the execution flow of the CPU regardless of where the program is currently executing at.

There are two types of Exceptions:

Synchronous Exceptions are exceptions that are directly caused by an instruction. For example, let's say we have a store instruction where the Effective Address is an invalid memory address. When that store instruction gets executed, a Synchronous exception will occur. Regular execution flow of the CPU is redirected to an exception handler that handles Synchronous type exceptions.

Asynchronous Exceptions are exceptions that are not directly associated with the current instruction. An example of this is a hardware timer. Such a timer can be set to a value and decrement while a program is running. Once the timer hits 0, an exception will be taken. Regular execution flow of the CPU is redirected to an exception handler that handles Asynchronous types exceptions.

For ARMv8 these are the following synchronous exceptions...

Invalid Instruction:
Obviously, if an invalid instruction gets executed, an exception will occur.

Trap Instruction:
Certain SPRs can be configured to where a float or vector based instruction will force an exception. This is called trapping.

Memory Access Fault:
For when an invalid or restricted memory address is referenced via a load or store.

Exception Generating Instructions:
This is for the svc (supervisor call), hvc (hypervisor call), or smc (secure monitor call) instructions. 

Debug Exceptions:
This is for things such as Breakpoints that are used to find a bug within a program.

Other:
This will include execution at an improper Exception level (we will cover Exception levels shortly), and this includes misalignment of the SP or PC.


For the Asynchronous exceptions, they are first broken up into 3 sub groups:

IRQ/vIRQ is an interrupt request from an external device (such as a hardware timer). This is known as an External Interrupt.

FIQ/vFIQ is a fast interrupt request. This will also be from some external source. It takes priority over IRQ/vIRQ and is meant to complete an interrupt request faster than IRQ/vFIQ.

SError/vSError is basically an "oh shit" exception. Usually this is due to a memory access that should be successful (according to all checks by the CPU), but the access still fails.

The "v" in the naming scheme refers to virtual. We're not going to dive into Virtual vs Physical interrupts as this is extremely nuance. 


We do need to cover Exception levels. There are 4 exception levels (EL's)

Whenever any ARMv8 CPU boots, it is in EL3. Its CRUCIAL to understand that a CPU can willingly go down a EL level, but *never* up. The only way for a CPU to reach a higher EL than its current EL, is thru an Exception.

Example: The CPU is executing in EL0. It executes a svc instruction. An exception is taken and the CPU is now in EL1. Fyi, hvc is used to go from EL1 -> EL2, and smc is used to go from EL2 -> EL3.

With this being said, EL's help the CPU stay secure. A program can be written to write out all the code to handle exceptions, then make the Memory Region holding that code be inaccessible to the lower ELs. The environment has now been secured.

When in EL0 (user mode), you cannot write to any of the SPRs, and most of them cannot even be read. Attempting reading/writing will result in an exception. You also cannot mask (disable) externel interrupts. Regardless of what EL you are in, you can always get your EL level with this instruction...

mrs xD, CurrentEL

The CurrentEL register holds well... your current EL ofc. bits 3 & 2 hold the EL value. The rest of the bits in the register are always Zero.

CurrentEL values:

We will have to wrap up this chapter. The Exception Model for ARMv8 is incredibly complex. It would take 5+ Chapters alone to cover it piece by piece.

The goal is to make sure you have a super beginner understanding of Exceptions + EL's.


Next Chapter

Tutorial Index