1use core::ops::{Deref, DerefMut};
4
5use aarch64_cpu::registers::{ESR_EL1, FAR_EL1, Readable};
6use ax_memory_addr::VirtAddr;
7use tock_registers::LocalRegisterCopy;
8
9use super::trap::{TrapKind, is_valid_page_fault};
10pub use crate::uspace_common::{ExceptionKind, ReturnReason};
11use crate::{TrapFrame, trap::PageFaultFlags};
12
13#[repr(C, align(16))]
15#[derive(Debug, Clone, Copy)]
16pub struct UserContext {
17 tf: TrapFrame,
18 pub sp: u64,
20 pub tpidr: u64,
22}
23
24impl UserContext {
25 const PAD_MAGIC: u64 = 0x1234_5678_9abc_def0;
26 pub fn new(entry: usize, ustack_top: VirtAddr, arg0: usize) -> Self {
29 use aarch64_cpu::registers::SPSR_EL1;
30 let mut regs = [0; 31];
31 regs[0] = arg0 as _;
32 Self {
33 tf: TrapFrame {
34 x: regs,
35 elr: entry as _,
36 spsr: (SPSR_EL1::M::EL0t
37 + SPSR_EL1::D::Masked
38 + SPSR_EL1::A::Masked
39 + SPSR_EL1::I::Unmasked
40 + SPSR_EL1::F::Masked)
41 .value,
42 __pad: Self::PAD_MAGIC,
43 },
44 sp: ustack_top.as_usize() as _,
45 tpidr: 0,
46 }
47 }
48
49 pub fn prepare_clone_child_return_state(&mut self) {
51 use aarch64_cpu::registers::SPSR_EL1;
52
53 self.tf.spsr = (self.tf.spsr
54 & !(SPSR_EL1::M.mask
55 | SPSR_EL1::D.mask
56 | SPSR_EL1::A.mask
57 | SPSR_EL1::I.mask
58 | SPSR_EL1::F.mask))
59 | (SPSR_EL1::M::EL0t
60 + SPSR_EL1::D::Masked
61 + SPSR_EL1::A::Masked
62 + SPSR_EL1::I::Unmasked
63 + SPSR_EL1::F::Masked)
64 .value;
65 }
66
67 pub const fn sp(&self) -> usize {
69 self.sp as _
70 }
71
72 pub const fn set_sp(&mut self, sp: usize) {
74 self.sp = sp as _;
75 }
76
77 pub const fn tls(&self) -> usize {
79 self.tpidr as _
80 }
81
82 pub const fn set_tls(&mut self, tls: usize) {
84 self.tpidr = tls as _;
85 }
86
87 pub fn run(&mut self) -> ReturnReason {
94 unsafe extern "C" {
95 fn enter_user(uctx: &mut UserContext) -> TrapKind;
96 }
97
98 crate::asm::disable_irqs();
99 let kind = unsafe { enter_user(self) };
100
101 let ret = match kind {
102 TrapKind::Irq => {
103 crate::trap::irq_handler(0);
104 ReturnReason::Interrupt
105 }
106 TrapKind::Fiq | TrapKind::SError => ReturnReason::Unknown,
107 TrapKind::Synchronous => {
108 let esr = ESR_EL1.extract();
109 let far = FAR_EL1.get() as usize;
110
111 let iss = esr.read(ESR_EL1::ISS);
112
113 match esr.read_as_enum(ESR_EL1::EC) {
114 Some(ESR_EL1::EC::Value::SVC64) => ReturnReason::Syscall,
115 Some(ESR_EL1::EC::Value::InstrAbortLowerEL) if is_valid_page_fault(iss) => {
116 ReturnReason::PageFault(
117 va!(far),
118 PageFaultFlags::EXECUTE | PageFaultFlags::USER,
119 )
120 }
121 Some(ESR_EL1::EC::Value::DataAbortLowerEL) if is_valid_page_fault(iss) => {
122 let wnr = (iss & (1 << 6)) != 0; let cm = (iss & (1 << 8)) != 0; ReturnReason::PageFault(
125 va!(far),
126 if wnr & !cm {
127 PageFaultFlags::WRITE
128 } else {
129 PageFaultFlags::READ
130 } | PageFaultFlags::USER,
131 )
132 }
133 _ => ReturnReason::Exception(ExceptionInfo { esr, far }),
134 }
135 }
136 };
137
138 crate::asm::enable_irqs();
139 ret
140 }
141}
142
143impl Deref for UserContext {
144 type Target = TrapFrame;
145
146 fn deref(&self) -> &Self::Target {
147 &self.tf
148 }
149}
150
151impl DerefMut for UserContext {
152 fn deref_mut(&mut self) -> &mut Self::Target {
153 &mut self.tf
154 }
155}
156
157#[derive(Debug, Clone, Copy)]
159pub struct ExceptionInfo {
160 pub esr: LocalRegisterCopy<u64, ESR_EL1::Register>,
162 pub far: usize,
164}
165
166impl ExceptionInfo {
167 pub fn esr_value(&self) -> u64 {
169 self.esr.get()
170 }
171
172 pub fn ec_value(&self) -> u64 {
174 self.esr.read(ESR_EL1::EC)
175 }
176
177 pub fn iss_value(&self) -> u64 {
179 self.esr.read(ESR_EL1::ISS)
180 }
181
182 pub fn kind(&self) -> ExceptionKind {
184 match self.esr.read_as_enum(ESR_EL1::EC) {
185 Some(ESR_EL1::EC::Value::Brk64) | Some(ESR_EL1::EC::Value::Bkpt32) => {
186 ExceptionKind::Breakpoint
187 }
188 Some(ESR_EL1::EC::Value::IllegalExecutionState) | Some(ESR_EL1::EC::Value::Unknown) => {
189 ExceptionKind::IllegalInstruction
190 }
191 Some(ESR_EL1::EC::Value::PCAlignmentFault)
192 | Some(ESR_EL1::EC::Value::SPAlignmentFault) => ExceptionKind::Misaligned,
193 _ => ExceptionKind::Other,
194 }
195 }
196}