- General-purpose registers r0–r12 (13 registers, shared across modes)
- SP — the banked SVC-mode stack pointer (
sp_svc) - LR — the banked SVC-mode link register (
lr_svc) - PC — the next instruction to execute
- SPSR — the saved CPSR (processor mode, flags, interrupt mask) of the interrupted process
Process PCB struct.
ARM banked registers
ARM Cortex-A cores bank certain registers per processor mode. IRQ mode has its own privatesp_irq and lr_irq that are invisible when the CPU runs in SVC mode, and vice versa. Registers r0–r12 are shared across all modes. This property is exploited during the context switch: r0–r12 are read from the IRQ stack (where they were pushed at handler entry), then the CPU switches temporarily to SVC mode to access the process’s banked sp_svc and lr_svc.
Preemptive IRQ-driven context switch
The full switch is implemented inirq_handler in root.s. It executes in 12 distinct stages:
Save r0–r12 and LR on the IRQ stack
root.s
r0–r12 and lr_irq are stored contiguously. lr_irq holds PC_interrupted + 4 (ARM IRQ pipeline behaviour).Load the CurrProcess pointer
root.s
CurrProcess global is loaded, then dereferenced to obtain the PCB pointer. If it is NULL the register-save block is skipped (safety guard).Copy r0–r12 from IRQ stack into PCB
root.s
r[] array in the PCB.Save SPSR into PCB
root.s
spsr_irq contains the CPSR that was automatically saved by hardware when the IRQ was taken. It reflects the mode and flags of the interrupted process.Compute and save the interrupted PC
root.s
lr_irq = PC_interrupted + 4. Subtracting 4 recovers the actual next instruction. That corrected value is written to PCB.pc.Switch to SVC mode and save sp_svc / lr_svc
root.s
sp_svc and lr_svc are banked, they are only visible while in SVC mode. The CPU mode is switched momentarily, the two registers are stored into the PCB, then IRQ mode is restored.Acknowledge the timer interrupt
root.s
Call schedule() to select the next process
root.s
schedule() re-enqueues the current process and dequeues the next one, updating the CurrProcess global.Load the new CurrProcess pointer
root.s
schedule() returns, CurrProcess points to the newly selected process. Its PCB is loaded into r4.Set lr_irq to the new process's PC and restore SPSR
root.s
lr_irq (the banked IRQ link register) is set to the new process’s saved PC. spsr_irq is loaded with the new process’s saved CPSR so that movs pc, lr restores the correct processor mode atomically.Switch to SVC to restore sp_svc and lr_svc, then return to IRQ
root.s
lr_irq is not disturbed because it is a separate banked register.Restore r0–r12 and atomically jump to the new process
root.s
r4 is advanced to the start of the r[] array in the PCB and ldmia loads all 13 registers in one instruction (overwriting r4 with its correct saved value in the process). Finally, movs pc, lr simultaneously sets PC to lr_irq (the new process’s entry point) and restores CPSR from spsr_irq (the new process’s saved flags and mode).The movs pc, lr trick
movs pc, lr is a privileged-mode data-processing instruction with the S-bit set. In privileged modes, the S-bit on a PC-write causes the processor to copy SPSR into CPSR. This makes the operation atomic: the new PC and the new CPSR are applied in a single cycle, with no window where the processor is in a partially-restored state.
On ARMv7-A this idiom is architecturally valid only in privileged modes (SVC, IRQ, FIQ, etc.). User-mode code must use a different return sequence.
Voluntary context switch: yield()
yield() allows a process to voluntarily surrender the CPU from SVC mode without waiting for the next timer tick. The save sequence mirrors the IRQ handler but does not need to read banked IRQ registers:
root.s
- Registers are pushed onto the SVC stack (no mode switch needed to read them).
- The saved PC is taken from the pushed
lrvalue, which is the return address from thebl yieldcall site — no- 4adjustment is needed. CPSRis saved directly as the process’s SPSR (no separatespsr_irqinvolved).- The restore path does not need to touch
lr_irqbecause there is no IRQ bank in play;movs pc, lrstill works identically to restore CPSR fromspsr_cxsf.