1use core::{arch::naked_asm, fmt};
2
3use ax_memory_addr::VirtAddr;
4
5#[repr(C)]
7#[derive(Default, Clone, Copy)]
8pub struct TrapFrame {
9 pub x: [u64; 31],
11 pub elr: u64,
13 pub spsr: u64,
15
16 pub __pad: u64,
18}
19
20impl fmt::Debug for TrapFrame {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 writeln!(f, "TrapFrame: {{")?;
23 for (i, ®) in self.x.iter().enumerate() {
24 writeln!(f, " x{i}: {reg:#x},")?;
25 }
26 writeln!(f, " elr: {:#x},", self.elr)?;
27 writeln!(f, " spsr: {:#x},", self.spsr)?;
28 writeln!(f, " pad: {:#x},", self.__pad)?;
29 write!(f, "}}")?;
30 Ok(())
31 }
32}
33
34impl TrapFrame {
35 pub const fn arg0(&self) -> usize {
37 self.x[0] as _
38 }
39
40 pub const fn set_arg0(&mut self, a0: usize) {
42 self.x[0] = a0 as _;
43 }
44
45 pub const fn arg1(&self) -> usize {
47 self.x[1] as _
48 }
49
50 pub const fn set_arg1(&mut self, a1: usize) {
52 self.x[1] = a1 as _;
53 }
54
55 pub const fn arg2(&self) -> usize {
57 self.x[2] as _
58 }
59
60 pub const fn set_arg2(&mut self, a2: usize) {
62 self.x[2] = a2 as _;
63 }
64
65 pub const fn arg3(&self) -> usize {
67 self.x[3] as _
68 }
69
70 pub const fn set_arg3(&mut self, a3: usize) {
72 self.x[3] = a3 as _;
73 }
74
75 pub const fn arg4(&self) -> usize {
77 self.x[4] as _
78 }
79
80 pub const fn set_arg4(&mut self, a4: usize) {
82 self.x[4] = a4 as _;
83 }
84
85 pub const fn arg5(&self) -> usize {
87 self.x[5] as _
88 }
89
90 pub const fn set_arg5(&mut self, a5: usize) {
92 self.x[5] = a5 as _;
93 }
94
95 pub const fn ip(&self) -> usize {
97 self.elr as _
98 }
99
100 pub const fn set_ip(&mut self, pc: usize) {
102 self.elr = pc as _;
103 }
104
105 pub const fn sysno(&self) -> usize {
107 self.x[8] as usize
108 }
109
110 pub const fn set_sysno(&mut self, sysno: usize) {
112 self.x[8] = sysno as _;
113 }
114
115 pub const fn retval(&self) -> usize {
117 self.x[0] as _
118 }
119
120 pub const fn set_retval(&mut self, r0: usize) {
122 self.x[0] = r0 as _;
123 }
124
125 pub const fn set_ra(&mut self, lr: usize) {
127 self.x[30] = lr as _;
128 }
129
130 pub fn backtrace(&self) -> axbacktrace::Backtrace {
132 axbacktrace::Backtrace::capture_trap(self.x[29] as _, self.elr as _, self.x[30] as _)
133 }
134}
135
136#[repr(C, align(16))]
138#[derive(Debug, Default)]
139pub struct FpState {
140 pub regs: [u128; 32],
142 pub fpcr: u32,
144 pub fpsr: u32,
146}
147
148#[cfg(feature = "fp-simd")]
149impl FpState {
150 pub fn save(&mut self) {
152 unsafe { fpstate_save(self) }
153 }
154
155 pub fn restore(&self) {
157 unsafe { fpstate_restore(self) }
158 }
159}
160
161#[allow(missing_docs)]
173#[repr(C)]
174#[derive(Debug, Default)]
175pub struct TaskContext {
176 pub sp: u64,
177 pub r19: u64,
178 pub r20: u64,
179 pub r21: u64,
180 pub r22: u64,
181 pub r23: u64,
182 pub r24: u64,
183 pub r25: u64,
184 pub r26: u64,
185 pub r27: u64,
186 pub r28: u64,
187 pub r29: u64,
188 pub lr: u64, pub tpidr_el0: u64,
191 #[cfg(feature = "uspace")]
193 pub ttbr0_el1: ax_memory_addr::PhysAddr,
194 #[cfg(feature = "fp-simd")]
195 pub fp_state: FpState,
196}
197
198impl TaskContext {
199 pub fn new() -> Self {
207 Self::default()
208 }
209
210 pub fn init(&mut self, entry: usize, kstack_top: VirtAddr, tls_area: VirtAddr) {
213 self.sp = kstack_top.as_usize() as u64;
214 self.lr = entry as u64;
215 self.tpidr_el0 = tls_area.as_usize() as u64;
216 }
217
218 #[cfg(feature = "uspace")]
223 pub fn set_page_table_root(&mut self, ttbr0_el1: ax_memory_addr::PhysAddr) {
224 self.ttbr0_el1 = ttbr0_el1;
225 }
226
227 pub fn switch_to(&mut self, next_ctx: &Self) {
232 #[cfg(feature = "tls")]
233 {
234 self.tpidr_el0 = crate::asm::read_thread_pointer() as _;
235 unsafe { crate::asm::write_thread_pointer(next_ctx.tpidr_el0 as _) };
236 }
237 #[cfg(feature = "fp-simd")]
238 {
239 self.fp_state.save();
240 next_ctx.fp_state.restore();
241 }
242 #[cfg(feature = "uspace")]
243 if self.ttbr0_el1 != next_ctx.ttbr0_el1 {
244 unsafe { crate::asm::write_user_page_table(next_ctx.ttbr0_el1) };
245 crate::asm::flush_tlb(None); }
247 unsafe { context_switch(self, next_ctx) }
248 }
249}
250
251#[unsafe(naked)]
252unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task: &TaskContext) {
253 naked_asm!(
254 "
255 // save old context (callee-saved registers)
256 stp x29, x30, [x0, 11 * 8]
257 stp x27, x28, [x0, 9 * 8]
258 stp x25, x26, [x0, 7 * 8]
259 stp x23, x24, [x0, 5 * 8]
260 stp x21, x22, [x0, 3 * 8]
261 stp x19, x20, [x0, 1 * 8]
262 mov x19, sp
263 str x19, [x0]
264
265 // restore new context
266 ldr x19, [x1]
267 mov sp, x19
268 ldp x19, x20, [x1, 1 * 8]
269 ldp x21, x22, [x1, 3 * 8]
270 ldp x23, x24, [x1, 5 * 8]
271 ldp x25, x26, [x1, 7 * 8]
272 ldp x27, x28, [x1, 9 * 8]
273 ldp x29, x30, [x1, 11 * 8]
274
275 ret",
276 )
277}
278
279#[unsafe(naked)]
280#[cfg(feature = "fp-simd")]
281unsafe extern "C" fn fpstate_save(state: &mut FpState) {
282 naked_asm!(
283 ".arch armv8
284 // save fp/neon context
285 mrs x9, fpcr
286 mrs x10, fpsr
287 stp q0, q1, [x0, 0 * 16]
288 stp q2, q3, [x0, 2 * 16]
289 stp q4, q5, [x0, 4 * 16]
290 stp q6, q7, [x0, 6 * 16]
291 stp q8, q9, [x0, 8 * 16]
292 stp q10, q11, [x0, 10 * 16]
293 stp q12, q13, [x0, 12 * 16]
294 stp q14, q15, [x0, 14 * 16]
295 stp q16, q17, [x0, 16 * 16]
296 stp q18, q19, [x0, 18 * 16]
297 stp q20, q21, [x0, 20 * 16]
298 stp q22, q23, [x0, 22 * 16]
299 stp q24, q25, [x0, 24 * 16]
300 stp q26, q27, [x0, 26 * 16]
301 stp q28, q29, [x0, 28 * 16]
302 stp q30, q31, [x0, 30 * 16]
303 str x9, [x0, 64 * 8]
304 str x10, [x0, 65 * 8]
305
306 isb
307 ret"
308 )
309}
310
311#[unsafe(naked)]
312#[cfg(feature = "fp-simd")]
313unsafe extern "C" fn fpstate_restore(state: &FpState) {
314 naked_asm!(
315 ".arch armv8
316 // restore fp/neon context
317 ldp q0, q1, [x0, 0 * 16]
318 ldp q2, q3, [x0, 2 * 16]
319 ldp q4, q5, [x0, 4 * 16]
320 ldp q6, q7, [x0, 6 * 16]
321 ldp q8, q9, [x0, 8 * 16]
322 ldp q10, q11, [x0, 10 * 16]
323 ldp q12, q13, [x0, 12 * 16]
324 ldp q14, q15, [x0, 14 * 16]
325 ldp q16, q17, [x0, 16 * 16]
326 ldp q18, q19, [x0, 18 * 16]
327 ldp q20, q21, [x0, 20 * 16]
328 ldp q22, q23, [x0, 22 * 16]
329 ldp q24, q25, [x0, 24 * 16]
330 ldp q26, q27, [x0, 26 * 16]
331 ldp q28, q29, [x0, 28 * 16]
332 ldp q30, q31, [x0, 30 * 16]
333 ldr x9, [x0, 64 * 8]
334 ldr x10, [x0, 65 * 8]
335 msr fpcr, x9
336 msr fpsr, x10
337
338 isb
339 ret"
340 )
341}