use spin::{Lazy, Mutex}; use x2apic::lapic::{LocalApic, LocalApicBuilder}; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; use crate::interp::wasm; pub unsafe fn init() { log::info!("Initialising IDT"); IDT.load(); Lazy::force(&LAPIC); x86_64::instructions::interrupts::enable(); } #[repr(u8)] enum Interrupt { Timer = 32, ApicErr = u8::MAX - 1, Spurious = u8::MAX, } pub(crate) static LAPIC: Lazy> = Lazy::new(|| { let mut lapic = LocalApicBuilder::new() .timer_vector(Interrupt::Timer as usize) .error_vector(Interrupt::ApicErr as usize) .spurious_vector(Interrupt::Spurious as usize) .set_xapic_base( unsafe { x2apic::lapic::xapic_base() } + super::memory::HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed), ) .build() .expect("failed to setup Local APIC"); unsafe { lapic.enable() }; Mutex::new(lapic) }); static IDT: Lazy = Lazy::new(|| { let mut idt = InterruptDescriptorTable::new(); unsafe { 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 usize].set_handler_fn(apic_err); idt[Interrupt::Spurious as usize].set_handler_fn(spurious); idt[Interrupt::Timer as usize].set_handler_fn(timer); idt }); 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.lock().end_of_interrupt() }; } extern "x86-interrupt" fn apic_err(_: InterruptStackFrame) { panic!("Internal APIC error"); } extern "x86-interrupt" fn spurious(_: InterruptStackFrame) { unsafe { LAPIC.lock().end_of_interrupt() }; }