Continuing our series on interrupts, this blog will capture the ARM interrupt architecture along with the evolution of the same from the early ARMv4 to the latest ARMv8 models. A fair outline of overall flow, including the exception/ registers model, is given to aid the reader understand the principles behind the ARM interrupt architecture design.
ARM Instruction Set
ARM architecture has continuously evolved since its introduction. Beginning with ARMv4, architecture evolution is labeled with incremental values like ARMv5, ARMv6 till the latest ARMv8. There are additions and extensions that are labeled with a suffix like ARMv5TE or ARMv6K.
As with any RISC core, ARM supports very few instructions and is capable of executing them fast at a rate of 1 instruction per clock using techniques such as pipelining, branch prediction, caching etc.
Many RISC architectures define a set of instructions and encoding that will be executed by the processor. But ARM Architecture is an advanced design that supports different instruction sets that can be changed dynamically. Each of these instruction execution modes offer unique advantage like higher code density, support for Java execution etc. Few of the instruction sets supported are
ARM: The default mode that operates with fixed width (32-bit) instructions. Automatically changed to this mode when an interrupt/exception occurs.
Thumb: It is a 16-bit instruction set that can be used for higher code density. It is has limited set of instructions and registers compared to ARM mode, but can be advantageous if limited register manipulations are done.
Thumb2: Introduced in ARMv6T2, this brings the best of both worlds, by supporting mixed 16 bit and 32 bit instructions able to achieve very higher code density and performance. This has become popular that modern OS like Windows Embedded Compact has made this the default execution mode. Even Linux kernel supports compilation to Thumb2 mode.
Jazelle: Optimized for Java code execution.
SIMD: Single Instruction Multiple Data instruction set for better data manipulation.
There are other sets like VFP, Security extension etc that are not explained in this blog. It is interesting to note that these instructions sets can be interchangeably used as switching from one to another is as simple as setting one or more bits is a register, that can be accomplished by a single instruction.
With ARMv8, two higher level Execution States are introduced – AArch32 and AArch64. While the AArch32 is mostly similar to the instructions sets in the earlier architectures, AArch64 supports a single 64 bit instructions set and registers. It is possible to transition between these during exceptions by a process called Interprocessing.
ARM Processor Modes and Exception Levels
While the instruction sets define the type of instructions supported, ARM core supports multiple modes that defines how the access privilege, current exception taken etc. The processor modes supported are
|User||Mode with minimal access privilege. It is not possible to change to other modes from this mode. In an OS, generally the applications are executed in this mode|
|FIQ||Entered up on an Fast Interrupt being received|
|IRQ||Entered up on an Interrupt being received|
|Supervisor||Same set of register visibility as in User mode but with higher privileges|
|Monitor||Part of security extension that can be used during transition from a Secure Mode to Non-secure mode.|
|Abort||Entered when there is an error accessing data memory(Data Abort) or instruction area (Prefetch abort)|
|Undefined||Entered when a wrong instructions is executed|
|System||Mode that has full privileges that can be used to configure the system. Usually the kernel operates in this mode in an OS.|
Of these modes, except User mode, all others are said to be privileged modes. Usually the transition between these modes is done primarily with exceptions and in limited case, with instructions.
AArch64, introduces four Exception levels, represented by ELn, that is used to determine the level of privilege. EL0 is the least privileged while EL3 is the most. The recommended usage model for the same are:
It is key to remember that the AArch32 mode processor states are still usable when executing in that.
ARM Register Model
It is generally known that there are 16 general purpose registers (R0 through R12, R13 (Stack Pointer), LR (Link Register) and PC) and two Program Status Registers (CPSR and SPSR). But few of these registers are actually banked and different registers are available for different processor modes. The register bank in AArch32 state as given in ARMv8 TRM is given below:
Based on the current processor mode, the registers are visible to software access. i.e. if the processor is in Supervisor mode, reading R13 will return SP_svc where as access to R13 will return SP_irq in IRQ mode. For FIQ mode, lot more registers are banked enabling fewer stack push/pops for faster interrupt processing. Also, since the FIQ vector is at the end of the vector table, the handler (ISR) can be directly placed at the FIQ vector address rather than having a branch to ISR instruction as in case of other exceptions.
In AArch64 mode, there are 31 64-bit general purpose registers labeled XL0 to XL30. XL30 is generally used as Procedure Link Register. None of these are banked. But there are few registers that are banked for each Execution level – Stack Pointer (SP), the Exception Link Register (ELR) and the Saved Process State Register (SPSR). To enable access of AArch32 registers from AArch64 state, the AArch32 registers are mapped to lease significant 32-bits of the AArch64 registers. The mapping of the same as given by ARM is as follows
ARM Exceptions Model
In ARM architecture, anything that affects sequential flow of instructions is called an exception. For example, it could be an occurrence of an interrupt, access of wrong memory or even power-cycling the system. These exceptions are clearly defined along with the specific steps taken on an exception – typically involving change in processor mode and jumping to a vector address. Some of the defined exceptions are
|Exception||Description||Entered Mode||Vector Offset|
|Reset||Entered on power on reset||Supervisor mode||0x00|
|Undefined Instruction||Invalid/Unimplemented instruction||Undefined||0x04|
|Supervisor Call||Usually by SWI/SVC instruction. Used for system call implementation||Supervisor||0x08|
|Secure Monitor Call||Usually by SMC/SMI instruction.||Monitor||0x08|
|Prefetch Abort||Invalid instruction memory access||Abort||0x0C|
|Data Abort||Invalid Data memory access||Abort||0x10|
|IRQ||Interrupt request to the core||IRQ||0x18|
|FIQ||FIQ request to core||FIQ||0x1C|
When any of these exceptions occurs in an ARM core, following set of sequences happens:
- CPSR is copied to the SPSR of the mode being entered.
- Processor mode is set to the new state
- Whatever the existing instruction set being executed, it is changed to ARM state
- Return address (of mode being left) is stored to the link register of the mode being entered
- PC is set to the vector address corresponding to the entered exception
Now that the processor is in the new exception mode, the corresponding registers are banked. The software can choose to handle the exception as desired. Care should be taken that no registers are corrupted or lost, due to multiple or nested exceptions. Registers can be backed up in the stack.
To return back to the interrupted code, following operations can be done:
- Restore the registers back to the original values (by popping from stack)
- The above process can be done using a single instruction LDMFD^ if possible.
For AArch64, numerous exception classes are defined that are source of the exceptions like WFI, Illegal execution state, Misaligned PC Exception etc. The cause of exception can be obtained from the Exception Syndrome Register (ESR). The major happenings on an exception entry, as given by ARMv8 TRM,
- The PE state is saved in the SPSR_ELx at the Exception level the exception is taken to.
- The preferred return address is saved in the ELR_ELx at the Exception level the exception is taken to.
- Execution moves to the target Exception level, and starts at the address defined by the exception vector.
- The stack pointer register selected is the dedicated stack pointer register for the target Exception level.
To return from exception, an ERET instruction can be used. On executing the same:
- PC is restored with the value held in the ELR_EL of level returning from.
- PSTATE is restored by using the contents of the SPSR_EL of level returning from.
It is possible to switch from AArch64 to AArch32 states using exceptions.
Thus ARM Architecture is evolving fast to accommodate the growing requirements in computing. Now with basic idea about, the instruction set, register sets and exception model in ARM architecture, we will see about the Interrupt Architecture in specific in the upcoming blog.