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#[derive(Debug, Default, Clone, Copy)]
65#[repr(C)]
66#[expect(missing_docs)]
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 pub _pad: usize,
86
87 pub trap_num: usize,
88 pub error_code: usize,
89
90 pub rip: usize,
92 pub cs: usize,
93 pub rflags: usize,
94}
95
96pub(crate) unsafe fn init_on_cpu() {
115 unsafe { gdt::init_on_cpu() };
117
118 idt::init_on_cpu();
119
120 unsafe { syscall::init_on_cpu() };
122}
123
124#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
126#[repr(C)]
127pub(super) struct RawUserContext {
128 pub(super) general: GeneralRegs,
129 pub(super) trap_num: usize,
130 pub(super) error_code: usize,
131}
132
133#[unsafe(no_mangle)]
136unsafe extern "sysv64" fn trap_handler(f: &mut TrapFrame) {
137 fn enable_local_if(cond: bool) {
138 if cond {
139 enable_local();
140 }
141 }
142
143 fn disable_local_if(cond: bool) {
144 if cond {
145 disable_local();
146 }
147 }
148
149 let was_irq_enabled =
152 f.rflags as u64 & x86_64::registers::rflags::RFlags::INTERRUPT_FLAG.bits() > 0;
153
154 let cpu_exception = CpuException::new(f.trap_num, f.error_code);
155 match cpu_exception {
156 #[cfg(feature = "cvm_guest")]
157 Some(CpuException::VirtualizationException) => {
158 let ve_info = tdcall::get_veinfo().expect("#VE handler: fail to get VE info\n");
159 enable_local_if(was_irq_enabled);
162 let mut trapframe_wrapper = TrapFrameWrapper(&mut *f);
163 handle_virtual_exception(&mut trapframe_wrapper, &ve_info);
164 *f = *trapframe_wrapper.0;
165 disable_local_if(was_irq_enabled);
166 }
167 Some(CpuException::PageFault(raw_page_fault_info)) => {
168 enable_local_if(was_irq_enabled);
169 if (0..MAX_USERSPACE_VADDR).contains(&raw_page_fault_info.addr) {
172 handle_user_page_fault(f, cpu_exception.as_ref().unwrap());
173 } else {
174 panic!(
175 "Cannot handle kernel page fault: {:#x?}; trapframe: {:#x?}",
176 raw_page_fault_info, f
177 );
178 }
179 disable_local_if(was_irq_enabled);
180 }
181 Some(exception) => {
182 enable_local_if(was_irq_enabled);
183 panic!(
184 "Cannot handle kernel CPU exception: {:#x?}; trapframe: {:#x?}",
185 exception, f
186 );
187 }
188 None => {
189 call_irq_callback_functions(
190 f,
191 &HwIrqLine::new(f.trap_num as u8),
192 PrivilegeLevel::Kernel,
193 );
194 }
195 }
196}
197
198#[expect(clippy::type_complexity)]
199static USER_PAGE_FAULT_HANDLER: Once<fn(&CpuException) -> core::result::Result<(), ()>> =
200 Once::new();
201
202pub fn inject_user_page_fault_handler(
205 handler: fn(info: &CpuException) -> core::result::Result<(), ()>,
206) {
207 USER_PAGE_FAULT_HANDLER.call_once(|| handler);
208}
209
210fn handle_user_page_fault(f: &mut TrapFrame, exception: &CpuException) {
212 let handler = USER_PAGE_FAULT_HANDLER
213 .get()
214 .expect("a page fault handler is missing");
215
216 let res = handler(exception);
217 if res.is_ok() {
220 return;
221 }
222
223 if let Some(addr) = ExTable::find_recovery_inst_addr(f.rip) {
225 f.rip = addr;
226 } else {
227 panic!("Cannot handle user page fault; trapframe: {:#x?}", f);
228 }
229}