proka_kernel/interrupts/
apic.rs1use crate::get_hhdm_offset;
2use crate::interrupts::idt::SPURIOUS_APIC_VECTOR;
3use crate::interrupts::pic;
4use crate::libs::msr;
5use log::{debug, error, info};
6use raw_cpuid::CpuId;
7use x86_64::registers::model_specific::Msr;
8
9const APIC_SIVR_ENABLE: u64 = 0x100;
10const APIC_BASE_ENABLE: u64 = 1 << 11;
11const APIC_BASE_X2APIC_ENABLE: u64 = 1 << 10;
12
13const XAPIC_EOI_OFFSET: u64 = 0x0B0;
15const XAPIC_SIVR_OFFSET: u64 = 0xF0;
16pub fn apic_is_available() -> bool {
17 let cpuid = CpuId::new();
18 cpuid.get_feature_info().is_some_and(|info| info.has_apic())
19}
20
21pub fn x2apic_is_available() -> bool {
22 let cpuid = CpuId::new();
23 cpuid
24 .get_feature_info()
25 .is_some_and(|info| info.has_x2apic())
26}
27
28pub fn enable_x2apic() {
30 unsafe {
31 let mut apic_base = Msr::new(msr::IA32_APIC_BASE);
33 let mut base_val = apic_base.read();
34 base_val |= APIC_BASE_ENABLE | APIC_BASE_X2APIC_ENABLE;
35 apic_base.write(base_val);
36
37 let mut sivr = Msr::new(msr::IA32_X2APIC_SIVR);
39 let sivr_val = APIC_SIVR_ENABLE | SPURIOUS_APIC_VECTOR as u64;
40 sivr.write(sivr_val);
41 }
42}
43
44unsafe fn get_xapic_base() -> u64 {
46 let apic_base = Msr::new(msr::IA32_APIC_BASE).read();
47 let phys_base = apic_base & 0xFFFFF000; let hhdm_offset = get_hhdm_offset().as_u64();
49 phys_base + hhdm_offset
50}
51
52pub fn enable_apic() {
54 unsafe {
55 let mut apic_base = Msr::new(msr::IA32_APIC_BASE);
57 let mut base_val = apic_base.read();
58 base_val |= APIC_BASE_ENABLE;
59 base_val &= !APIC_BASE_X2APIC_ENABLE;
60 apic_base.write(base_val);
61
62 let base_addr = get_xapic_base();
64 let sivr_ptr = (base_addr + XAPIC_SIVR_OFFSET) as *mut u32;
65 let sivr_val = (APIC_SIVR_ENABLE | SPURIOUS_APIC_VECTOR as u64) as u32;
66 core::ptr::write_volatile(sivr_ptr, sivr_val);
67 }
68}
69
70pub fn end_of_interrupt() {
72 unsafe {
73 if x2apic_is_available() {
74 let mut eoi = Msr::new(msr::IA32_X2APIC_EOI);
75 eoi.write(0);
76 } else {
77 let base_addr = get_xapic_base();
78 let eoi_ptr = (base_addr + XAPIC_EOI_OFFSET) as *mut u32;
79 core::ptr::write_volatile(eoi_ptr, 0);
80 }
81 }
82}
83
84pub fn init() -> bool {
85 pic::disable();
87
88 let success = if x2apic_is_available() {
89 debug!("x2APIC is available, enabling...");
90 enable_x2apic();
91 info!("x2APIC enabled");
92 true
93 } else if apic_is_available() {
94 debug!("x2APIC not available, falling back to xAPIC...");
95 enable_apic();
96 info!("xAPIC enabled");
97 true
98 } else {
99 error!("APIC not supported!");
100 false
101 };
102
103 success
104}