1use core::ops::{Deref, DerefMut};
4
5use ax_memory_addr::VirtAddr;
6use x86_64::{
7 registers::{
8 control::Cr2,
9 model_specific::{Efer, EferFlags, KernelGsBase, LStar, SFMask, Star},
10 rflags::RFlags,
11 },
12 structures::idt::ExceptionVector,
13};
14
15use super::{
16 TrapFrame,
17 asm::{read_thread_pointer, write_thread_pointer},
18 gdt,
19 trap::{IRQ_VECTOR_END, IRQ_VECTOR_START, LEGACY_SYSCALL_VECTOR, err_code_to_flags},
20};
21pub use crate::uspace_common::{ExceptionKind, ReturnReason};
22
23#[derive(Debug, Clone, Copy)]
25#[repr(C)]
26pub struct UserContext {
27 tf: TrapFrame,
28 pub fs_base: u64,
30 pub gs_base: u64,
32}
33
34impl UserContext {
35 pub fn new(entry: usize, ustack_top: VirtAddr, arg0: usize) -> Self {
38 use x86_64::registers::rflags::RFlags;
39 Self {
40 tf: TrapFrame {
41 rdi: arg0 as _,
42 rip: entry as _,
43 cs: gdt::UCODE64.0 as _,
44 rflags: RFlags::INTERRUPT_FLAG.bits(), rsp: ustack_top.as_usize() as _,
46 ss: gdt::UDATA.0 as _,
47 ..Default::default()
48 },
49 fs_base: 0,
50 gs_base: 0,
51 }
52 }
53
54 pub const fn tls(&self) -> usize {
56 self.fs_base as _
57 }
58
59 pub const fn set_tls(&mut self, tls_area: usize) {
61 self.fs_base = tls_area as _;
62 }
63
64 pub fn run(&mut self) -> ReturnReason {
71 extern "C" {
72 fn enter_user(uctx: &mut UserContext);
73 }
74
75 assert_eq!(self.cs, gdt::UCODE64.0 as _);
76 assert_eq!(self.ss, gdt::UDATA.0 as _);
77
78 crate::asm::disable_irqs();
79
80 let kernel_fs_base = read_thread_pointer();
81 unsafe { write_thread_pointer(self.fs_base as _) };
82 KernelGsBase::write(x86_64::VirtAddr::new_truncate(self.gs_base));
83
84 unsafe { enter_user(self) };
85
86 self.gs_base = KernelGsBase::read().as_u64();
87 self.fs_base = read_thread_pointer() as _;
88 unsafe { write_thread_pointer(kernel_fs_base) };
89
90 let cr2 = Cr2::read().unwrap().as_u64() as usize;
91 let vector = self.vector as u8;
92
93 const PAGE_FAULT_VECTOR: u8 = ExceptionVector::Page as u8;
94
95 let ret = match (vector, err_code_to_flags(self.error_code)) {
96 (PAGE_FAULT_VECTOR, Ok(flags)) => ReturnReason::PageFault(va!(cr2), flags),
97 (LEGACY_SYSCALL_VECTOR, _) => ReturnReason::Syscall,
98 (IRQ_VECTOR_START..=IRQ_VECTOR_END, _) => {
99 crate::trap::irq_handler(vector as _);
100 ReturnReason::Interrupt
101 }
102 _ => ReturnReason::Exception(ExceptionInfo {
103 vector,
104 error_code: self.error_code,
105 cr2,
106 }),
107 };
108
109 crate::asm::enable_irqs();
110 ret
111 }
112}
113
114impl Deref for UserContext {
115 type Target = TrapFrame;
116
117 fn deref(&self) -> &Self::Target {
118 &self.tf
119 }
120}
121
122impl DerefMut for UserContext {
123 fn deref_mut(&mut self) -> &mut Self::Target {
124 &mut self.tf
125 }
126}
127
128#[derive(Debug, Clone, Copy)]
130pub struct ExceptionInfo {
131 pub vector: u8,
133 pub error_code: u64,
135 pub cr2: usize,
137}
138
139impl ExceptionInfo {
140 pub fn kind(&self) -> ExceptionKind {
142 match ExceptionVector::try_from(self.vector) {
143 Ok(ExceptionVector::Debug) => ExceptionKind::Debug,
144 Ok(ExceptionVector::Breakpoint) => ExceptionKind::Breakpoint,
145 Ok(ExceptionVector::InvalidOpcode) => ExceptionKind::IllegalInstruction,
146 _ => ExceptionKind::Other,
147 }
148 }
149}
150
151pub(super) fn init_syscall() {
153 extern "C" {
154 fn syscall_entry();
155 }
156
157 LStar::write(x86_64::VirtAddr::new_truncate(
158 syscall_entry as *const () as usize as _,
159 ));
160 Star::write(gdt::UCODE64, gdt::UDATA, gdt::KCODE64, gdt::KDATA).unwrap();
161 SFMask::write(
162 RFlags::TRAP_FLAG
163 | RFlags::INTERRUPT_FLAG
164 | RFlags::DIRECTION_FLAG
165 | RFlags::IOPL_LOW
166 | RFlags::IOPL_HIGH
167 | RFlags::NESTED_TASK
168 | RFlags::ALIGNMENT_CHECK,
169 ); unsafe {
171 Efer::update(|efer| *efer |= EferFlags::SYSTEM_CALL_EXTENSIONS);
172 }
173}