macro_rules! __log_prefix {
() => {
"acpi: "
};
}
pub(in crate::arch) mod dmar;
pub(in crate::arch) mod remapping;
use core::{num::NonZeroU8, ptr::NonNull};
use acpi::{
AcpiHandler, AcpiTables,
address::AddressSpace,
fadt::{Fadt, IaPcBootArchFlags},
mcfg::Mcfg,
rsdp::Rsdp,
};
use spin::Once;
use crate::{
boot::{self, BootloaderAcpiArg},
info,
mm::paddr_to_vaddr,
warn,
};
#[derive(Clone, Debug)]
pub(crate) struct AcpiMemoryHandler {}
impl AcpiHandler for AcpiMemoryHandler {
unsafe fn map_physical_region<T>(
&self,
physical_address: usize,
size: usize,
) -> acpi::PhysicalMapping<Self, T> {
let virtual_address = NonNull::new(paddr_to_vaddr(physical_address) as *mut T).unwrap();
unsafe {
acpi::PhysicalMapping::new(physical_address, virtual_address, size, size, self.clone())
}
}
fn unmap_physical_region<T>(_region: &acpi::PhysicalMapping<Self, T>) {}
}
struct SyncAcpiTables(Option<AcpiTables<AcpiMemoryHandler>>);
unsafe impl Sync for SyncAcpiTables {}
static ACPI_TABLES: Once<SyncAcpiTables> = Once::new();
pub(crate) fn get_acpi_tables() -> Option<&'static AcpiTables<AcpiMemoryHandler>> {
let acpi_tables = ACPI_TABLES.call_once(|| {
let acpi_tables = match boot::EARLY_INFO.get().unwrap().acpi_arg {
BootloaderAcpiArg::Rsdp(addr) => unsafe {
AcpiTables::from_rsdp(AcpiMemoryHandler {}, addr).unwrap()
},
BootloaderAcpiArg::Rsdt(addr) => unsafe {
AcpiTables::from_rsdt(AcpiMemoryHandler {}, 0, addr).unwrap()
},
BootloaderAcpiArg::Xsdt(addr) => unsafe {
AcpiTables::from_rsdt(AcpiMemoryHandler {}, 1, addr).unwrap()
},
BootloaderAcpiArg::NotProvided => {
let rsdp = unsafe { Rsdp::search_for_on_bios(AcpiMemoryHandler {}) };
match rsdp {
Ok(map) => unsafe {
AcpiTables::from_rsdp(AcpiMemoryHandler {}, map.physical_start()).unwrap()
},
Err(_) => {
warn!("ACPI info not found!");
return SyncAcpiTables(None);
}
}
}
};
SyncAcpiTables(Some(acpi_tables))
});
acpi_tables.0.as_ref()
}
#[derive(Debug)]
pub struct AcpiInfo {
pub century_register: Option<NonZeroU8>,
pub boot_flags: Option<IaPcBootArchFlags>,
pub reset_port_and_val: Option<(u16, u8)>,
pub pci_ecam_region: Option<PciEcamRegion>,
}
#[derive(Debug)]
pub struct PciEcamRegion {
pub base_address: u64,
pub bus_start: u8,
pub bus_end: u8,
}
pub static ACPI_INFO: Once<AcpiInfo> = Once::new();
pub(in crate::arch) fn init() {
let mut acpi_info = AcpiInfo {
century_register: None,
boot_flags: None,
reset_port_and_val: None,
pci_ecam_region: None,
};
let Some(acpi_tables) = get_acpi_tables() else {
ACPI_INFO.call_once(|| acpi_info);
return;
};
if let Ok(fadt) = acpi_tables.find_table::<Fadt>() {
acpi_info.century_register = NonZeroU8::new(fadt.century);
acpi_info.boot_flags = Some(fadt.iapc_boot_arch);
if let Ok(reset_reg) = fadt.reset_register()
&& reset_reg.address_space == AddressSpace::SystemIo
&& let Ok(reset_port) = reset_reg.address.try_into()
{
acpi_info.reset_port_and_val = Some((reset_port, fadt.reset_value));
}
};
if let Ok(mcfg) = acpi_tables.find_table::<Mcfg>()
&& let Some(mcfg_entry) = mcfg.entries().first()
{
acpi_info.pci_ecam_region = Some(PciEcamRegion {
base_address: mcfg_entry.base_address,
bus_start: mcfg_entry.bus_number_start,
bus_end: mcfg_entry.bus_number_end,
});
}
info!("Collected information {:?}", acpi_info);
ACPI_INFO.call_once(|| acpi_info);
}