ARM modes and why are there so many? - arm

I'm currently reading/learning about ARM architecture ...
and I was wondering why there are so many modes
(FIQ, User, System, Supervisor, IRQ, ...).
My question is why do we need so many modes? Wouldn't just User and System be enough?
Thanks in advance.

It's just an architectural decision. The big advantage of the multiple modes is that they have some banked registers. Those extra registers allow you to write much less complicated exception routines.
If you were to pick only two, just USR and SYS are probably as good a choice as any, but what would happen when you took an exception? The normal ARM model is to go to an exception mode, set the banked link register for that exception mode to point to the instruction you want to return to after you resolve the exception, save the processor state in the exception mode's SPSR register, and then jump to the exception vector. USR and SYS share all their registers - using this model, you'd blow away your function return address (in LR) every time you took an interrupt!
The FIQ mode in particular has even more banked registers than the other exception modes. Those extra registers are in keeping with the "F" part of FIQ - it stands for "Fast". Not having to save and restore more processor context in software will speed up your interrupt handler.

Not too much to add to Carl's answer. Not sure what family / architecture of ARM processors you're talking about, so I'll just assume based on your question (FIQ, IRQ, etc.) that you're talking about ARM7/9/11. I won't enumerate every difference between every mode in every ARM architecture variant.
In addition to what Carl said, a few other advantages of having different modes for different circumstances:
for example, in the FIQ, you don't have to branch off right away, you can just keep on executing. With other exceptions you have to branch right away
with different modes, you have natural support for separate stacks. If you're multitasking (e.g., RTOS) and you don't have a separate stack when you're in an interrupt mode, you have to build-in extra space onto each task stack for the worst-case interrupt situation
with different modes, certain registers (e.g. CPSR, MMU regs, etc. - depends on architecture) are off-limits. Same thing with certain instructions. You don't want to let user code modify privileged registers, now do you?

Related

ARM modes when context switching a user process running on guest

It is my understanding (from this article) that on ARM, the hypervisor/VMM runs in HYP mode, the guest OS runs in SVC mode, and user processes on the guest run in USR mode.
When there is a context switch in the guest OS, say switching from one user process to another, does this trap all the way up to the VMM in HYP mode? And if so, what happens at each stage of the process, going from USR to to SVC to HYP modes?
Short answer: depends on the hypervisor, architecture permits both approaches.
A context switch on ARM would be switching the Page Table and invalidating the TLB.
To switch Page Table, you need to modify the register TTBR0 (user-space part) or TTBR1 (kernel-space. normally for Linux it never changes but some exotic OS might be different) which are accessed via the "co-processor" instructions.
To set TTBR0 you use the instruction "MRC" with CRn = 2.
Such coprocessor accesses can be trapped by a HYP, but not necessarily. It depends on whether you request them to be trapped or not. This is set in the "Hypervisor System Trap Register" (HSTR_EL2 on aarch64).
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488d/CIHJFIHA.html
TLB invalidation instructions and cache maintenance operations are also implemented as coprocessor access instructions on ARMv7 (technically also on ARMv8 but the Architecture Reference Manual suggests to use human-readable mnemonics instead). For example, "TLBIALL" is coprocessor CRn8 so you need to set bit T8 in HSTR_EL2.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0438i/CIHECHCD.html

ARM Banked register

In ARM there is a concept of Banked Register. While reading many questions and their answer and various other resources about what is Banked mean here. Then I got this definition:
Register banking refers to providing multiple copies of a register at the same address. Not all registers can be seen at once.
But my query here is that How multiple copies of registers are created. Because we have single register file in our core. And if there is another mode then it will get the new copy of the banked register that will not contain any data and not going to access the data of another mode register.
Then how this copy of register is created?
Register banking refers to providing multiple copies of a register at the same address. Not all registers can be seen at once.
This is some what correct. However, the register does not have a 'traditional address'. The majority of the arm instructions or 'binary encodings' have register as source or destination arguments. There are sixteen base register so four bits are needed for each register in a binary instruction. A typical instruction takes 12 bits (out of 32bits) to describe the three registers (two source and one destination). These bits in the instruction are the 'address' in the definition above.
But my query here is that How multiple copies of registers are created. Because we have single register file in our core. And if there is another mode then it will get the new copy of the banked register that will not contain any data and not going to access the data of another mode register. Then how this copy of register is created?
They are not 'created' dynamically. The banked registers are part of the 'register file' of the core and always exist. The issue is that the typical instructions can not access some banked registers unless a 'mode switch' occurs. This maybe from user to IRQ mode or from normal to secure world with trustzone.
So running the same code in different modes may end up accessing different (banked) registers. In this way, user code never affects the IRQ stack and vice-versa. Perhaps more importantly, the IRQ code could corrupt non-banked user registers if careful context saving is not performed at the start and end of an IRQ.
See: Accessing banked registers on ARM for information on how you might access these different registers.
The newer ARMv7 instruction mrs r2,sp_svc breaks this banked register rule and allows access to the banked registers directly without switching a mode. the intent is to allow context switching code to easily access the banked registers for saving and restoring without a mode switch.
The traditional instruction ldm rN, {sp,lr}^ allows saving of user stack pointer and link register without switching modes. Again, this has a special encoding (or addressing as per your definition).
Banking is also done with CP15 system registers in trustzone. TrustZone monitor mode and banked IFSR... maybe interesting for anyone looking at that ARM 'banking' which is conceptually the same as the register banking.
I count 31 registers needed to support the traditional arm. Several r13s and r14s a bunch for FIQ mode. First and foremost you are confusing tasks and modes. At the application level the tasks will all share the same set of registers, there is no banking there, when you switch tasks you have to save registers, the operating system allocates memory for this and for each task switch saves the old tasks registers and restores the next tasks registers.
As far as register banking there are multiple r13s for example. For each access to the register there is more than a simple offset into the register file it also has other inputs, for example
unsigned int get_r13 ( unsigned int mode )
{
switch(mode)
{
case SYS: return r13_sys;
case SVC: return r13_svc;
case ABT: return r13_abt;
case UND: return r13_und;
case IRQ: return r13_irq;
case FIQ: return r13_fiq;
}
}
but in logic although the logic could very well look about the same, that or they take the mode bits and logically convert them into some of the address bits into the register file or a combination thereof.
A single register file does not mean there are only 16 registers (r0-r15, not counting cpsr, etc) in the register file, there are 31 or more depending on whether or not it contains *PSR registers.

