ARM Cortex-M processors support two main modes of operation to separate application-level code from system-level (privileged) operations. This is crucial for building safe and secure embedded systems.
1. Thread Mode
-
Default execution mode
-
Used by:
-
Application-level code
-
main()function and background tasks
-
-
Can run in either:
-
Privileged mode (full access)
-
Unprivileged mode (restricted access)
-
2. Handler Mode
-
Entered automatically when an exception or interrupt occurs
-
Always runs in Privileged mode
-
Used by:
-
Interrupt Service Routines (ISRs)
-
Fault handlers (e.g. HardFault, MemManage, etc.)
-
System-level operations (e.g. PendSV, SysTick)
-
Why Separate Modes?
Certain instructions like disabling interrupts, accessing system control registers, or performing privileged memory operations can compromise system stability or break critical services if misused.
By separating modes:
-
We protect the kernel/system from faulty or malicious application code
-
We enforce privilege levels, supporting a minimal security boundary even in bare-metal systems
Privilege Levels
| Privilege Level | Description | Allowed Mode(s) |
|---|---|---|
| Privileged | Full access to all instructions, system control space, and memory regions | Thread & Handler |
| Unprivileged | Limited access. Cannot disable interrupts or access system control | Thread only |
Unprivileged code is typically application-level logic, while the kernel, ISRs, and system services run as privileged.
Mode Switching

-
The CPU starts in Thread Mode, running user code.
-
When an interrupt or exception occurs:
-
The core automatically switches to Handler Mode
-
Saves context to the stack
-
Executes the ISR or handler
-
-
Upon
BX LRor return-from-exception:- The CPU restores context and switches back to Thread Mode
Register Banking
What is Register Banking?
Register banking is a technique where certain registers are swapped or replaced depending on the mode.
In Cortex-M, the only banked register is the Stack Pointer (SP).
| Register | Banked? | Notes |
|---|---|---|
| R0–R12 | ❌ | Shared across modes |
| R13 (SP) | ✅ | Separate for each stack mode |
| R14–R15 | ❌ | LR (link register) and PC shared |
The Two Stacks: MSP and PSP
ARM Cortex-M has two stack pointers, both pointing to separate stacks in memory:
| Stack Pointer | Name | Used By |
|---|---|---|
| MSP | Main Stack Pointer | Handler Mode + default Thread Mode |
| PSP | Process Stack Pointer | Thread Mode (if configured) |
Why Two Stacks?
- To separate application tasks from system context.
- Prevents corruption of ISR stack space by untrusted or buggy application code.
- Allows an RTOS to:
- Use PSP for tasks
- Use MSP for system-level and interrupt handling This structure supports safe preemption, clean context switching, and modular RTOS design.