1use core::{marker::PhantomData, mem};
2
3use tracing::error;
4
5use super::interrupts::stack_index;
6
7core::arch::global_asm!(include_str!("idt_vectors.S"));
8
9extern "C" {
10 static interrupt_vector_table: [u64; 256];
11}
12
13static mut REDIRECTED_INTERRUPTS: [Option<*const u8>; 256] = [None; 256];
14
15pub type BasicInterruptHandler = extern "x86-interrupt" fn(frame: InterruptStackFrame64);
16pub type InterruptHandlerWithError =
17 extern "x86-interrupt" fn(frame: InterruptStackFrame64, error_code: u64);
18pub type InterruptHandlerWithAllState = extern "C" fn(state: &mut InterruptAllSavedState);
19
20#[repr(C, align(8))]
21#[derive(Default, Clone, Copy, Debug)]
22pub struct InterruptStackFrame64 {
23 pub rip: u64,
24 pub cs: u8,
25 pub rflags: u64,
26 pub rsp: u64,
27 pub ss: u8,
28}
29
30#[repr(C, align(8))]
31#[derive(Default, Clone, Copy, Debug)]
32pub struct RestSavedRegisters {
33 pub ds: u64,
34 pub es: u64,
35 pub fs: u64,
36 pub gs: u64,
37 pub dr0: u64,
38 pub dr1: u64,
39 pub dr2: u64,
40 pub dr3: u64,
41 pub dr6: u64,
42 pub dr7: u64,
43 pub rax: u64,
44 pub rbx: u64,
45 pub rcx: u64,
46 pub rdx: u64,
47 pub rsi: u64,
48 pub rdi: u64,
49 pub rbp: u64,
50 pub r8: u64,
51 pub r9: u64,
52 pub r10: u64,
53 pub r11: u64,
54 pub r12: u64,
55 pub r13: u64,
56 pub r14: u64,
57 pub r15: u64,
58}
59
60#[repr(C, align(8))]
61#[derive(Default, Clone, Debug)]
62pub struct InterruptAllSavedState {
63 pub rest: RestSavedRegisters,
64 pub number: u64,
65 pub error: u64,
66 pub frame: InterruptStackFrame64,
67}
68
69mod flags {
70 pub const GATE_TYPE: u8 = 0b1110;
71 pub const KEEP_INTERRUPTS: u8 = 1 << 0;
72 pub const PRESENT: u8 = 1 << 7;
73 pub const fn dpl(ring: u8) -> u8 {
74 ring << 5
75 }
76}
77
78#[repr(C, align(16))]
79#[derive(Default, Clone, Copy)]
80pub(super) struct InterruptDescriptorTableEntry<T> {
81 offset_low: u16,
82 selector: u16,
83 ist: u8,
84 flags: u8,
85 offset_middle: u16,
86 offset_high: u32,
87 zero: u32,
88 phantom: PhantomData<T>,
89}
90
91impl<T> InterruptDescriptorTableEntry<T> {
92 pub const fn empty() -> Self {
93 Self {
94 offset_low: 0,
95 selector: 0,
96 ist: 0,
97 flags: 0,
98 offset_middle: 0,
99 offset_high: 0,
100 zero: 0,
101 phantom: PhantomData,
102 }
103 }
104
105 fn set_handler_ptr(&mut self, handler_addr: u64) -> &mut Self {
106 let cs = super::get_cs();
107 self.offset_low = handler_addr as u16;
108 self.offset_middle = (handler_addr >> 16) as u16;
109 self.offset_high = (handler_addr >> 32) as u32;
110 self.ist = 0;
111 self.selector = cs;
112 self.flags = flags::PRESENT | flags::GATE_TYPE;
113 self
114 }
115
116 pub fn set_stack_index(&mut self, stack_index: Option<u8>) -> &mut Self {
117 let stack_index = stack_index.map(|i| i + 1).unwrap_or(0);
118 assert!(stack_index <= 7);
119 self.ist = stack_index;
120 self
121 }
122
123 pub fn set_disable_interrupts(&mut self, disable_interrupts: bool) -> &mut Self {
124 if disable_interrupts {
125 self.flags &= !flags::KEEP_INTERRUPTS;
126 } else {
127 self.flags |= flags::KEEP_INTERRUPTS;
128 }
129 self
130 }
131
132 #[allow(dead_code)]
133 pub fn override_code_segment(&mut self, cs: u16) -> &mut Self {
134 self.selector = cs;
135 self
136 }
137
138 pub fn set_privilege_level(&mut self, ring: u8) -> &mut Self {
139 self.flags = (self.flags & !flags::dpl(0b11)) | flags::dpl(ring);
140 self
141 }
142}
143
144impl InterruptDescriptorTableEntry<BasicInterruptHandler> {
145 pub fn set_handler(&mut self, handler: BasicInterruptHandler) -> &mut Self {
146 self.set_handler_ptr(handler as *const u8 as u64)
147 }
148}
149
150impl InterruptDescriptorTableEntry<InterruptHandlerWithError> {
151 pub fn set_handler(&mut self, handler: InterruptHandlerWithError) -> &mut Self {
152 self.set_handler_ptr(handler as *const u8 as u64)
153 }
154}
155
156impl<T> InterruptDescriptorTableEntry<T> {
157 pub fn set_handler_with_number(
158 &mut self,
159 handler: InterruptHandlerWithAllState,
160 vector_n: u8,
161 ) -> &mut Self {
162 unsafe {
163 REDIRECTED_INTERRUPTS[vector_n as usize] = Some(handler as *const u8);
165 self.set_handler_ptr(interrupt_vector_table[vector_n as usize] as *const u8 as u64)
166 }
167 }
168}
169
170#[repr(C)]
171pub(super) struct InterruptDescriptorTable {
172 pub divide_by_zero: InterruptDescriptorTableEntry<BasicInterruptHandler>,
173 pub debug: InterruptDescriptorTableEntry<BasicInterruptHandler>,
174 pub non_maskable_interrupt: InterruptDescriptorTableEntry<BasicInterruptHandler>,
175 pub breakpoint: InterruptDescriptorTableEntry<BasicInterruptHandler>,
176 pub overflow: InterruptDescriptorTableEntry<BasicInterruptHandler>,
177 pub bound_range_exceeded: InterruptDescriptorTableEntry<BasicInterruptHandler>,
178 pub invalid_opcode: InterruptDescriptorTableEntry<BasicInterruptHandler>,
179 pub device_not_available: InterruptDescriptorTableEntry<BasicInterruptHandler>,
180 pub double_fault: InterruptDescriptorTableEntry<InterruptHandlerWithError>,
181 pub coprocessor_segment_overrun: InterruptDescriptorTableEntry<()>,
182 pub invalid_tss: InterruptDescriptorTableEntry<InterruptHandlerWithError>,
183 pub segment_not_present: InterruptDescriptorTableEntry<InterruptHandlerWithError>,
184 pub stack_exception: InterruptDescriptorTableEntry<InterruptHandlerWithError>,
185 pub general_protection_fault: InterruptDescriptorTableEntry<InterruptHandlerWithError>,
186 pub page_fault: InterruptDescriptorTableEntry<InterruptHandlerWithError>,
187 pub reserved_1: InterruptDescriptorTableEntry<()>,
188 pub x87_floating_point: InterruptDescriptorTableEntry<BasicInterruptHandler>,
189 pub alignment_check: InterruptDescriptorTableEntry<InterruptHandlerWithError>,
190 pub machine_check: InterruptDescriptorTableEntry<BasicInterruptHandler>,
191 pub simd_floating_point: InterruptDescriptorTableEntry<BasicInterruptHandler>,
192 pub reserved_2: InterruptDescriptorTableEntry<()>,
193 pub control_protection: InterruptDescriptorTableEntry<BasicInterruptHandler>,
194 pub reserved_3: [InterruptDescriptorTableEntry<()>; 6],
195 pub hypervisor_injection: InterruptDescriptorTableEntry<BasicInterruptHandler>,
196 pub vmm_communication: InterruptDescriptorTableEntry<BasicInterruptHandler>,
197 pub security_exception: InterruptDescriptorTableEntry<InterruptHandlerWithError>,
198 pub reserved_4: InterruptDescriptorTableEntry<()>,
199 pub user_defined: [InterruptDescriptorTableEntry<BasicInterruptHandler>; 256 - 32],
200}
201
202impl InterruptDescriptorTable {
203 pub(super) const fn empty() -> Self {
204 Self {
205 divide_by_zero: InterruptDescriptorTableEntry::empty(),
206 debug: InterruptDescriptorTableEntry::empty(),
207 non_maskable_interrupt: InterruptDescriptorTableEntry::empty(),
208 breakpoint: InterruptDescriptorTableEntry::empty(),
209 overflow: InterruptDescriptorTableEntry::empty(),
210 bound_range_exceeded: InterruptDescriptorTableEntry::empty(),
211 invalid_opcode: InterruptDescriptorTableEntry::empty(),
212 device_not_available: InterruptDescriptorTableEntry::empty(),
213 double_fault: InterruptDescriptorTableEntry::empty(),
214 coprocessor_segment_overrun: InterruptDescriptorTableEntry::empty(),
215 invalid_tss: InterruptDescriptorTableEntry::empty(),
216 segment_not_present: InterruptDescriptorTableEntry::empty(),
217 stack_exception: InterruptDescriptorTableEntry::empty(),
218 general_protection_fault: InterruptDescriptorTableEntry::empty(),
219 page_fault: InterruptDescriptorTableEntry::empty(),
220 reserved_1: InterruptDescriptorTableEntry::empty(),
221 x87_floating_point: InterruptDescriptorTableEntry::empty(),
222 alignment_check: InterruptDescriptorTableEntry::empty(),
223 machine_check: InterruptDescriptorTableEntry::empty(),
224 simd_floating_point: InterruptDescriptorTableEntry::empty(),
225 reserved_2: InterruptDescriptorTableEntry::empty(),
226 control_protection: InterruptDescriptorTableEntry::empty(),
227 reserved_3: [InterruptDescriptorTableEntry::empty(); 6],
228 hypervisor_injection: InterruptDescriptorTableEntry::empty(),
229 vmm_communication: InterruptDescriptorTableEntry::empty(),
230 security_exception: InterruptDescriptorTableEntry::empty(),
231 reserved_4: InterruptDescriptorTableEntry::empty(),
232 user_defined: [InterruptDescriptorTableEntry::empty(); 256 - 32],
233 }
234 }
235
236 pub fn init_default_handlers(&mut self) {
237 self.divide_by_zero.set_handler(default_handler::<0>);
238 self.debug.set_handler(default_handler::<1>);
239 self.non_maskable_interrupt
240 .set_handler(default_handler::<2>);
241 self.breakpoint.set_handler(default_handler::<3>);
242 self.overflow.set_handler(default_handler::<4>);
243 self.bound_range_exceeded
244 .set_handler(default_handler::<5>)
245 .set_stack_index(Some(stack_index::FAULTS_STACK));
246 self.invalid_opcode
247 .set_handler(default_handler::<6>)
248 .set_stack_index(Some(stack_index::FAULTS_STACK));
249 self.device_not_available
250 .set_handler(default_handler::<7>)
251 .set_stack_index(Some(stack_index::FAULTS_STACK));
252 self.double_fault
253 .set_handler(default_handler_with_error::<8>)
254 .set_stack_index(Some(stack_index::DOUBLE_FAULT_STACK));
255 self.invalid_tss
256 .set_handler(default_handler_with_error::<10>);
257 self.segment_not_present
258 .set_handler(default_handler_with_error::<11>);
259 self.stack_exception
260 .set_handler(default_handler_with_error::<12>);
261 self.general_protection_fault
262 .set_handler(default_handler_with_error::<13>);
263 self.page_fault
264 .set_handler(default_handler_with_error::<14>)
265 .set_stack_index(Some(stack_index::FAULTS_STACK));
266 self.x87_floating_point.set_handler(default_handler::<16>);
267 self.alignment_check
268 .set_handler(default_handler_with_error::<17>)
269 .set_stack_index(Some(stack_index::FAULTS_STACK));
270 self.machine_check.set_handler(default_handler::<18>);
271 self.simd_floating_point.set_handler(default_handler::<19>);
272 self.control_protection.set_handler(default_handler::<21>);
273 self.hypervisor_injection.set_handler(default_handler::<28>);
274 self.vmm_communication.set_handler(default_handler::<29>);
275 self.security_exception
276 .set_handler(default_handler_with_error::<30>);
277
278 for entry in self.user_defined.iter_mut() {
279 entry.set_handler(default_handler::<0xFF>);
280 }
281 }
282
283 pub(super) fn apply_idt(&'static self) {
284 let idt_ptr = InterruptDescriptorTablePointer {
285 limit: mem::size_of::<InterruptDescriptorTable>() as u16 - 1,
286 base: self,
287 };
288
289 unsafe {
290 super::lidt(&idt_ptr);
291 }
292 }
293}
294
295#[repr(C, packed(2))]
296pub(super) struct InterruptDescriptorTablePointer {
297 limit: u16,
298 base: *const InterruptDescriptorTable,
299}
300
301#[no_mangle]
302pub extern "C" fn rust_interrupt_handler_for_all_state(mut state: InterruptAllSavedState) {
303 let handler = unsafe { REDIRECTED_INTERRUPTS[state.number as usize] };
304 if let Some(handler) = handler {
305 let handler: InterruptHandlerWithAllState = unsafe { mem::transmute(handler) };
306 handler(&mut state);
307 return;
308 }
309
310 panic!("Could not find handler for interrupt {}", state.number);
311}
312
313extern "x86-interrupt" fn default_handler<const N: u8>(frame: InterruptStackFrame64) {
314 error!("[{N}] Got exception: \n frame: {:x?}", frame);
315
316 crate::panic_handler::print_originating_stack_trace(&frame, super::rbp!());
317 panic!("Unhandled exception");
318}
319
320extern "x86-interrupt" fn default_handler_with_error<const N: u8>(
321 frame: InterruptStackFrame64,
322 error_code: u64,
323) {
324 let cr2: u64;
325 unsafe {
326 core::arch:: asm!("mov {}, cr2", out(reg) cr2);
327 }
328 let current_cpu = super::cpu();
329 let proc_id = current_cpu.context.map(|_| current_cpu.process_id);
330 error!(
331 "[{N}] {proc_id:?} Got exception: \n frame: {frame:x?}\n error: {error_code:016X}\n cr2: {cr2:X}",
332 );
333
334 crate::panic_handler::print_originating_stack_trace(&frame, super::rbp!());
335 panic!("Unhandled exception");
336}