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 r8: usize,
77 pub r9: usize,
78 pub r10: usize,
79 pub r11: usize,
80 pub r12: usize,
81 pub r13: usize,
82 pub r14: usize,
83 pub r15: usize,
84
85 pub trap_num: usize,
86 pub error_code: usize,
87
88 pub rip: usize,
90 pub cs: usize,
91 pub rflags: usize,
92 pub rsp: usize,
93 pub ss: usize,
94}
95
96crate::const_assert!(size_of::<TrapFrame>().is_multiple_of(16));
104
105pub(crate) unsafe fn init_on_cpu() {
124 unsafe { gdt::init_on_cpu() };
126
127 idt::init_on_cpu();
128
129 unsafe { syscall::init_on_cpu() };
131}
132
133#[repr(C)]
135#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
136pub(super) struct RawUserContext {
137 pub(super) general: GeneralRegs,
138 pub(super) trap_num: usize,
139 pub(super) error_code: usize,
140}
141
142#[unsafe(no_mangle)]
145unsafe extern "sysv64" fn trap_handler(f: &mut TrapFrame) {
146 fn enable_local_if(cond: bool) {
147 if cond {
148 enable_local();
149 }
150 }
151
152 fn disable_local_if(cond: bool) {
153 if cond {
154 disable_local();
155 }
156 }
157
158 let was_irq_enabled =
161 f.rflags as u64 & x86_64::registers::rflags::RFlags::INTERRUPT_FLAG.bits() > 0;
162
163 let cpu_exception = CpuException::new(f.trap_num, f.error_code);
164 match cpu_exception {
165 #[cfg(feature = "cvm_guest")]
166 Some(CpuException::VirtualizationException) => {
167 let ve_info = tdcall::get_veinfo().expect("#VE handler: fail to get VE info\n");
168 enable_local_if(was_irq_enabled);
171 let mut trapframe_wrapper = TrapFrameWrapper(&mut *f);
172 handle_virtual_exception(&mut trapframe_wrapper, &ve_info);
173 *f = *trapframe_wrapper.0;
174 disable_local_if(was_irq_enabled);
175 }
176 Some(CpuException::PageFault(raw_page_fault_info)) => {
177 enable_local_if(was_irq_enabled);
178 if (0..MAX_USERSPACE_VADDR).contains(&raw_page_fault_info.addr) {
181 handle_user_page_fault(f, cpu_exception.as_ref().unwrap());
182 } else {
183 panic!(
184 "Cannot handle kernel page fault: {:#x?}; trapframe: {:#x?}",
185 raw_page_fault_info, f
186 );
187 }
188 disable_local_if(was_irq_enabled);
189 }
190 Some(exception) => {
191 enable_local_if(was_irq_enabled);
192 panic!(
193 "Cannot handle kernel CPU exception: {:#x?}; trapframe: {:#x?}",
194 exception, f
195 );
196 }
197 None => {
198 call_irq_callback_functions(
199 f,
200 &HwIrqLine::new(f.trap_num as u8),
201 PrivilegeLevel::Kernel,
202 );
203 }
204 }
205}
206
207#[expect(clippy::type_complexity)]
208static USER_PAGE_FAULT_HANDLER: Once<fn(&CpuException) -> Result<(), ()>> = Once::new();
209
210pub fn inject_user_page_fault_handler(handler: fn(info: &CpuException) -> Result<(), ()>) {
213 USER_PAGE_FAULT_HANDLER.call_once(|| handler);
214}
215
216fn handle_user_page_fault(f: &mut TrapFrame, exception: &CpuException) {
218 let handler = USER_PAGE_FAULT_HANDLER
219 .get()
220 .expect("a page fault handler is missing");
221
222 let res = handler(exception);
223 if res.is_ok() {
226 return;
227 }
228
229 if let Some(addr) = ExTable::find_recovery_inst_addr(f.rip) {
231 f.rip = addr;
232 } else {
233 panic!("Cannot handle user page fault; trapframe: {:#x?}", f);
234 }
235}
236
237pub const USER_CS_VALUE: usize = gdt::USER_CS.0 as usize;
239pub const USER_SS_VALUE: usize = gdt::USER_SS.0 as usize;