CS 452/652 Spring 2026 - Lecture 5
Context-Switch and System Call
May 27, 2026 prev
AEM - AArch64 Exception Model
Context Switch
- execution state
- high-level language: line, variables (automatic, static, global, heap)
- machine: program counter, stack pointer, other registers, stack content
- data on stack (heap?)
- context = registers + stack
- registers: fast operands for processor operations
- stack: dynamic storage for automatic variables
- stack switch
- save registers (to somewhere) without changing them
- stack switch: save/restore SP register
- restore registers
- mode switch (privilege level) - processor exception
- some state automatically saved
- usually implies stack switch for safety & security
- must save/restore registers after stack switch
System Call
- synchronous exception - this is how a task asks the kernel for something
- dedicated instruction:
svc N
- execution continues (PC) at hard-coded handler (exception vector)
- processor in EL1 using SP_EL1 (assuming SPSel=1)
- ELR_EL1 holds return address (next PC after svc)
- ESR_EL1 holds exception code and N from SVC
- SPSR_EL1 holds processor state from before SVC
- SP is banked SP_EL1 (run with SPSel set to 1)
- C/C++ function call: compiler has saved x0-x18 (as needed)
- what needs to happen next?
- save general-purpose registers
- save ELR_EL1, SP_EL0, SPSR_EL1
- SPSR not strictly needed for system call (ABI rules)
- access to SP_EL0 direct or via SPSel = 0 (temporarily)
- we might not return to same task
- choices for storing user context:
- on user stack, or
- in task descriptor
- restore kernel state
- symmetry: kernel vs. user entry/exit
- kernel entry/exit: syscall vs. irq
- resume user task:
- save kernel context (function call, ABI)
- restore ELR_EL1, SP_EL0, SPSR_EL1
- return from exception:
eret
- restores PC from ELR, pstate from SPSR
- returns to EL0 (then using SP_EL0)
Exception Vector
- kernel-controlled jump destinations for exceptions (see AEM Table 4)
- vectors: VBAR_ELn exceptions to EL n
- 4 groups (from where): Current EL SP0/x, Lower EL 64/32
- 4 vectors (32 instructions): Synchronous, IRQ, FIQ, Error
→ total of 2KB = 4 * 4 * 128 bytes
- recommendation: set up dummy handlers for everything!
System Call Parameters
- example:
int Create(int priority, void (*function)())
- how does the kernel receive the two parameters?
- how does it return the int?
- simple answer: can use the same arg/return conventions established by the ABI
- user task puts params into x0 and x1 before svc
- exception handler saves application context
- kernel can inspect (saved) x0 and x1 to find parameters
- kernel overwrites (saved) x0 with return value before
eret
- after
eret, user task looks in x0 to find result
- system call stubs: create a user-level function corresponding to each system call
Task State
- execution state
- management state: Ready, Active, Blocked, etc.
- management information: parent task
- normally used for group scheduling, termination
- task descriptor: in-kernel data structure holding task state
- queues for scheduling and blocking
- task-shared memory: code, readonly data
- task-private memory on stack
- ok to use static global for singleton tasks with subroutines
- ok to use static global for boot-time write-once configuration constants
- do not share other memory between tasks!
Task Creation
Kernel Initialization
- initially in boot.S:
- sets up EL1 stack pointer, masks interrupts, jumps to kmain
- what else needs to happen?
- need to initialize exception vector
- need to initialize any kernel data structures
- need to create an initial task, and context switch to it
- initial task will need to run some user-level function, at some priority
- hard code function pointer into kernel
- set up new task context to be the "saved" context for user task
- return from exception (restore user context, then
eret)
Memory Management
- dynamic data structures without heap
- intrusive linkage, i.e., embed next (and/or other) pointers in data structure
- slab allocation: dedicated memory region (array of objects) for each data type
- store freed objects in free list, use intrusive overlay (cast/union) to manage
- allocate first from free list, then from slab
- can use C++ templates (and inheritance) for elegant implementation
Additional Information
An earlier context-switch document by Bill Cowan is available
here.
This is certainly not the only way to write a context switch and I do not
necessarily recommend (or not recommend) this particular approach, but I
figure every bit of information can help.