⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/arch/
context.rs

1//! Architecture-independent context management interface
2//!
3//! This module defines the common interface for thread context management
4//! that must be implemented for each architecture.
5
6use crate::sched::task::TaskContext;
7
8/// Thread context trait
9pub trait ThreadContext: Sized {
10    /// Create a new empty context
11    fn new() -> Self;
12
13    /// Initialize context for a new thread
14    fn init(&mut self, entry_point: usize, stack_pointer: usize, kernel_stack: usize);
15
16    /// Get instruction pointer
17    fn get_instruction_pointer(&self) -> usize;
18
19    /// Set instruction pointer
20    fn set_instruction_pointer(&mut self, ip: usize);
21
22    /// Get stack pointer
23    fn get_stack_pointer(&self) -> usize;
24
25    /// Set stack pointer
26    fn set_stack_pointer(&mut self, sp: usize);
27
28    /// Get kernel stack pointer
29    fn get_kernel_stack(&self) -> usize;
30
31    /// Set kernel stack pointer
32    fn set_kernel_stack(&mut self, sp: usize);
33
34    /// Set return value (for syscalls, fork, etc.)
35    fn set_return_value(&mut self, value: usize);
36
37    /// Set user TLS base for this context (FS/TP).
38    fn set_tls_base(&mut self, base: u64);
39
40    /// Get user TLS base stored in this context.
41    fn tls_base(&self) -> u64;
42
43    /// Clone the context
44    fn clone_from(&mut self, other: &Self);
45
46    /// Convert to scheduler's TaskContext
47    fn to_task_context(&self) -> TaskContext;
48}
49
50/// Architecture-specific thread context type alias
51#[cfg(target_arch = "x86_64")]
52pub type ArchThreadContext = crate::arch::x86_64::context::X86_64Context;
53
54#[cfg(target_arch = "aarch64")]
55pub type ArchThreadContext = crate::arch::aarch64::context::AArch64Context;
56
57#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
58pub type ArchThreadContext = crate::arch::riscv::context::RiscVContext;
59
60/// Perform a context switch between two threads
61///
62/// # Safety
63/// This function must be called with interrupts disabled and
64/// both contexts must be valid.
65pub unsafe fn switch_context(from: &mut ArchThreadContext, to: &ArchThreadContext) {
66    #[cfg(target_arch = "x86_64")]
67    crate::arch::x86_64::context::switch_context(from, to);
68
69    #[cfg(target_arch = "aarch64")]
70    crate::arch::aarch64::context::switch_context(from, to);
71
72    #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
73    crate::arch::riscv::context::switch_context(from, to);
74}
75
76/// Initialize FPU/SIMD for the current CPU
77pub fn init_fpu() {
78    #[cfg(target_arch = "x86_64")]
79    crate::arch::x86_64::context::init_fpu();
80
81    #[cfg(target_arch = "aarch64")]
82    crate::arch::aarch64::context::init_fpu();
83
84    #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
85    crate::arch::riscv::context::init_fpu();
86}
87
88/// Save FPU/SIMD state
89pub fn save_fpu_state(state: &mut [u8]) {
90    #[cfg(target_arch = "x86_64")]
91    // SAFETY: The caller provides a byte slice large enough to hold FpuState
92    // (512 bytes, 16-byte aligned via repr(C, align(16))). The pointer cast from
93    // u8 to FpuState is valid because save_fpu_state writes all fields via FXSAVE.
94    unsafe {
95        crate::arch::x86_64::context::save_fpu_state(
96            &mut *(state.as_mut_ptr() as *mut crate::arch::x86_64::context::FpuState),
97        );
98    }
99
100    #[cfg(target_arch = "aarch64")]
101    {
102        // SAFETY: The byte slice must be large enough and aligned for AArch64 FpuState.
103        // The cast is valid because save_fpu_state writes all fields via STP.
104        let fpu =
105            unsafe { &mut *(state.as_mut_ptr() as *mut crate::arch::aarch64::context::FpuState) };
106        crate::arch::aarch64::context::save_fpu_state(fpu);
107    }
108
109    #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
110    {
111        // SAFETY: The byte slice must be large enough and aligned for RISC-V FpuState.
112        // The cast is valid because save_fpu_state writes all fields via FSD.
113        let fpu =
114            unsafe { &mut *(state.as_mut_ptr() as *mut crate::arch::riscv::context::FpuState) };
115        crate::arch::riscv::context::save_fpu_state(fpu);
116    }
117}
118
119/// Restore FPU/SIMD state
120pub fn restore_fpu_state(state: &[u8]) {
121    #[cfg(target_arch = "x86_64")]
122    // SAFETY: The caller provides a byte slice containing valid FpuState data
123    // previously saved by save_fpu_state. The pointer cast from u8 to FpuState
124    // is valid because the data was written via FXSAVE with proper alignment.
125    unsafe {
126        crate::arch::x86_64::context::restore_fpu_state(
127            &*(state.as_ptr() as *const crate::arch::x86_64::context::FpuState),
128        );
129    }
130
131    #[cfg(target_arch = "aarch64")]
132    {
133        // SAFETY: The byte slice contains valid FpuState data from save_fpu_state.
134        let fpu = unsafe { &*(state.as_ptr() as *const crate::arch::aarch64::context::FpuState) };
135        crate::arch::aarch64::context::restore_fpu_state(fpu);
136    }
137
138    #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
139    {
140        // SAFETY: The byte slice contains valid FpuState data from save_fpu_state.
141        let fpu = unsafe { &*(state.as_ptr() as *const crate::arch::riscv::context::FpuState) };
142        crate::arch::riscv::context::restore_fpu_state(fpu);
143    }
144}