From 8b89acfca542080384f03a0d93f5b13e6de175b8 Mon Sep 17 00:00:00 2001 From: Zejun Zhao Date: Mon, 17 Feb 2025 06:49:28 +0000 Subject: [PATCH] acpi: add support for SLIT --- acpi/src/lib.rs | 1 + acpi/src/platform/mod.rs | 37 ++++++++++++------ acpi/src/slit.rs | 84 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 acpi/src/slit.rs diff --git a/acpi/src/lib.rs b/acpi/src/lib.rs index 0b254df1..e3a1343b 100644 --- a/acpi/src/lib.rs +++ b/acpi/src/lib.rs @@ -72,6 +72,7 @@ pub mod madt; pub mod mcfg; pub mod rsdp; pub mod sdt; +pub mod slit; pub mod spcr; #[cfg(feature = "allocator_api")] diff --git a/acpi/src/platform/mod.rs b/acpi/src/platform/mod.rs index bf4097c3..3d6b96b6 100644 --- a/acpi/src/platform/mod.rs +++ b/acpi/src/platform/mod.rs @@ -1,15 +1,7 @@ pub mod interrupt; use crate::{ - address::GenericAddress, - fadt::Fadt, - madt::{Madt, MadtError, MpProtectedModeWakeupCommand, MultiprocessorWakeupMailbox}, - AcpiError, - AcpiHandler, - AcpiResult, - AcpiTables, - ManagedSlice, - PowerProfile, + address::GenericAddress, fadt::Fadt, madt::{Madt, MadtError, MpProtectedModeWakeupCommand, MultiprocessorWakeupMailbox}, slit::Slit, AcpiError, AcpiHandler, AcpiResult, AcpiTables, ManagedSlice, PowerProfile }; use core::{alloc::Allocator, mem, ptr}; use interrupt::InterruptModel; @@ -64,6 +56,24 @@ where } } +#[derive(Clone, Debug)] +pub struct SystemLocalityInfo<'a, A> +where + A: Allocator, +{ + pub nr_system_localities: u64, + pub distance_matrix: ManagedSlice<'a, ManagedSlice<'a, u8, A>, A>, +} + +impl <'a, A> SystemLocalityInfo<'a, A> +where + A: Allocator, +{ + pub(crate) fn new(nr_system_localities: u64, distance_matrix: ManagedSlice<'a, ManagedSlice<'a, u8, A>, A>) -> Self { + Self { nr_system_localities, distance_matrix } + } +} + /// Information about the ACPI Power Management Timer (ACPI PM Timer). #[derive(Debug, Clone)] pub struct PmTimer { @@ -95,6 +105,7 @@ where /// On `x86_64` platforms that support the APIC, the processor topology must also be inferred from the /// interrupt model. That information is stored here, if present. pub processor_info: Option>, + pub system_locality_info: Option>, pub pm_timer: Option, /* * TODO: we could provide a nice view of the hardware register blocks in the FADT here. @@ -124,12 +135,16 @@ where let madt = tables.find_table::(); let (interrupt_model, processor_info) = match madt { - Ok(madt) => madt.get().parse_interrupt_model_in(allocator)?, + Ok(madt) => madt.get().parse_interrupt_model_in(allocator.clone())?, Err(_) => (InterruptModel::Unknown, None), }; + let system_locality_info = { + let slit = tables.find_table::(); + slit.and_then(|slit| slit.get().parse_system_locality_in(allocator)).ok() + }; let pm_timer = PmTimer::new(&fadt)?; - Ok(PlatformInfo { power_profile, interrupt_model, processor_info, pm_timer }) + Ok(PlatformInfo { power_profile, interrupt_model, processor_info, system_locality_info, pm_timer }) } } diff --git a/acpi/src/slit.rs b/acpi/src/slit.rs new file mode 100644 index 00000000..a51c1d20 --- /dev/null +++ b/acpi/src/slit.rs @@ -0,0 +1,84 @@ +use core::{alloc::Allocator, marker::PhantomPinned, pin::Pin}; + +use crate::{platform::SystemLocalityInfo, sdt::{SdtHeader, Signature}, AcpiResult, AcpiTable}; + +/// System Locality Information Table (SLIT) +/// +/// This optional table provides a matrix that describes the relative distance +/// (memory latency) between all System Localities, which are also referred to +/// as Proximity Domains. The value of each Entry[i,j] in the SLIT table, where +/// i represents a row of a matrix and j represents a column of a matrix, +/// indicates the relative distances from System Locality / Proximity Domain i +/// to every other System Locality j in the system (including itself). +#[repr(C, packed)] +pub struct Slit { + header: SdtHeader, + nr_system_localities: u64, + _pinned: PhantomPinned, +} + +unsafe impl AcpiTable for Slit { + const SIGNATURE: Signature = Signature::SLIT; + + fn header(&self) -> &SdtHeader { + &self.header + } +} + +impl Slit { + #[cfg(feature = "allocator_api")] + pub fn parse_system_locality_in<'a, A>( + self: Pin<&Self>, + allocator: A, + ) -> AcpiResult> + where + A: Allocator + Clone, + { + use crate::ManagedSlice; + + let (mut row, mut column) = (0, 0); + let mut distance_matrix = ManagedSlice::new_in(self.nr_system_localities as usize, allocator.clone())?; + for entry in self.entries() { + if column == 0 { + distance_matrix[row] = ManagedSlice::new_in(self.nr_system_localities as usize, allocator.clone())?; + } + distance_matrix[row][column] = entry; + column += 1; + if column == self.nr_system_localities as usize { + row += 1; + column = 0; + } + } + + Ok(SystemLocalityInfo::new(self.nr_system_localities, distance_matrix)) + } + + fn entries(self: Pin<&Self>) -> SlitEntryIter { + let ptr = unsafe { Pin::into_inner_unchecked(self) as *const Slit as *const u8 }; + SlitEntryIter { + pointer: unsafe { ptr.add(size_of::()) }, + remaining_length: self.header.length - size_of::() as u32, + } + } +} + +struct SlitEntryIter { + pointer: *const u8, + remaining_length: u32, +} + +impl Iterator for SlitEntryIter { + type Item = u8; + + fn next(&mut self) -> Option { + if self.remaining_length > 0 { + let entry_pointer = self.pointer; + self.pointer = unsafe { self.pointer.add(size_of::()) }; + self.remaining_length -= size_of::() as u32; + Some(unsafe { *entry_pointer }) + } else { + None + } + } +} +