ostd/arch/x86/trap/
mod.rs1pub(super) mod gdt;
20mod idt;
21mod syscall;
22
23use cfg_if::cfg_if;
24use spin::Once;
25
26use super::cpu::context::GeneralRegs;
27use crate::{
28 arch::{
29 cpu::context::CpuException,
30 irq::{HwIrqLine, disable_local, enable_local},
31 },
32 cpu::PrivilegeLevel,
33 ex_table::ExTable,
34 irq::call_irq_callback_functions,
35 mm::MAX_USERSPACE_VADDR,
36};
37
38cfg_if! {
39 if #[cfg(feature = "cvm_guest")] {
40 use tdx_guest::{tdcall, handle_virtual_exception};
41 use crate::arch::tdx_guest::TrapFrameWrapper;
42 }
43}
44
45#[expect(missing_docs)]
65#[repr(C)]
66#[derive(Clone, Copy, Debug, Default)]
67pub struct TrapFrame {
68 pub rax: usize,
70 pub rbx: usize,
71 pub rcx: usize,
72 pub rdx: usize,
73 pub rsi: usize,
74 pub rdi: usize,
75 pub rbp: usize,
76 pub rsp: usize,
77 pub r8: usize,
78 pub r9: usize,
79 pub r10: usize,
80 pub r11: usize,
81 pub r12: usize,
82 pub r13: usize,
83 pub r14: usize,
84 pub r15: usize,
85
86 pub trap_num: usize,
87 pub error_code: usize,
88
89 pub rip: usize,
91 pub cs: usize,
92 pub rflags: usize,
93}
94
95pub(crate) unsafe fn init_on_cpu() {
114 unsafe { gdt::init_on_cpu() };
116
117 idt::init_on_cpu();
118
119 unsafe { syscall::init_on_cpu() };
121}
122
123#[repr(C)]
125#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
126pub(super) struct RawUserContext {
127 pub(super) general: GeneralRegs,
128 pub(super) trap_num: usize,
129 pub(super) error_code: usize,
130}
131
132#[unsafe(no_mangle)]
135unsafe extern "sysv64" fn trap_handler(f: &mut TrapFrame) {
136 fn enable_local_if(cond: bool) {
137 if cond {
138 enable_local();
139 }
140 }
141
142 fn disable_local_if(cond: bool) {
143 if cond {
144 disable_local();
145 }
146 }
147
148 let was_irq_enabled =
151 f.rflags as u64 & x86_64::registers::rflags::RFlags::INTERRUPT_FLAG.bits() > 0;
152
153 let cpu_exception = CpuException::new(f.trap_num, f.error_code);
154 match cpu_exception {
155 #[cfg(feature = "cvm_guest")]
156 Some(CpuException::VirtualizationException) => {
157 let ve_info = tdcall::get_veinfo().expect("#VE handler: fail to get VE info\n");
158 enable_local_if(was_irq_enabled);
161 let mut trapframe_wrapper = TrapFrameWrapper(&mut *f);
162 handle_virtual_exception(&mut trapframe_wrapper, &ve_info);
163 *f = *trapframe_wrapper.0;
164 disable_local_if(was_irq_enabled);
165 }
166 Some(CpuException::PageFault(raw_page_fault_info)) => {
167 enable_local_if(was_irq_enabled);
168 if (0..MAX_USERSPACE_VADDR).contains(&raw_page_fault_info.addr) {
171 handle_user_page_fault(f, cpu_exception.as_ref().unwrap());
172 } else {
173 panic!(
174 "Cannot handle kernel page fault: {:#x?}; trapframe: {:#x?}",
175 raw_page_fault_info, f
176 );
177 }
178 disable_local_if(was_irq_enabled);
179 }
180 Some(exception) => {
181 enable_local_if(was_irq_enabled);
182 panic!(
183 "Cannot handle kernel CPU exception: {:#x?}; trapframe: {:#x?}",
184 exception, f
185 );
186 }
187 None => {
188 call_irq_callback_functions(
189 f,
190 &HwIrqLine::new(f.trap_num as u8),
191 PrivilegeLevel::Kernel,
192 );
193 }
194 }
195}
196
197#[expect(clippy::type_complexity)]
198static USER_PAGE_FAULT_HANDLER: Once<fn(&CpuException) -> Result<(), ()>> = Once::new();
199
200pub fn inject_user_page_fault_handler(handler: fn(info: &CpuException) -> Result<(), ()>) {
203 USER_PAGE_FAULT_HANDLER.call_once(|| handler);
204}
205
206fn handle_user_page_fault(f: &mut TrapFrame, exception: &CpuException) {
208 let handler = USER_PAGE_FAULT_HANDLER
209 .get()
210 .expect("a page fault handler is missing");
211
212 let res = handler(exception);
213 if res.is_ok() {
216 return;
217 }
218
219 if let Some(addr) = ExTable::find_recovery_inst_addr(f.rip) {
221 f.rip = addr;
222 } else {
223 panic!("Cannot handle user page fault; trapframe: {:#x?}", f);
224 }
225}
226
227pub const USER_CS_VALUE: usize = gdt::USER_CS.0 as usize;
229pub const USER_SS_VALUE: usize = gdt::USER_SS.0 as usize;