mycelium_kernel/arch/x86_64/
acpi.rs

1use acpi::{AcpiError, AcpiHandler, AcpiTables};
2use core::fmt;
3use hal_core::{Address, PAddr};
4use hal_x86_64::mm;
5
6#[derive(Debug)]
7pub enum Error {
8    Acpi(AcpiError),
9    Other(&'static str),
10}
11
12pub(super) fn acpi_tables(
13    rsdp_addr: PAddr,
14) -> Result<AcpiTables<IdentityMappedAcpiHandler>, AcpiError> {
15    tracing::info!("trying to parse ACPI tables from RSDP...");
16    let tables = unsafe { AcpiTables::from_rsdp(IdentityMappedAcpiHandler, rsdp_addr.as_usize()) }?;
17    tracing::info!("found ACPI tables!");
18    Ok(tables)
19}
20
21#[tracing::instrument(err, skip(platform))]
22pub fn bringup_smp(platform: &acpi::PlatformInfo) -> Result<(), Error> {
23    use acpi::platform::{self, interrupt::InterruptModel};
24
25    tracing::info!(?platform.power_profile);
26
27    let apic = match platform.interrupt_model {
28        acpi::InterruptModel::Apic(ref apic) => {
29            tracing::info!("APIC interrupt model detected");
30            apic
31        }
32        InterruptModel::Unknown => {
33            return Err(Error::Other(
34                "MADT does not indicate support for APIC interrupt model!",
35            ));
36        }
37        ref model => {
38            tracing::warn!(?model, "unknown interrupt model detected");
39            return Err(Error::Other(
40                "MADT does not indicate support for APIC interrupt model!",
41            ));
42        }
43    };
44
45    tracing::debug!(?apic);
46
47    let platform::ProcessorInfo {
48        ref application_processors,
49        ref boot_processor,
50    } = platform
51        .processor_info
52        .as_ref()
53        .ok_or(Error::Other("no processor information found in MADT!"))?;
54    tracing::info!("boot processor seems normalish");
55    tracing::debug!(?boot_processor);
56    tracing::info!(
57        "found {} application processors",
58        application_processors.len()
59    );
60    tracing::debug!(?application_processors);
61    tracing::warn!("not starting app processors (SMP support isn't done yet)");
62
63    Ok(())
64}
65
66#[derive(Clone)]
67pub(super) struct IdentityMappedAcpiHandler;
68
69impl AcpiHandler for IdentityMappedAcpiHandler {
70    unsafe fn map_physical_region<T>(
71        &self,
72        physical_address: usize,
73        size: usize,
74    ) -> acpi::PhysicalMapping<Self, T> {
75        let paddr = PAddr::from_u64(physical_address as u64);
76        let vaddr = mm::kernel_vaddr_of(paddr);
77        let vptr = vaddr
78            .as_non_null()
79            .expect("virtual address for ACPI region is not null");
80        // we have identity mapped all physical memory, so we don't actually
81        // have to map any pages --- just tell the ACPI crate that it can use
82        // this region.
83        acpi::PhysicalMapping::new(physical_address, vptr, size, size, Self)
84    }
85
86    fn unmap_physical_region<T>(_region: &acpi::PhysicalMapping<Self, T>) {
87        // we don't need to unmap anything, since we didn't map anything. :)
88    }
89}
90
91// === impl Error ===
92
93impl From<AcpiError> for Error {
94    fn from(inner: AcpiError) -> Self {
95        Self::Acpi(inner)
96    }
97}
98
99impl fmt::Display for Error {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        match self {
102            // format the ACPI error using its `fmt::Debug` implementation,
103            // since the ACPI crate doesn't implement `fmt::Display` for its
104            // errors.
105            // TODO(eliza): add a `Display` impl upstream...
106            Self::Acpi(inner) => write!(f, "ACPI error: {inner:?}"),
107            Self::Other(msg) => fmt::Display::fmt(msg, f),
108        }
109    }
110}