CS 452/652 Winter 2023 - Lecture 4
Jab 19, 2023
prev
next
Documents
Programmer's Guide
(
local copy
)
ARMv8 Architecture
Processor State
execution state: 32 vs. 64 bit mode (AArch32 vs. AArch64)
exception level: 0...3 (cf. protection ring)
user program
kernel
hypervisor
secure monitor
security state: normal world (non-secure) vs. secure world
register file (X for 64 bits vs. W for 32 bits)
X0, X1, ..., X30
XZR (X31)
PC, SP banked (EL 0-3)
pstate: current processor status (mostly implicit)
condition codes (N,Z,C,V), interrupt flags, processor mode, systemstate
Negative, Zero, Carry and oVerflow -> conditional branching
named system/control registers; access with MRS/read, MSR/write
Section 4.3: timer, memory mapping, caching, exceptions, see below
SPSR (EL 1-3) - pstate, ELR (EL 1-3) - link/return, ESR (1-3) - status
Instructions
RISC architecture: instructions + operands encoded in 32 bits
opcodes for various addressing modes and immediate shifting
State, Register, and ABI Rules
x0-x7 arguments, x0 return value
x8 return pointer (instead of x0) for objects > 16 bytes
set up by caller, filled by callee
x9-x15 local registers
x16,x17 temporary for linker
x18 platform, such as thread-local storage
x19-x28 global registers
x29 frame pointer
x30 link register
condition flags in pstate undefined at entry/return of routine
floating point registers → do not use!
Context Switch
context = registers + stack + descriptor
subroutine call always creates new context at beginning of subroutine
and returns to caller → same stack
couroutine call resumes state in coroutine
separate stacks
but still explicit and synchronous invocation
multi-tasking: independence → scheduler decides what to do next
switch into and out of scheduler: subroutine or coroutine possible
blocking and resumption, independent or parallel execution
various design alternatives for context switch
Kernel Design
single stack with kernel state
new stack, subroutine using global/static kernel state
stack per user task using global/static kernel state
kernel tasks, preemptive kernel, multi-core
mode switch between kernel and user - synchronous vs. asynchronous
Routine Calls
starting point for context switch considerations
argument passing: registers and stack, stack alignment
b
jump
bl
branch and link (store next pc in lr)
ret
return (pc := lr)
ABI rules apply
x0-x18 caller saved, callee owned
x19-x30 caller owned, callee saved
pstate conditions invalid at routine boundary (callee owned)
stack alignment must be 16
Stack Switch
simplest form of context switch
used for coroutines or multi-task in same privilege level
could be declared as
void StackSwitch(char* newSP, char** oldSP);
implemented in assembler
compiler has saved x0-x18 (as needed)
save callee-saved x19-x30 (on stack)
save stack pointer to *x1
load stack pointer from x0
restore callee-saved (from stack)
return
seems easy, why?
no mode switch, no register banking
synchronous: ABI rules apply
symmetric: one routine only
Mode Switch
SP banked: stack switch might happen automatically
asymmetric (enter vs. leave kernel)
System Call
svc N
hard-coded handler → enter_kernel()
N is stored in ESR_ELx
synchronous, ABI rules apply
Interrupt
asynchronous: ABI rules don't apply
need to save callee-owned registers including pstate (helped by SPRS_ELx)
further routine calls will apply ABI rules
but need dedicated stack to restore later
only helps with per-user-task kernel stack
useful when interrupts often return to the interrupted task
Exceptions and Exception Vector
exception vector table stored at VBAR_ELx (exceptions
to
level x)
4 groups (
from
where): Current EL SP0/x, Lower EL 64/32
Lower EL 64 is used in CS 452 kernel
4 vectors (128 bytes, 32 instructions): Synchronous, IRQ, FIQ, Error
FIQ: AArch32 legacy
total of 4 * 4 * 128 bytes = 2KB
implement top-level exception handler directly in vector
recommendation: set up dummy handlers for all groups/vectors for error-checking!