RISC-V Context Management
Relevant source files
Purpose and Scope
This document covers the RISC-V architecture's CPU context management implementation within the axcpu library. It focuses on the data structures and mechanisms used to manage CPU state during task switching and exception handling, including register preservation, memory management integration, and thread-local storage support.
For RISC-V trap and exception handling mechanisms, see RISC-V Trap and Exception Handling. For system initialization procedures, see RISC-V System Initialization.
Core Context Structures
The RISC-V context management is built around three primary data structures that represent different levels of CPU state preservation.
Context Structure Hierarchy
flowchart TD
subgraph subGraph2["RISC-V Hardware Registers"]
SEPC["SEPCSupervisor Exception PC"]
SSTATUS["SSTATUSSupervisor Status"]
SATP["SATPAddress Translation"]
TP_REG["TPThread Pointer"]
end
subgraph subGraph1["Usage Contexts"]
EXCEPTION["Exception/Trap HandlingFull state preservation"]
SWITCHING["Task SwitchingMinimal state preservation"]
SYSCALL["System Call InterfaceArgument extraction"]
end
subgraph subGraph0["RISC-V Context Management"]
GR["GeneralRegistersAll 31 GP registersra, sp, gp, tp, t0-t6, s0-s11, a0-a7"]
TF["TrapFrameComplete exception stateregs + sepc + sstatus"]
TC["TaskContextMinimal switching stateCallee-saved + sp + tp + satp"]
end
GR --> TF
TC --> SATP
TC --> SWITCHING
TC --> TP_REG
TF --> EXCEPTION
TF --> SEPC
TF --> SSTATUS
TF --> SYSCALL
Sources: src/riscv/context.rs(L8 - L123)
GeneralRegisters Structure
The GeneralRegisters structure represents the complete RISC-V general-purpose register set, containing all 31 registers as defined by the RISC-V specification.
| Register Group | Registers | Purpose |
|---|---|---|
| Return Address | ra | Function return address |
| Stack Pointer | sp | Current stack pointer |
| Global Pointer | gp | Global data pointer (user traps only) |
| Thread Pointer | tp | Thread-local storage (user traps only) |
| Temporaries | t0-t6 | Temporary registers |
| Saved Registers | s0-s11 | Callee-saved registers |
| Arguments | a0-a7 | Function arguments and return values |
Sources: src/riscv/context.rs(L8 - L40)
TrapFrame Structure
The TrapFrame extends GeneralRegisters with supervisor-mode control and status registers required for complete exception context preservation.
flowchart TD
subgraph subGraph1["System Call Interface"]
ARG0["arg0() -> a0"]
ARG1["arg1() -> a1"]
ARG2["arg2() -> a2"]
ARG3["arg3() -> a3"]
ARG4["arg4() -> a4"]
ARG5["arg5() -> a5"]
end
subgraph subGraph0["TrapFrame Layout"]
REGS["regs: GeneralRegistersComplete register file"]
SEPC["sepc: usizeException return address"]
SSTATUS["sstatus: usizeProcessor status"]
end
REGS --> ARG0
REGS --> ARG1
REGS --> ARG2
REGS --> ARG3
REGS --> ARG4
REGS --> ARG5
The TrapFrame provides accessor methods for system call arguments through the arg0() through arg5() methods, which extract values from the appropriate argument registers (a0-a5).
Sources: src/riscv/context.rs(L44 - L84)
TaskContext Structure
The TaskContext represents the minimal CPU state required for task switching, containing only callee-saved registers and system-specific state.
| Field | Purpose | Availability |
|---|---|---|
| ra | Return address for context switch | Always |
| sp | Stack pointer | Always |
| s0-s11 | Callee-saved registers | Always |
| tp | Thread pointer for TLS | Always |
| satp | Page table root | uspacefeature only |
Sources: src/riscv/context.rs(L100 - L123)
Context Switching Mechanism
The RISC-V context switching implementation uses a combination of Rust methods and naked assembly functions to efficiently preserve and restore task state.
Context Switch Flow
flowchart TD
subgraph subGraph1["context_switch() Assembly"]
SAVE_REGS["Save callee-saved registersSTR ra,sp,s0-s11 -> current"]
RESTORE_REGS["Restore callee-saved registersLDR s11-s0,sp,ra <- next"]
RETURN["ret"]
end
subgraph TaskContext::switch_to()["TaskContext::switch_to()"]
START["switch_to(&self, next_ctx: &Self)"]
TLS_CHECK["TLS featureenabled?"]
TLS_SAVE["Save current TPLoad next TP"]
USPACE_CHECK["USPACE featureenabled?"]
SATP_CMP["Current SATP !=Next SATP?"]
SATP_SWITCH["Switch page tableFlush TLB"]
ASM_SWITCH["context_switch(self, next_ctx)"]
end
ASM_SWITCH --> SAVE_REGS
RESTORE_REGS --> RETURN
SATP_CMP --> ASM_SWITCH
SATP_CMP --> SATP_SWITCH
SATP_SWITCH --> ASM_SWITCH
SAVE_REGS --> RESTORE_REGS
START --> TLS_CHECK
TLS_CHECK --> TLS_SAVE
TLS_CHECK --> USPACE_CHECK
TLS_SAVE --> USPACE_CHECK
USPACE_CHECK --> ASM_SWITCH
USPACE_CHECK --> SATP_CMP
Sources: src/riscv/context.rs(L162 - L177) src/riscv/context.rs(L181 - L219)
Assembly Context Switch Implementation
The context_switch function is implemented as a naked assembly function that directly manipulates the task context structures:
- Save Phase: Uses
STRmacro to store callee-saved registers from CPU to current task's context - Restore Phase: Uses
LDRmacro to load callee-saved registers from next task's context to CPU - Register Order: Processes registers in reverse order during restore to maintain stack discipline
The assembly implementation assumes that the STR and LDR macros are defined to handle register storage and loading operations specific to the RISC-V architecture.
Sources: src/riscv/context.rs(L181 - L219)
Memory Management Integration
The RISC-V context management integrates closely with the memory management system through the satp (Supervisor Address Translation and Protection) register.
Page Table Root Management
flowchart TD
subgraph subGraph1["SATP Management"]
CURRENT_SATP["Current Task SATP"]
NEXT_SATP["Next Task SATP"]
COMPARE["SATP valuesdifferent?"]
WRITE_SATP["write_user_page_table()"]
FLUSH_TLB["flush_tlb(None)"]
end
subgraph subGraph0["User Space Context Management"]
NEW_TASK["TaskContext::new()"]
KERNEL_SATP["read_kernel_page_table()"]
SET_ROOT["set_page_table_root(satp)"]
SWITCH["Context Switch"]
end
COMPARE --> SWITCH
COMPARE --> WRITE_SATP
CURRENT_SATP --> COMPARE
NEW_TASK --> KERNEL_SATP
NEXT_SATP --> COMPARE
SET_ROOT --> CURRENT_SATP
SWITCH --> COMPARE
WRITE_SATP --> FLUSH_TLB
Key Operations:
- Initialization: New tasks start with the kernel page table root
- Page Table Switching: Only occurs when SATP values differ between tasks
- TLB Management: Complete TLB flush after page table switches
- Conditional Compilation: Available only with
uspacefeature
Sources: src/riscv/context.rs(L120 - L121) src/riscv/context.rs(L154 - L156) src/riscv/context.rs(L168 - L172)
Thread Local Storage Support
The RISC-V implementation provides thread-local storage support through the tp (thread pointer) register, available when the tls feature is enabled.
TLS Context Management
| Operation | Method | Register | Purpose |
|---|---|---|---|
| Initialization | init() | Settpfield | Configure TLS area for new tasks |
| Context Switch | switch_to() | Save/restoretp | Maintain per-task TLS state |
| Register Access | ASM functions | Read/write TP | Low-level TLS manipulation |
The TLS implementation ensures that each task maintains its own thread-local storage area by:
- Saving Current State: Reading the current
tpregister value before switching - Restoring Next State: Writing the next task's
tpvalue to the register - Initialization Support: Setting the TLS area address during task creation
Sources: src/riscv/context.rs(L118) src/riscv/context.rs(L146) src/riscv/context.rs(L164 - L167)
TaskContext Lifecycle
The TaskContext follows a specific lifecycle pattern for task creation and management:
flowchart TD
subgraph subGraph1["Runtime Operations"]
SWITCH["switch_to(next_ctx)"]
SET_PT["set_page_table_root()"]
ACTIVE["Task Execution"]
end
subgraph subGraph0["Task Creation Flow"]
NEW["TaskContext::new()"]
INIT["init(entry, kstack_top, tls_area)"]
READY["Ready for Switching"]
end
ACTIVE --> SWITCH
INIT --> READY
NEW --> INIT
READY --> SET_PT
READY --> SWITCH
SET_PT --> SWITCH
SWITCH --> ACTIVE
Initialization Parameters:
entry: Task entry point address (stored inra)kstack_top: Kernel stack top (stored insp)tls_area: Thread-local storage area (stored intp)
Sources: src/riscv/context.rs(L133 - L147)