Skip to main content

kernel/arch/x86_64/tables/
idt.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! Interrupt Descriptor Table (IDT): maps every interrupt vector to its handler
3//! and loads the table into the CPU.
4//!
5//! Authors: MarioS271
6
7use crate::kinfo;
8use spin::Once;
9use x86_64::structures::idt::InterruptDescriptorTable;
10
11/// The single kernel IDT; must not move after loading (the CPU holds its address).
12pub struct Idt {
13    table: Once<InterruptDescriptorTable>
14}
15impl Idt {
16    /// Create a new, unloaded `Idt`; call [`Idt::init`] to populate and load it.
17    pub const fn new() -> Self {
18        Self {
19            table: Once::new()
20        }
21    }
22
23    /// Build and load the IDT with all exception and IRQ handlers.
24    pub fn init(&'static self) {
25        self.table.call_once(|| {
26            let mut idt = InterruptDescriptorTable::new();
27
28            use crate::arch::x86_64::interrupts::{exceptions, irqs};
29            use super::tss::{DOUBLE_FAULT_IST_STACK_INDEX, DEBUG_IST_STACK_INDEX, NMI_IST_STACK_INDEX, MACHINE_CHECK_IST_STACK_INDEX};
30
31            // Faults
32            idt.divide_error.set_handler_fn(exceptions::_0_divide_error::handler);
33            unsafe { idt.debug.set_handler_fn(exceptions::_1_debug::handler).set_stack_index(DEBUG_IST_STACK_INDEX as u16); }
34            unsafe { idt.non_maskable_interrupt.set_handler_fn(exceptions::_2_non_maskable_interrupt::handler).set_stack_index(NMI_IST_STACK_INDEX as u16); }
35            idt.breakpoint.set_handler_fn(exceptions::_3_breakpoint::handler);
36            idt.overflow.set_handler_fn(exceptions::_4_overflow::handler);
37            idt.bound_range_exceeded.set_handler_fn(exceptions::invalid_fault_handler::handler::<5>);
38            idt.invalid_opcode.set_handler_fn(exceptions::_6_invalid_opcode::handler);
39            idt.device_not_available.set_handler_fn(exceptions::_7_device_not_avail::handler);
40            unsafe { idt.double_fault.set_handler_fn(exceptions::_8_double_fault::handler).set_stack_index(DOUBLE_FAULT_IST_STACK_INDEX as u16); }
41            idt.invalid_tss.set_handler_fn(exceptions::_10_invalid_tss::handler);
42            idt.segment_not_present.set_handler_fn(exceptions::_11_segment_not_present::handler);
43            idt.stack_segment_fault.set_handler_fn(exceptions::_12_stack_segment_fault::handler);
44            idt.general_protection_fault.set_handler_fn(exceptions::_13_general_protection_fault::handler);
45            idt.page_fault.set_handler_fn(exceptions::_14_page_fault::handler);
46            idt.x87_floating_point.set_handler_fn(exceptions::_16_x87_floating_point::handler);
47            idt.alignment_check.set_handler_fn(exceptions::_17_alignment_check::handler);
48            unsafe { idt.machine_check.set_handler_fn(exceptions::_18_machine_check::handler).set_stack_index(MACHINE_CHECK_IST_STACK_INDEX as u16); }
49            idt.simd_floating_point.set_handler_fn(exceptions::_19_simd_floating_point::handler);
50            idt.virtualization.set_handler_fn(exceptions::_20_virtualization::handler);
51            idt.vmm_communication_exception.set_handler_fn(exceptions::_29_vmm_communication_exception::handler);
52            idt.security_exception.set_handler_fn(exceptions::_30_security_exception::handler);
53
54            // IRQs
55            idt[32].set_handler_fn(irqs::irq0_timer::handler);
56
57            idt
58        });
59
60        self.table.get().unwrap().load();
61
62        kinfo!("Initialized IDT");
63    }
64}