kernel/cpu/
idt.rs

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            // save first as it might get called right away
164            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}