// SPDX-License-Identifier: MPL-2.0 #![allow(dead_code)] use alloc::sync::Arc; use log::info; use spin::Once; use crate::sync::SpinLock; pub mod ioapic; pub mod x2apic; pub mod xapic; pub static APIC_INSTANCE: Once>> = Once::new(); pub trait Apic: ApicTimer + Sync + Send { fn id(&self) -> u32; fn version(&self) -> u32; /// End of Interrupt, this function will inform APIC that this interrupt has been processed. fn eoi(&mut self); } pub trait ApicTimer: Sync + Send { /// Sets the initial timer count, the APIC timer will count down from this value. fn set_timer_init_count(&mut self, value: u64); /// Gets the current count of the timer. /// The interval can be expressed by the expression: `init_count` - `current_count`. fn timer_current_count(&self) -> u64; /// Sets the timer register in the APIC. /// Bit 0-7: The interrupt vector of timer interrupt. /// Bit 12: Delivery Status, 0 for Idle, 1 for Send Pending. /// Bit 16: Mask bit. /// Bit 17-18: Timer Mode, 0 for One-shot, 1 for Periodic, 2 for TSC-Deadline. fn set_lvt_timer(&mut self, value: u64); /// Sets timer divide config register. fn set_timer_div_config(&mut self, div_config: DivideConfig); } #[derive(Debug)] pub enum ApicInitError { /// No x2APIC or xAPIC found. NoApic, } #[derive(Debug)] #[repr(u32)] pub enum DivideConfig { Divide1 = 0b1011, Divide2 = 0b0000, Divide4 = 0b0001, Divide8 = 0b0010, Divide16 = 0b0011, Divide32 = 0b1000, Divide64 = 0b1001, Divide128 = 0b1010, } pub fn init() -> Result<(), ApicInitError> { crate::arch::x86::kernel::pic::disable_temp(); if let Some(mut x2apic) = x2apic::X2Apic::new() { x2apic.enable(); let version = x2apic.version(); info!( "x2APIC ID:{:x}, Version:{:x}, Max LVT:{:x}", x2apic.id(), version & 0xff, (version >> 16) & 0xff ); APIC_INSTANCE.call_once(|| Arc::new(SpinLock::new(x2apic))); Ok(()) } else if let Some(mut xapic) = xapic::XApic::new() { xapic.enable(); let version = xapic.version(); info!( "xAPIC ID:{:x}, Version:{:x}, Max LVT:{:x}", xapic.id(), version & 0xff, (version >> 16) & 0xff ); APIC_INSTANCE.call_once(|| Arc::new(SpinLock::new(xapic))); Ok(()) } else { log::warn!("Not found x2APIC or xAPIC"); Err(ApicInitError::NoApic) } }