Skip to content

Commit 8b89acf

Browse files
committed
acpi: add support for SLIT
1 parent bc88428 commit 8b89acf

File tree

3 files changed

+111
-11
lines changed

3 files changed

+111
-11
lines changed

acpi/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub mod madt;
7272
pub mod mcfg;
7373
pub mod rsdp;
7474
pub mod sdt;
75+
pub mod slit;
7576
pub mod spcr;
7677

7778
#[cfg(feature = "allocator_api")]

acpi/src/platform/mod.rs

+26-11
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
11
pub mod interrupt;
22

33
use crate::{
4-
address::GenericAddress,
5-
fadt::Fadt,
6-
madt::{Madt, MadtError, MpProtectedModeWakeupCommand, MultiprocessorWakeupMailbox},
7-
AcpiError,
8-
AcpiHandler,
9-
AcpiResult,
10-
AcpiTables,
11-
ManagedSlice,
12-
PowerProfile,
4+
address::GenericAddress, fadt::Fadt, madt::{Madt, MadtError, MpProtectedModeWakeupCommand, MultiprocessorWakeupMailbox}, slit::Slit, AcpiError, AcpiHandler, AcpiResult, AcpiTables, ManagedSlice, PowerProfile
135
};
146
use core::{alloc::Allocator, mem, ptr};
157
use interrupt::InterruptModel;
@@ -64,6 +56,24 @@ where
6456
}
6557
}
6658

59+
#[derive(Clone, Debug)]
60+
pub struct SystemLocalityInfo<'a, A>
61+
where
62+
A: Allocator,
63+
{
64+
pub nr_system_localities: u64,
65+
pub distance_matrix: ManagedSlice<'a, ManagedSlice<'a, u8, A>, A>,
66+
}
67+
68+
impl <'a, A> SystemLocalityInfo<'a, A>
69+
where
70+
A: Allocator,
71+
{
72+
pub(crate) fn new(nr_system_localities: u64, distance_matrix: ManagedSlice<'a, ManagedSlice<'a, u8, A>, A>) -> Self {
73+
Self { nr_system_localities, distance_matrix }
74+
}
75+
}
76+
6777
/// Information about the ACPI Power Management Timer (ACPI PM Timer).
6878
#[derive(Debug, Clone)]
6979
pub struct PmTimer {
@@ -95,6 +105,7 @@ where
95105
/// On `x86_64` platforms that support the APIC, the processor topology must also be inferred from the
96106
/// interrupt model. That information is stored here, if present.
97107
pub processor_info: Option<ProcessorInfo<'a, A>>,
108+
pub system_locality_info: Option<SystemLocalityInfo<'a, A>>,
98109
pub pm_timer: Option<PmTimer>,
99110
/*
100111
* TODO: we could provide a nice view of the hardware register blocks in the FADT here.
@@ -124,12 +135,16 @@ where
124135

125136
let madt = tables.find_table::<Madt>();
126137
let (interrupt_model, processor_info) = match madt {
127-
Ok(madt) => madt.get().parse_interrupt_model_in(allocator)?,
138+
Ok(madt) => madt.get().parse_interrupt_model_in(allocator.clone())?,
128139
Err(_) => (InterruptModel::Unknown, None),
129140
};
141+
let system_locality_info = {
142+
let slit = tables.find_table::<Slit>();
143+
slit.and_then(|slit| slit.get().parse_system_locality_in(allocator)).ok()
144+
};
130145
let pm_timer = PmTimer::new(&fadt)?;
131146

132-
Ok(PlatformInfo { power_profile, interrupt_model, processor_info, pm_timer })
147+
Ok(PlatformInfo { power_profile, interrupt_model, processor_info, system_locality_info, pm_timer })
133148
}
134149
}
135150

acpi/src/slit.rs

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use core::{alloc::Allocator, marker::PhantomPinned, pin::Pin};
2+
3+
use crate::{platform::SystemLocalityInfo, sdt::{SdtHeader, Signature}, AcpiResult, AcpiTable};
4+
5+
/// System Locality Information Table (SLIT)
6+
///
7+
/// This optional table provides a matrix that describes the relative distance
8+
/// (memory latency) between all System Localities, which are also referred to
9+
/// as Proximity Domains. The value of each Entry[i,j] in the SLIT table, where
10+
/// i represents a row of a matrix and j represents a column of a matrix,
11+
/// indicates the relative distances from System Locality / Proximity Domain i
12+
/// to every other System Locality j in the system (including itself).
13+
#[repr(C, packed)]
14+
pub struct Slit {
15+
header: SdtHeader,
16+
nr_system_localities: u64,
17+
_pinned: PhantomPinned,
18+
}
19+
20+
unsafe impl AcpiTable for Slit {
21+
const SIGNATURE: Signature = Signature::SLIT;
22+
23+
fn header(&self) -> &SdtHeader {
24+
&self.header
25+
}
26+
}
27+
28+
impl Slit {
29+
#[cfg(feature = "allocator_api")]
30+
pub fn parse_system_locality_in<'a, A>(
31+
self: Pin<&Self>,
32+
allocator: A,
33+
) -> AcpiResult<SystemLocalityInfo<'a, A>>
34+
where
35+
A: Allocator + Clone,
36+
{
37+
use crate::ManagedSlice;
38+
39+
let (mut row, mut column) = (0, 0);
40+
let mut distance_matrix = ManagedSlice::new_in(self.nr_system_localities as usize, allocator.clone())?;
41+
for entry in self.entries() {
42+
if column == 0 {
43+
distance_matrix[row] = ManagedSlice::new_in(self.nr_system_localities as usize, allocator.clone())?;
44+
}
45+
distance_matrix[row][column] = entry;
46+
column += 1;
47+
if column == self.nr_system_localities as usize {
48+
row += 1;
49+
column = 0;
50+
}
51+
}
52+
53+
Ok(SystemLocalityInfo::new(self.nr_system_localities, distance_matrix))
54+
}
55+
56+
fn entries(self: Pin<&Self>) -> SlitEntryIter {
57+
let ptr = unsafe { Pin::into_inner_unchecked(self) as *const Slit as *const u8 };
58+
SlitEntryIter {
59+
pointer: unsafe { ptr.add(size_of::<Slit>()) },
60+
remaining_length: self.header.length - size_of::<Slit>() as u32,
61+
}
62+
}
63+
}
64+
65+
struct SlitEntryIter {
66+
pointer: *const u8,
67+
remaining_length: u32,
68+
}
69+
70+
impl Iterator for SlitEntryIter {
71+
type Item = u8;
72+
73+
fn next(&mut self) -> Option<Self::Item> {
74+
if self.remaining_length > 0 {
75+
let entry_pointer = self.pointer;
76+
self.pointer = unsafe { self.pointer.add(size_of::<Self::Item>()) };
77+
self.remaining_length -= size_of::<Self::Item>() as u32;
78+
Some(unsafe { *entry_pointer })
79+
} else {
80+
None
81+
}
82+
}
83+
}
84+

0 commit comments

Comments
 (0)