AArch64 Context Management
Relevant source files
This document covers CPU context management for the AArch64 architecture within the axcpu library. It details the data structures, mechanisms, and assembly implementations used for task switching, exception handling, and state preservation on ARM64 systems.
The scope includes the TaskContext structure for task switching, TrapFrame for exception handling, and FpState for floating-point operations. For information about how these contexts are used during exception processing, see AArch64 Trap and Exception Handling. For system initialization and setup procedures, see AArch64 System Initialization.
Context Data Structures
The AArch64 context management revolves around three primary data structures, each serving different aspects of CPU state management.
Context Structure Overview
flowchart TD
subgraph subGraph3["FpState Fields"]
FP_REGS["regs[32]: u128V0-V31 SIMD Registers"]
FP_CTRL["fpcr/fpsr: u32Control/Status Registers"]
end
subgraph subGraph2["TrapFrame Fields"]
TF_REGS["r[31]: u64General Purpose Registers"]
TF_USP["usp: u64User Stack Pointer"]
TF_ELR["elr: u64Exception Link Register"]
TF_SPSR["spsr: u64Saved Process Status"]
end
subgraph subGraph1["TaskContext Fields"]
TC_SP["sp: u64Stack Pointer"]
TC_TPIDR["tpidr_el0: u64Thread Local Storage"]
TC_REGS["r19-r29, lr: u64Callee-saved Registers"]
TC_TTBR["ttbr0_el1: PhysAddrPage Table Root"]
TC_FP["fp_state: FpStateFP/SIMD State"]
end
subgraph subGraph0["AArch64 Context Management"]
TaskContext["TaskContextTask Switching Context"]
TrapFrame["TrapFrameException Context"]
FpState["FpStateFP/SIMD Context"]
end
FpState --> FP_CTRL
FpState --> FP_REGS
TC_FP --> FpState
TaskContext --> TC_FP
TaskContext --> TC_REGS
TaskContext --> TC_SP
TaskContext --> TC_TPIDR
TaskContext --> TC_TTBR
TrapFrame --> TF_ELR
TrapFrame --> TF_REGS
TrapFrame --> TF_SPSR
TrapFrame --> TF_USP
Sources: src/aarch64/context.rs(L8 - L124)
TaskContext Structure
The TaskContext structure maintains the minimal set of registers needed for task switching, focusing on callee-saved registers and system state.
| Field | Type | Purpose |
|---|---|---|
| sp | u64 | Stack pointer register |
| tpidr_el0 | u64 | Thread pointer for TLS |
| r19-r29 | u64 | Callee-saved general registers |
| lr | u64 | Link register (r30) |
| ttbr0_el1 | PhysAddr | User page table root (uspace feature) |
| fp_state | FpState | Floating-point state (fp-simd feature) |
The structure is conditionally compiled based on enabled features, with ttbr0_el1 only included with the uspace feature and fp_state only with the fp-simd feature.
Sources: src/aarch64/context.rs(L104 - L124)
TrapFrame Structure
The TrapFrame captures the complete CPU state during exceptions and system calls, preserving all general-purpose registers and processor state.
flowchart TD
subgraph subGraph0["TrapFrame Memory Layout"]
R0_30["r[0-30]General Registers248 bytes"]
USP["uspUser Stack Pointer8 bytes"]
ELR["elrException Link Register8 bytes"]
SPSR["spsrSaved Process Status8 bytes"]
end
ELR --> SPSR
USP --> ELR
The TrapFrame provides accessor methods for system call arguments through arg0() through arg5() methods, which map to registers r[0] through r[5] respectively.
Sources: src/aarch64/context.rs(L8 - L63)
FpState Structure
The FpState structure manages floating-point and SIMD register state, with 16-byte alignment required for proper SIMD operations.
flowchart TD
subgraph Operations["Operations"]
SAVE["save()CPU → Memory"]
RESTORE["restore()Memory → CPU"]
end
subgraph subGraph0["FpState Structure"]
REGS["regs[32]: u128V0-V31 SIMD/FP Registers512 bytes total"]
FPCR["fpcr: u32Floating-Point Control Register"]
FPSR["fpsr: u32Floating-Point Status Register"]
end
FPCR --> SAVE
FPSR --> SAVE
REGS --> SAVE
RESTORE --> FPCR
RESTORE --> FPSR
RESTORE --> REGS
SAVE --> RESTORE
Sources: src/aarch64/context.rs(L66 - L88)
Context Switching Mechanism
Task switching on AArch64 involves saving the current task's callee-saved registers and restoring the next task's context, with optional handling of floating-point state and page tables.
Context Switch Flow
sequenceDiagram
participant CurrentTaskContext as "Current TaskContext"
participant NextTaskContext as "Next TaskContext"
participant AArch64CPU as "AArch64 CPU"
participant MemoryManagementUnit as "Memory Management Unit"
CurrentTaskContext ->> CurrentTaskContext: Check fp-simd feature
alt fp-simd enabled
CurrentTaskContext ->> AArch64CPU: Save FP/SIMD state
NextTaskContext ->> AArch64CPU: Restore FP/SIMD state
end
CurrentTaskContext ->> CurrentTaskContext: Check uspace feature
alt uspace enabled and ttbr0_el1 differs
NextTaskContext ->> MemoryManagementUnit: Update page table root
MemoryManagementUnit ->> MemoryManagementUnit: Flush TLB
end
CurrentTaskContext ->> AArch64CPU: context_switch(current, next)
Note over AArch64CPU: Assembly context switch
AArch64CPU ->> CurrentTaskContext: Save callee-saved registers
AArch64CPU ->> AArch64CPU: Restore next task registers
AArch64CPU ->> NextTaskContext: Load context to CPU
The switch_to method orchestrates the complete context switch:
- FP/SIMD State: If
fp-simdfeature is enabled, saves current FP state and restores next task's FP state - Page Table Switching: If
uspacefeature is enabled and page tables differ, updatesttbr0_el1and flushes TLB - Register Context: Calls assembly
context_switchfunction to handle callee-saved registers
Sources: src/aarch64/context.rs(L160 - L172)
Assembly Context Switch Implementation
The low-level context switching is implemented in naked assembly within the context_switch function:
flowchart TD
subgraph subGraph0["context_switch Assembly Flow"]
SAVE_START["Save Current Contextstp x29,x30 [x0,12*8]"]
SAVE_REGS["Save Callee-Savedr19-r28 to memory"]
SAVE_SP_TLS["Save SP and TLSmov x19,sp; mrs x20,tpidr_el0"]
RESTORE_SP_TLS["Restore SP and TLSmov sp,x19; msr tpidr_el0,x20"]
RESTORE_REGS["Restore Callee-Savedr19-r28 from memory"]
RESTORE_END["Restore Frameldp x29,x30 [x1,12*8]"]
RET["Returnret"]
end
RESTORE_END --> RET
RESTORE_REGS --> RESTORE_END
RESTORE_SP_TLS --> RESTORE_REGS
SAVE_REGS --> SAVE_SP_TLS
SAVE_SP_TLS --> RESTORE_SP_TLS
SAVE_START --> SAVE_REGS
The assembly implementation uses paired load/store instructions (stp/ldp) for efficiency, handling registers in pairs and preserving the AArch64 calling convention.
Sources: src/aarch64/context.rs(L175 - L203)
Feature-Conditional Context Management
The AArch64 context management includes several optional features that extend the base functionality.
Feature Integration Overview
flowchart TD
subgraph subGraph2["Feature Operations"]
SET_PT["set_page_table_root()Update ttbr0_el1"]
SWITCH_PT["Page table switchingin switch_to()"]
FP_SAVE["fp_state.save()CPU → Memory"]
FP_RESTORE["fp_state.restore()Memory → CPU"]
TLS_INIT["TLS initializationin init()"]
end
subgraph subGraph1["Optional Features"]
USPACE["uspace Featurettbr0_el1: PhysAddr"]
FPSIMD["fp-simd Featurefp_state: FpState"]
TLS["tls Supporttpidr_el0 management"]
end
subgraph subGraph0["Base Context"]
BASE["TaskContext Basesp, tpidr_el0, r19-r29, lr"]
end
BASE --> FPSIMD
BASE --> TLS
BASE --> USPACE
FPSIMD --> FP_RESTORE
FPSIMD --> FP_SAVE
TLS --> TLS_INIT
USPACE --> SET_PT
USPACE --> SWITCH_PT
User Space Support
When the uspace feature is enabled, TaskContext includes the ttbr0_el1 field for managing user-space page tables. The set_page_table_root method allows updating the page table root, and context switching automatically handles page table updates and TLB flushes when switching between tasks with different address spaces.
Floating-Point State Management
The fp-simd feature enables comprehensive floating-point and SIMD state management through the FpState structure. The assembly implementations fpstate_save and fpstate_restore handle all 32 vector registers (V0-V31) plus control registers using quad-word load/store instructions.
Sources: src/aarch64/context.rs(L77 - L88) src/aarch64/context.rs(L120 - L123) src/aarch64/context.rs(L147 - L154) src/aarch64/context.rs(L206 - L267)
Task Initialization
New tasks are initialized through the TaskContext::init method, which sets up the minimal execution environment:
flowchart TD
subgraph subGraph1["TaskContext Setup"]
SET_SP["self.sp = kstack_top"]
SET_LR["self.lr = entry"]
SET_TLS["self.tpidr_el0 = tls_area"]
end
subgraph subGraph0["Task Initialization Parameters"]
ENTRY["entry: usizeTask entry point"]
KSTACK["kstack_top: VirtAddrKernel stack top"]
TLS_AREA["tls_area: VirtAddrThread-local storage"]
end
ENTRY --> SET_LR
KSTACK --> SET_SP
TLS_AREA --> SET_TLS
The initialization sets the stack pointer to the kernel stack top, the link register to the task entry point, and the thread pointer for thread-local storage support.
Sources: src/aarch64/context.rs(L140 - L145)