use { core::mem::MaybeUninit, log::trace, x2apic::lapic::{LocalApic, LocalApicBuilder}, x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}, }; /// Safety: Using LAPIC or IDT before init() is UB /// Using static mut LAPIC: LocalApic = unsafe { MaybeUninit::zeroed().assume_init() }; static mut IDT: InterruptDescriptorTable = unsafe { MaybeUninit::zeroed().assume_init() }; #[repr(u8)] enum Interrupt { Timer = 32, ApicErr = u8::MAX - 1, Spurious = u8::MAX, } pub unsafe fn init() { trace!("Initializing IDT and LAPIC"); // Initialize and load the IDT IDT = InterruptDescriptorTable::new(); IDT.double_fault .set_handler_fn(double_fault) .set_stack_index(super::gdt::DOUBLE_FAULT_IX); IDT.page_fault.set_handler_fn(page_fault); IDT[Interrupt::ApicErr as u8].set_handler_fn(apic_err); IDT[Interrupt::Spurious as u8].set_handler_fn(spurious); IDT[Interrupt::Timer as u8].set_handler_fn(timer); IDT.load(); LAPIC = LocalApicBuilder::new() .timer_vector(Interrupt::Timer as usize) .error_vector(Interrupt::ApicErr as usize) .spurious_vector(Interrupt::Spurious as usize) .set_xapic_base( x2apic::lapic::xapic_base() + super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed), ) .build() .expect("Failed to setup Local APIC"); LAPIC.enable(); x86_64::instructions::interrupts::enable(); } extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, error_code: u64) -> ! { panic!("Double fault: error code {error_code} \n{stack_frame:#?}") } extern "x86-interrupt" fn page_fault( stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode, ) { panic!("Page fault ({error_code:?}): {stack_frame:?}") } extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) { unsafe { LAPIC.end_of_interrupt(); } } extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) { panic!("Internal APIC error"); } extern "x86-interrupt" fn spurious(_: InterruptStackFrame) { unsafe { LAPIC.end_of_interrupt(); } }