1use core::arch::naked_asm;
2#[cfg(feature = "fp-simd")]
3use core::mem::offset_of;
4
5use ax_memory_addr::VirtAddr;
6
7#[allow(missing_docs)]
9#[repr(C)]
10#[derive(Debug, Default, Clone, Copy)]
11pub struct GeneralRegisters {
12 pub zero: usize,
13 pub ra: usize,
14 pub tp: usize,
15 pub sp: usize,
16 pub a0: usize,
17 pub a1: usize,
18 pub a2: usize,
19 pub a3: usize,
20 pub a4: usize,
21 pub a5: usize,
22 pub a6: usize,
23 pub a7: usize,
24 pub t0: usize,
25 pub t1: usize,
26 pub t2: usize,
27 pub t3: usize,
28 pub t4: usize,
29 pub t5: usize,
30 pub t6: usize,
31 pub t7: usize,
32 pub t8: usize,
33 pub u0: usize,
34 pub fp: usize,
35 pub s0: usize,
36 pub s1: usize,
37 pub s2: usize,
38 pub s3: usize,
39 pub s4: usize,
40 pub s5: usize,
41 pub s6: usize,
42 pub s7: usize,
43 pub s8: usize,
44}
45
46#[repr(C)]
48#[derive(Debug, Default, Clone, Copy)]
49pub struct FpuState {
50 pub fp: [u64; 32],
52 pub fcc: [u8; 8],
54 pub fcsr: u32,
56}
57
58#[cfg(feature = "fp-simd")]
59impl FpuState {
60 #[inline]
62 pub fn save(&mut self) {
63 unsafe { save_fp_registers(self) }
64 }
65
66 #[inline]
68 pub fn restore(&self) {
69 unsafe { restore_fp_registers(self) }
70 }
71}
72
73#[repr(C)]
75#[derive(Debug, Default, Clone, Copy)]
76pub struct TrapFrame {
77 pub regs: GeneralRegisters,
79 pub prmd: usize,
81 pub era: usize,
83}
84
85impl TrapFrame {
86 pub const fn arg0(&self) -> usize {
88 self.regs.a0
89 }
90
91 pub const fn set_arg0(&mut self, a0: usize) {
93 self.regs.a0 = a0;
94 }
95
96 pub const fn arg1(&self) -> usize {
98 self.regs.a1
99 }
100
101 pub const fn set_arg1(&mut self, a1: usize) {
103 self.regs.a1 = a1;
104 }
105
106 pub const fn arg2(&self) -> usize {
108 self.regs.a2
109 }
110
111 pub const fn set_arg2(&mut self, a2: usize) {
113 self.regs.a2 = a2;
114 }
115
116 pub const fn arg3(&self) -> usize {
118 self.regs.a3
119 }
120
121 pub const fn set_arg3(&mut self, a3: usize) {
123 self.regs.a3 = a3;
124 }
125
126 pub const fn arg4(&self) -> usize {
128 self.regs.a4
129 }
130
131 pub const fn set_arg4(&mut self, a4: usize) {
133 self.regs.a4 = a4;
134 }
135
136 pub const fn arg5(&self) -> usize {
138 self.regs.a5
139 }
140
141 pub const fn set_arg5(&mut self, a5: usize) {
143 self.regs.a5 = a5;
144 }
145
146 pub const fn sysno(&self) -> usize {
148 self.regs.a7
149 }
150
151 pub const fn set_sysno(&mut self, a7: usize) {
153 self.regs.a7 = a7;
154 }
155
156 pub const fn ip(&self) -> usize {
158 self.era
159 }
160
161 pub const fn set_ip(&mut self, pc: usize) {
163 self.era = pc;
164 }
165
166 pub const fn sp(&self) -> usize {
168 self.regs.sp
169 }
170
171 pub const fn set_sp(&mut self, sp: usize) {
173 self.regs.sp = sp;
174 }
175
176 pub const fn retval(&self) -> usize {
178 self.regs.a0
179 }
180
181 pub const fn set_retval(&mut self, a0: usize) {
183 self.regs.a0 = a0;
184 }
185
186 pub const fn set_ra(&mut self, ra: usize) {
188 self.regs.ra = ra;
189 }
190
191 pub const fn tls(&self) -> usize {
193 self.regs.tp
194 }
195
196 pub const fn set_tls(&mut self, tls_area: usize) {
198 self.regs.tp = tls_area;
199 }
200
201 pub fn backtrace(&self) -> axbacktrace::Backtrace {
203 axbacktrace::Backtrace::capture_trap(self.regs.fp as _, self.era as _, self.regs.ra as _)
204 }
205}
206
207#[allow(missing_docs)]
219#[repr(C)]
220#[derive(Debug, Default)]
221pub struct TaskContext {
222 pub ra: usize,
224 pub sp: usize,
226 pub s: [usize; 10],
228 pub tp: usize,
230 #[cfg(feature = "uspace")]
231 pub pgdl: usize,
233 #[cfg(feature = "fp-simd")]
234 pub fpu: FpuState,
236}
237
238impl TaskContext {
239 pub fn new() -> Self {
241 Self::default()
242 }
243
244 pub fn init(&mut self, entry: usize, kstack_top: VirtAddr, tls_area: VirtAddr) {
247 self.sp = kstack_top.as_usize();
248 self.ra = entry;
249 self.tp = tls_area.as_usize();
250 }
251
252 #[cfg(feature = "uspace")]
257 pub fn set_page_table_root(&mut self, pgdl: ax_memory_addr::PhysAddr) {
258 self.pgdl = pgdl.as_usize();
259 }
260
261 pub fn switch_to(&mut self, next_ctx: &Self) {
266 #[cfg(feature = "tls")]
267 {
268 self.tp = crate::asm::read_thread_pointer();
269 unsafe { crate::asm::write_thread_pointer(next_ctx.tp) };
270 }
271 #[cfg(feature = "uspace")]
272 {
273 if self.pgdl != next_ctx.pgdl {
274 unsafe { crate::asm::write_user_page_table(pa!(next_ctx.pgdl)) };
275 crate::asm::flush_tlb(None); }
277 }
278 #[cfg(feature = "fp-simd")]
279 {
280 self.fpu.save();
281 next_ctx.fpu.restore();
282 }
283 unsafe { context_switch(self, next_ctx) }
284 }
285}
286
287#[cfg(feature = "fp-simd")]
288#[unsafe(naked)]
289unsafe extern "C" fn save_fp_registers(fpu: &mut FpuState) {
290 naked_asm!(
291 include_fp_asm_macros!(),
292 "
293 SAVE_FP $a0
294 addi.d $t8, $a0, {fcc_offset}
295 SAVE_FCC $t8
296 addi.d $t8, $a0, {fcsr_offset}
297 SAVE_FCSR $t8
298 ret",
299 fcc_offset = const offset_of!(FpuState, fcc),
300 fcsr_offset = const offset_of!(FpuState, fcsr),
301 )
302}
303
304#[cfg(feature = "fp-simd")]
305#[unsafe(naked)]
306unsafe extern "C" fn restore_fp_registers(fpu: &FpuState) {
307 naked_asm!(
308 include_fp_asm_macros!(),
309 "
310 RESTORE_FP $a0
311 addi.d $t8, $a0, {fcc_offset}
312 RESTORE_FCC $t8
313 addi.d $t8, $a0, {fcsr_offset}
314 RESTORE_FCSR $t8
315 ret",
316 fcc_offset = const offset_of!(FpuState, fcc),
317 fcsr_offset = const offset_of!(FpuState, fcsr),
318 )
319}
320
321#[unsafe(naked)]
322unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task: &TaskContext) {
323 naked_asm!(
324 include_asm_macros!(),
325 "
326 // save old context (callee-saved registers)
327 STD $ra, $a0, 0
328 STD $sp, $a0, 1
329 STD $s0, $a0, 2
330 STD $s1, $a0, 3
331 STD $s2, $a0, 4
332 STD $s3, $a0, 5
333 STD $s4, $a0, 6
334 STD $s5, $a0, 7
335 STD $s6, $a0, 8
336 STD $s7, $a0, 9
337 STD $s8, $a0, 10
338 STD $fp, $a0, 11
339
340 // restore new context
341 LDD $fp, $a1, 11
342 LDD $s8, $a1, 10
343 LDD $s7, $a1, 9
344 LDD $s6, $a1, 8
345 LDD $s5, $a1, 7
346 LDD $s4, $a1, 6
347 LDD $s3, $a1, 5
348 LDD $s2, $a1, 4
349 LDD $s1, $a1, 3
350 LDD $s0, $a1, 2
351 LDD $sp, $a1, 1
352 LDD $ra, $a1, 0
353
354 ret",
355 )
356}