good_os_framework/arch/
acpi.rs

1use acpi::mcfg::{Mcfg, McfgEntry};
2use acpi::platform::interrupt::Apic;
3use acpi::InterruptModel;
4use acpi::{AcpiHandler, AcpiTables, HpetInfo, PhysicalMapping};
5use alloc::alloc::Global;
6use alloc::boxed::Box;
7use alloc::vec::Vec;
8use conquer_once::spin::OnceCell;
9use core::ptr::NonNull;
10use limine::request::RsdpRequest;
11use x86_64::{PhysAddr, VirtAddr};
12
13use crate::memory::{convert_physical_to_virtual, convert_virtual_to_physical};
14
15pub static ACPI: OnceCell<Acpi> = OnceCell::uninit();
16
17#[used]
18#[link_section = ".requests"]
19static RSDP_REQUEST: RsdpRequest = RsdpRequest::new();
20
21#[derive(Clone)]
22struct AcpiMemHandler;
23
24impl AcpiHandler for AcpiMemHandler {
25    unsafe fn map_physical_region<T>(
26        &self,
27        physical_address: usize,
28        size: usize,
29    ) -> PhysicalMapping<Self, T> {
30        let virtual_address = {
31            let physical_address = PhysAddr::new(physical_address as u64);
32            let virtual_address = convert_physical_to_virtual(physical_address);
33            NonNull::new_unchecked(virtual_address.as_u64() as *mut T)
34        };
35        PhysicalMapping::new(physical_address, virtual_address, size, size, self.clone())
36    }
37
38    fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {}
39}
40
41#[derive(Debug)]
42pub struct Acpi<'a> {
43    pub apic_info: Apic<'a, Global>,
44    pub hpet_info: HpetInfo,
45    pub mcfg_info: Vec<McfgEntry>,
46}
47
48pub fn init() {
49    let rsdp_response = RSDP_REQUEST.get_response().unwrap();
50
51    let acpi_tables = unsafe {
52        let rsdp_addr = VirtAddr::new(rsdp_response.address() as u64);
53        let tables = AcpiTables::from_rsdp(
54            AcpiMemHandler,
55            convert_virtual_to_physical(rsdp_addr).as_u64() as usize,
56        );
57        Box::leak(Box::new(tables.unwrap()))
58    };
59
60    log::info!("Find ACPI tables successfully!");
61
62    let platform_info = acpi_tables
63        .platform_info()
64        .expect("Failed to get platform info!");
65
66    let apic_info = match platform_info.interrupt_model {
67        InterruptModel::Unknown => panic!("No APIC support, cannot continue!"),
68        InterruptModel::Apic(apic) => apic,
69        _ => panic!("ACPI does not have interrupt model info!"),
70    };
71
72    let hpet_info = HpetInfo::new(acpi_tables).expect("Failed to get HPET info!");
73
74    let mut mcfg_info = Vec::new();
75    let mcfg = acpi_tables.find_table::<Mcfg>().expect("Cannot get MCFG");
76    for entry in mcfg.entries() {
77        mcfg_info.push(*entry);
78    }
79
80    ACPI.init_once(|| Acpi {
81        apic_info,
82        hpet_info,
83        mcfg_info,
84    });
85}