axhal/arch/x86_64/
idt.rs

1use core::fmt;
2
3use lazyinit::LazyInit;
4use x86_64::addr::VirtAddr;
5use x86_64::structures::DescriptorTablePointer;
6use x86_64::structures::idt::{Entry, HandlerFunc, InterruptDescriptorTable};
7
8const NUM_INT: usize = 256;
9
10static IDT: LazyInit<IdtStruct> = LazyInit::new();
11
12/// A wrapper of the Interrupt Descriptor Table (IDT).
13#[repr(transparent)]
14pub struct IdtStruct {
15    table: InterruptDescriptorTable,
16}
17
18impl IdtStruct {
19    /// Constructs a new IDT struct that filled with entries from
20    /// `trap_handler_table`.
21    #[allow(clippy::new_without_default)]
22    pub fn new() -> Self {
23        unsafe extern "C" {
24            #[link_name = "trap_handler_table"]
25            static ENTRIES: [extern "C" fn(); NUM_INT];
26        }
27        let mut idt = Self {
28            table: InterruptDescriptorTable::new(),
29        };
30
31        let entries = unsafe {
32            core::slice::from_raw_parts_mut(
33                &mut idt.table as *mut _ as *mut Entry<HandlerFunc>,
34                NUM_INT,
35            )
36        };
37        for i in 0..NUM_INT {
38            #[allow(clippy::missing_transmute_annotations)]
39            let opt = entries[i].set_handler_fn(unsafe { core::mem::transmute(ENTRIES[i]) });
40            if i == 0x3 || i == 0x80 {
41                // enable user space breakpoints and legacy int 0x80 syscall
42                opt.set_privilege_level(x86_64::PrivilegeLevel::Ring3);
43            }
44        }
45        idt
46    }
47
48    /// Returns the IDT pointer (base and limit) that can be used in the `lidt`
49    /// instruction.
50    pub fn pointer(&self) -> DescriptorTablePointer {
51        DescriptorTablePointer {
52            base: VirtAddr::new(&self.table as *const _ as u64),
53            limit: (core::mem::size_of::<InterruptDescriptorTable>() - 1) as u16,
54        }
55    }
56
57    /// Loads the IDT into the CPU (executes the `lidt` instruction).
58    ///
59    /// # Safety
60    ///
61    /// This function is unsafe because it manipulates the CPU's privileged
62    /// states.
63    pub unsafe fn load(&'static self) {
64        self.table.load();
65    }
66}
67
68impl fmt::Debug for IdtStruct {
69    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70        f.debug_struct("IdtStruct")
71            .field("pointer", &self.pointer())
72            .field("table", &self.table)
73            .finish()
74    }
75}
76
77/// Initializes the global IDT and loads it into the current CPU.
78pub fn init_idt() {
79    IDT.call_once(IdtStruct::new);
80    unsafe { IDT.load() };
81}