1use core::{
4 mem::{align_of, offset_of, size_of},
5 ops::{Deref, DerefMut},
6};
7
8use ax_memory_addr::VirtAddr;
9use x86_64::{
10 registers::{
11 control::{Cr2, Cr4, Cr4Flags},
12 model_specific::{Efer, EferFlags, LStar, SFMask, Star},
13 rflags::RFlags,
14 },
15 structures::idt::ExceptionVector,
16};
17
18use super::{
19 context::TrapFrame,
20 gdt,
21 trap::{IRQ_VECTOR_END, IRQ_VECTOR_START, LEGACY_SYSCALL_VECTOR, err_code_to_flags},
22};
23pub use crate::uspace_common::{ExceptionKind, ExceptionSyndrome, ReturnReason};
24
25#[derive(Debug, Clone, Copy)]
27#[repr(C, align(16))]
28pub struct UserContext {
29 tf: TrapFrame,
30 pub fs_base: u64,
35 pub gs_base: u64,
37 kernel_stack_pointer: u64,
39 _reserved: u64,
41}
42
43unsafe impl bytemuck::NoUninit for UserContext {}
47
48const _: () = {
49 assert!(align_of::<UserContext>() >= 16);
54 assert!(size_of::<TrapFrame>().is_multiple_of(16));
55 assert!(offset_of!(UserContext, tf) == 0);
56 assert!(offset_of!(UserContext, fs_base) == size_of::<TrapFrame>());
57 assert!(offset_of!(UserContext, gs_base) == size_of::<TrapFrame>() + size_of::<u64>());
58 assert!(
59 offset_of!(UserContext, kernel_stack_pointer)
60 == size_of::<TrapFrame>() + 2 * size_of::<u64>()
61 );
62 assert!(offset_of!(UserContext, _reserved) == size_of::<TrapFrame>() + 3 * size_of::<u64>());
63 assert!(size_of::<UserContext>() == size_of::<TrapFrame>() + 4 * size_of::<u64>());
64};
65
66impl UserContext {
67 pub fn new(entry: usize, ustack_top: VirtAddr, arg0: usize) -> Self {
70 use x86_64::registers::rflags::RFlags;
71 Self {
72 tf: TrapFrame {
73 regs: super::registers::GeneralRegisters {
74 rdi: arg0 as _,
75 ..Default::default()
76 },
77 rip: entry as _,
78 cs: gdt::UCODE64.0 as _,
79 rflags: RFlags::INTERRUPT_FLAG.bits(), rsp: ustack_top.as_usize() as _,
81 ss: gdt::UDATA.0 as _,
82 ..Default::default()
83 },
84 fs_base: 0,
85 gs_base: 0,
86 kernel_stack_pointer: 0,
87 _reserved: 0,
88 }
89 }
90
91 pub fn prepare_clone_child_return_state(&mut self) {
93 let mut flags = RFlags::from_bits_truncate(self.tf.rflags);
94 flags.insert(RFlags::INTERRUPT_FLAG);
95 flags.remove(RFlags::TRAP_FLAG | RFlags::NESTED_TASK | RFlags::RESUME_FLAG);
96 self.tf.rflags = flags.bits();
97 }
98
99 pub fn clear_single_step_after_debug(&mut self) -> bool {
103 let mut flags = RFlags::from_bits_truncate(self.tf.rflags);
104 let was_set = flags.contains(RFlags::TRAP_FLAG);
105 flags.remove(RFlags::TRAP_FLAG);
106 self.tf.rflags = flags.bits();
107 was_set
108 }
109
110 pub const fn syscall_insn_len(&self) -> usize {
112 2
113 }
114
115 pub const fn tls(&self) -> usize {
117 self.fs_base as _
118 }
119
120 pub const fn set_tls(&mut self, tls_area: usize) {
122 self.fs_base = tls_area as _;
123 }
124
125 pub fn has_interruptible_user_return_mode(&self) -> bool {
128 let forbidden =
129 RFlags::IOPL_LOW | RFlags::IOPL_HIGH | RFlags::NESTED_TASK | RFlags::VIRTUAL_8086_MODE;
130 let flags = RFlags::from_bits_retain(self.tf.rflags);
131 self.tf.cs == gdt::UCODE64.0 as u64
132 && self.tf.ss == gdt::UDATA.0 as u64
133 && flags.contains(RFlags::INTERRUPT_FLAG)
134 && !flags.intersects(forbidden)
135 }
136
137 pub unsafe fn run_unchecked(&mut self) -> ReturnReason {
155 unsafe extern "C" {
156 fn enter_user(uctx: &mut UserContext);
157 }
158
159 assert!(
160 self.has_interruptible_user_return_mode(),
161 "raw user entry requires an interruptible ring-3 register image"
162 );
163
164 assert!(
165 !crate::asm::irqs_enabled(),
166 "raw user entry requires the prepared IRQ-off boundary"
167 );
168 super::local_state::install_current_user_tls(self.fs_base as _, self.gs_base as _);
169
170 unsafe { enter_user(self) };
171
172 let vector = self.vector as u8;
173
174 const PAGE_FAULT_VECTOR: u8 = ExceptionVector::Page as u8;
175
176 let ret = match (vector, err_code_to_flags(self.error_code)) {
177 (PAGE_FAULT_VECTOR, Ok(flags)) => {
178 ReturnReason::PageFault(va!(Cr2::read_raw() as usize), flags)
179 }
180 (LEGACY_SYSCALL_VECTOR, _) => ReturnReason::Syscall,
181 (IRQ_VECTOR_START..=IRQ_VECTOR_END, _) => {
182 crate::trap::dispatch_irq(
183 vector as _,
184 crate::trap::TrapOrigin::User,
185 Some(self.tf.interrupted_context()),
186 );
187 ReturnReason::Interrupt
188 }
189 _ => ReturnReason::Exception(ExceptionInfo {
190 vector,
191 error_code: self.error_code,
192 cr2: Cr2::read_raw() as usize,
193 }),
194 };
195
196 crate::asm::enable_irqs();
197 ret
198 }
199}
200
201const _: unsafe fn(&mut UserContext) -> ReturnReason = UserContext::run_unchecked;
202
203impl Deref for UserContext {
204 type Target = TrapFrame;
205
206 fn deref(&self) -> &Self::Target {
207 &self.tf
208 }
209}
210
211impl DerefMut for UserContext {
212 fn deref_mut(&mut self) -> &mut Self::Target {
213 &mut self.tf
214 }
215}
216
217#[derive(Debug, Clone, Copy)]
219pub struct ExceptionInfo {
220 pub vector: u8,
222 pub error_code: u64,
224 pub cr2: usize,
226}
227
228impl ExceptionInfo {
229 pub const fn fault_addr(&self) -> Option<usize> {
231 Some(self.cr2)
232 }
233
234 pub const fn syndrome(&self) -> ExceptionSyndrome {
236 ExceptionSyndrome {
237 raw: self.error_code,
238 class: self.vector as u64,
239 iss: 0,
240 }
241 }
242
243 pub fn kind(&self) -> ExceptionKind {
245 match ExceptionVector::try_from(self.vector) {
246 Ok(ExceptionVector::Debug) => ExceptionKind::Debug,
247 Ok(ExceptionVector::Breakpoint) => ExceptionKind::Breakpoint,
248 Ok(ExceptionVector::InvalidOpcode) => ExceptionKind::IllegalInstruction,
249 Ok(ExceptionVector::Division) => ExceptionKind::ArithmeticError,
253 _ => ExceptionKind::Other,
254 }
255 }
256}
257
258pub(super) fn init_syscall() {
260 unsafe extern "C" {
261 fn syscall_entry();
262 }
263
264 assert!(
265 !Cr4::read().contains(Cr4Flags::FSGSBASE),
266 "LinuxCurrent user TLS requires trapping all FS/GS base changes"
267 );
268 super::local_state::initialize_cpu_user_tls();
269 LStar::write(x86_64::VirtAddr::new_truncate(
270 syscall_entry as *const () as usize as _,
271 ));
272 Star::write(gdt::UCODE64, gdt::UDATA, gdt::KCODE64, gdt::KDATA).unwrap();
273 SFMask::write(
274 RFlags::TRAP_FLAG
275 | RFlags::INTERRUPT_FLAG
276 | RFlags::DIRECTION_FLAG
277 | RFlags::IOPL_LOW
278 | RFlags::IOPL_HIGH
279 | RFlags::NESTED_TASK
280 | RFlags::ALIGNMENT_CHECK,
281 ); unsafe {
283 Efer::update(|efer| *efer |= EferFlags::SYSTEM_CALL_EXTENSIONS);
284 }
285}