ARM HYPERVISOR: Execute single instruction and trap (equivalent of Intel's MTF)

I'm implementing a hypervisor on ARM and I need to know if there's a way to resume (ERET) the guest and trap after a single instruction execution, without depending on the debug architecture (v7.1). I could use a software approach by modifying the next instruction of the guest to a HVC (equivalent of VMCALL on Intel), but I don't know how to handle instructions that cause branching (JMP).
On Intel I could use either the trap flag (=TF bit in RFLAGS, per-OS-thread-context) or the monitor trap flag (=MTF, VT-x feature).
Thank you
EDIT: Clarifications
I want to avoid disassembly/emulation (as much as possible)

What does 'bank'ing a register mean?

Reading 'ARM Architecture' on Wikipedia and found the following statement:
Registers R0-R7 are the same across all CPU modes; they are never
banked.
R13 and R14 are banked across all privileged CPU modes except system
mode.
What does banking a register mean?
Register banking refers to providing multiple copies of a register at the same address.
Taken from section 1.4.6 of the arm docs
The term is referring to a solution for the problem that not all registers can be seen at once.
There is a different register bank for each processor mode. The banked registers give rapid context switching for dealing with processor exceptions and privileged operations.
If your looking for a more theoretical reasoning, I recommend this paper.
Edit: A much deeper answer than mine is given here
When the processor enters an exception, the banked registers are switched automatically with another set of these registers.
Virtually, the exception handler routine doesn't have to save these registers on the stack to prevent them from being clobbered later on (by the exception handler functions). The processor just keeps a safe copy of that set; and will restore the original set on exception return.
This clip explains it well
https://youtu.be/7LqPJGnBPMM?t=1419
Banked registers are registers which are not needed and accessible by the current execution mode. When the execution mode changes, the registers needed for the new mode will become usable.

switching between ARM/THUMB state

Why should an ARM controller return to ARM state from THUMB state, when an exception occurs?
One explanation might be that ARM mode is the CPU's "native" operating mode, and that it's possible to do more operations in that mode than in the limited Thumb mode. The Thumb mode, as far as I've understood, is optimized for code size, which might mean it lacks certain instructions that perhaps are necessary in exception processing.
This page mentions that exception processing is always done in ARM mode. It doesn't provide any reasons why, so maybe it's just The Way It Is, by design. It does talk about ways to exit from exception processing back to the proper (ARM or Thumb) mode though, so as long as you're not writing the exception handler yourself, you might be able to ignore this issue. That, of course, assumes that your system is set up with a "default" exception handler that does retain the execution mode.
On the other hand, this page says this, about the interrupt vectors of the Cortex-M3 ARM implementation:
The LSB of each exception vector indicates whether the exception is to
be executed in the Thumb state.
So it doesn't seem to be universally true, perhaps you can make your particular exception run in Thumb mode.
Perhaps it is because that the interrupt vector table is really an ARM instruction and to process it requires being in ARM mode. This reduces the programmers job as you dont have to write two handlers one for arm mode and one for thumb mode. How would you even know there is one entry point for an exception and you can only have one instruction type to handle it. You can certainly switch to thumb mode once entered no different than switching to thumb mode after a reset exception.
The cortex-m3 has re-defined the interrupt vector table to be more traditional (an address instead of an instruction). By necessity I would assume, the cortex-m3 is a thumb(2) only processor so either they re-define the vector table to hold thumb instructions or they re-define the table with addresses, or they have just enough of an arm core to process the load or jump that you normally see in a vector table entry.
Basically you would either need two entries per exception, one for the arm based handler and one for the thumb based handler or you require the user to write their handler with an entry point that is one mode specifically.
Even with the one mode entry point into a handler, you still have to be aware of the mode the processor was in when the exception occurred to know what address to return to and how to inspect the instruction in question that caused the exception.
It depends which CPU you have, as there are two thumb instruction sets. The original thumb instruction set (used in armv4t, armv5te) lacked instructions to be able to deal with interrupts; the newer thumb2 set (in the cortex series) has extra instructions so you can remain in thumb2 mode to service an interrupt routine.
Traditional ARM systems boot into ARM mode and jumps to reset exception vector after reset. This means that all exception vectors have to be written in ARM assembly. If your exceptions are ARM instructions naturally the CPU is forced to change its mode to ARM mode before exception handling; if this does not happen it will result in an undefined exception, which will cause another one and so on and on in an infinite loop.
Initial ARM systems only had ARM instructions, the THUMB instructions were later added on; this might be another explanation.

Resources