axhal/platform/x86_pc/
apic.rs1#![allow(dead_code)]
2
3use core::{cell::SyncUnsafeCell, mem::MaybeUninit};
4
5use kspin::SpinNoIrq;
6use lazyinit::LazyInit;
7use memory_addr::PhysAddr;
8use x2apic::ioapic::IoApic;
9use x2apic::lapic::{LocalApic, LocalApicBuilder, xapic_base};
10use x86_64::instructions::port::Port;
11
12use self::vectors::*;
13use crate::mem::phys_to_virt;
14
15pub(super) mod vectors {
16 pub const APIC_TIMER_VECTOR: u8 = 0xf0;
17 pub const APIC_SPURIOUS_VECTOR: u8 = 0xf1;
18 pub const APIC_ERROR_VECTOR: u8 = 0xf2;
19}
20
21pub const MAX_IRQ_COUNT: usize = 256;
23
24pub const TIMER_IRQ_NUM: usize = APIC_TIMER_VECTOR as usize;
26
27const IO_APIC_BASE: PhysAddr = pa!(0xFEC0_0000);
28
29static LOCAL_APIC: SyncUnsafeCell<MaybeUninit<LocalApic>> =
30 SyncUnsafeCell::new(MaybeUninit::uninit());
31static mut IS_X2APIC: bool = false;
32static IO_APIC: LazyInit<SpinNoIrq<IoApic>> = LazyInit::new();
33
34#[cfg(feature = "irq")]
36pub fn set_enable(vector: usize, enabled: bool) {
37 if vector < APIC_TIMER_VECTOR as _ {
39 unsafe {
40 if enabled {
41 IO_APIC.lock().enable_irq(vector as u8);
42 } else {
43 IO_APIC.lock().disable_irq(vector as u8);
44 }
45 }
46 }
47}
48
49#[cfg(feature = "irq")]
54pub fn register_handler(vector: usize, handler: crate::irq::IrqHandler) -> bool {
55 crate::irq::register_handler_common(vector, handler)
56}
57
58#[cfg(feature = "irq")]
64pub fn dispatch_irq(vector: usize) {
65 crate::irq::dispatch_irq_common(vector);
66 unsafe { local_apic().end_of_interrupt() };
67}
68
69pub(super) fn local_apic<'a>() -> &'a mut LocalApic {
70 unsafe { LOCAL_APIC.get().as_mut().unwrap().assume_init_mut() }
72}
73
74pub(super) fn raw_apic_id(id_u8: u8) -> u32 {
75 if unsafe { IS_X2APIC } {
76 id_u8 as u32
77 } else {
78 (id_u8 as u32) << 24
79 }
80}
81
82fn cpu_has_x2apic() -> bool {
83 match raw_cpuid::CpuId::new().get_feature_info() {
84 Some(finfo) => finfo.has_x2apic(),
85 None => false,
86 }
87}
88
89pub(super) fn init_primary() {
90 info!("Initialize Local APIC...");
91
92 unsafe {
93 Port::<u8>::new(0x21).write(0xff);
95 Port::<u8>::new(0xA1).write(0xff);
96 }
97
98 let mut builder = LocalApicBuilder::new();
99 builder
100 .timer_vector(APIC_TIMER_VECTOR as _)
101 .error_vector(APIC_ERROR_VECTOR as _)
102 .spurious_vector(APIC_SPURIOUS_VECTOR as _);
103
104 if cpu_has_x2apic() {
105 info!("Using x2APIC.");
106 unsafe { IS_X2APIC = true };
107 } else {
108 info!("Using xAPIC.");
109 let base_vaddr = phys_to_virt(pa!(unsafe { xapic_base() } as usize));
110 builder.set_xapic_base(base_vaddr.as_usize() as u64);
111 }
112
113 let mut lapic = builder.build().unwrap();
114 unsafe {
115 lapic.enable();
116 LOCAL_APIC.get().as_mut().unwrap().write(lapic);
117 }
118
119 info!("Initialize IO APIC...");
120 let io_apic = unsafe { IoApic::new(phys_to_virt(IO_APIC_BASE).as_usize() as u64) };
121 IO_APIC.init_once(SpinNoIrq::new(io_apic));
122}
123
124#[cfg(feature = "smp")]
125pub(super) fn init_secondary() {
126 unsafe { local_apic().enable() };
127}