ax_cpu/arch/aarch64/
uspace.rs1use core::{
4 mem::{offset_of, size_of},
5 ops::{Deref, DerefMut},
6};
7
8use aarch64_cpu::registers::FAR_EL1;
9pub use aarch64_cpu::registers::{ESR_EL1, Readable};
10use ax_memory_addr::VirtAddr;
11pub use tock_registers::{
12 LocalRegisterCopy, RegisterLongName, UIntLike,
13 debug::{RegisterDebugInfo, RegisterDebugValue},
14 fields::{Field, FieldValue, TryFromValue},
15};
16
17use super::trap::{TrapKind, is_valid_page_fault};
18pub use crate::uspace_common::{ExceptionKind, ExceptionSyndrome, ReturnReason};
19use crate::{arch::current::context::TrapFrame, trap::PageFaultFlags};
20
21#[repr(C, align(16))]
23#[derive(Debug, Clone, Copy)]
24pub struct UserContext {
25 tf: TrapFrame,
26 pub sp: u64,
28 pub tpidr: u64,
30}
31
32unsafe impl bytemuck::NoUninit for UserContext {}
35
36const _: () = {
37 assert!(size_of::<TrapFrame>() == 34 * size_of::<u64>());
38 assert!(offset_of!(UserContext, tf) == 0);
39 assert!(offset_of!(UserContext, sp) == size_of::<TrapFrame>());
40 assert!(offset_of!(UserContext, tpidr) == size_of::<TrapFrame>() + size_of::<u64>());
41 assert!(size_of::<UserContext>() == size_of::<TrapFrame>() + 2 * size_of::<u64>());
42};
43
44impl UserContext {
45 pub fn new(entry: usize, ustack_top: VirtAddr, arg0: usize) -> Self {
47 use aarch64_cpu::registers::SPSR_EL1;
48 let mut regs = [0; 31];
49 regs[0] = arg0 as _;
50 Self {
51 tf: TrapFrame {
52 x: regs,
53 elr: entry as _,
54 spsr: (SPSR_EL1::M::EL0t
55 + SPSR_EL1::D::Masked
56 + SPSR_EL1::A::Masked
57 + SPSR_EL1::I::Unmasked
58 + SPSR_EL1::F::Masked)
59 .value,
60 sp: 0,
61 },
62 sp: ustack_top.as_usize() as _,
63 tpidr: 0,
64 }
65 }
66
67 pub fn prepare_clone_child_return_state(&mut self) {
69 use aarch64_cpu::registers::SPSR_EL1;
70
71 self.tf.spsr = (self.tf.spsr
72 & !(SPSR_EL1::M.mask
73 | SPSR_EL1::D.mask
74 | SPSR_EL1::A.mask
75 | SPSR_EL1::I.mask
76 | SPSR_EL1::F.mask))
77 | (SPSR_EL1::M::EL0t
78 + SPSR_EL1::D::Masked
79 + SPSR_EL1::A::Masked
80 + SPSR_EL1::I::Unmasked
81 + SPSR_EL1::F::Masked)
82 .value;
83 }
84
85 pub const fn clear_single_step_after_debug(&mut self) -> bool {
90 false
91 }
92
93 pub const fn syscall_insn_len(&self) -> usize {
95 4
96 }
97
98 pub const fn sp(&self) -> usize {
100 self.sp as _
101 }
102
103 pub const fn set_sp(&mut self, sp: usize) {
105 self.sp = sp as _;
106 }
107
108 pub const fn tls(&self) -> usize {
110 self.tpidr as _
111 }
112
113 pub const fn set_tls(&mut self, tls: usize) {
115 self.tpidr = tls as _;
116 }
117
118 pub fn has_interruptible_user_return_mode(&self) -> bool {
121 use aarch64_cpu::registers::SPSR_EL1;
122
123 let runtime_daif =
124 SPSR_EL1::D::Masked + SPSR_EL1::A::Masked + SPSR_EL1::I::Unmasked + SPSR_EL1::F::Masked;
125 self.tf.spsr & SPSR_EL1::M::EL0t.mask() == SPSR_EL1::M::EL0t.value
126 && self.tf.spsr & runtime_daif.mask() == runtime_daif.value
127 }
128
129 pub unsafe fn run_unchecked(&mut self) -> ReturnReason {
147 unsafe extern "C" {
148 fn enter_user(uctx: &mut UserContext) -> TrapKind;
149 }
150
151 assert!(
152 !crate::asm::irqs_enabled(),
153 "raw user entry requires the prepared IRQ-off boundary"
154 );
155 assert!(
156 self.has_interruptible_user_return_mode(),
157 "raw user entry requires an interruptible EL0 register image"
158 );
159 let kind = unsafe { enter_user(self) };
160
161 let ret = match kind {
162 TrapKind::Irq => {
163 crate::trap::dispatch_irq(
164 0,
165 crate::trap::TrapOrigin::User,
166 Some(crate::trap::InterruptedContext {
167 pc: self.tf.ip(),
168 sp: self.sp as usize,
169 fp: self.tf.x[29] as usize,
170 lr: self.tf.x[30] as usize,
171 privilege: crate::trap::InterruptedPrivilege::User,
172 }),
173 );
174 ReturnReason::Interrupt
175 }
176 TrapKind::Fiq | TrapKind::SError => ReturnReason::Unknown,
177 TrapKind::Synchronous => {
178 let esr = ESR_EL1.extract();
179 let far = FAR_EL1.get() as usize;
180
181 let iss = esr.read(ESR_EL1::ISS);
182
183 match esr.read_as_enum(ESR_EL1::EC) {
184 Some(ESR_EL1::EC::Value::SVC64) => ReturnReason::Syscall,
185 Some(ESR_EL1::EC::Value::InstrAbortLowerEL) if is_valid_page_fault(iss) => {
186 ReturnReason::PageFault(
187 va!(far),
188 PageFaultFlags::EXECUTE | PageFaultFlags::USER,
189 )
190 }
191 Some(ESR_EL1::EC::Value::DataAbortLowerEL) if is_valid_page_fault(iss) => {
192 let wnr = (iss & (1 << 6)) != 0; let cm = (iss & (1 << 8)) != 0; ReturnReason::PageFault(
195 va!(far),
196 if wnr & !cm {
197 PageFaultFlags::WRITE
198 } else {
199 PageFaultFlags::READ
200 } | PageFaultFlags::USER,
201 )
202 }
203 _ => ReturnReason::Exception(ExceptionInfo { esr, far }),
204 }
205 }
206 };
207
208 crate::asm::enable_irqs();
209 ret
210 }
211}
212
213const _: unsafe fn(&mut UserContext) -> ReturnReason = UserContext::run_unchecked;
214
215impl Deref for UserContext {
216 type Target = TrapFrame;
217
218 fn deref(&self) -> &Self::Target {
219 &self.tf
220 }
221}
222
223impl DerefMut for UserContext {
224 fn deref_mut(&mut self) -> &mut Self::Target {
225 &mut self.tf
226 }
227}
228
229#[derive(Debug, Clone, Copy)]
231pub struct ExceptionInfo {
232 pub esr: LocalRegisterCopy<u64, ESR_EL1::Register>,
234 pub far: usize,
236}
237
238impl ExceptionInfo {
239 pub const fn fault_addr(&self) -> Option<usize> {
241 Some(self.far)
242 }
243
244 pub fn syndrome(&self) -> ExceptionSyndrome {
246 ExceptionSyndrome {
247 raw: self.esr_value(),
248 class: self.ec_value(),
249 iss: self.iss_value(),
250 }
251 }
252
253 pub fn esr_value(&self) -> u64 {
255 self.esr.get()
256 }
257
258 pub fn ec_value(&self) -> u64 {
260 self.esr.read(ESR_EL1::EC)
261 }
262
263 pub fn iss_value(&self) -> u64 {
265 self.esr.read(ESR_EL1::ISS)
266 }
267
268 pub fn kind(&self) -> ExceptionKind {
270 match self.esr.read_as_enum(ESR_EL1::EC) {
271 Some(ESR_EL1::EC::Value::Brk64) | Some(ESR_EL1::EC::Value::Bkpt32) => {
272 ExceptionKind::Breakpoint
273 }
274 Some(ESR_EL1::EC::Value::IllegalExecutionState) | Some(ESR_EL1::EC::Value::Unknown) => {
275 ExceptionKind::IllegalInstruction
276 }
277 Some(ESR_EL1::EC::Value::PCAlignmentFault)
278 | Some(ESR_EL1::EC::Value::SPAlignmentFault) => ExceptionKind::Misaligned,
279 _ => ExceptionKind::Other,
280 }
281 }
282}