Skip to content

Commit b231b6c

Browse files
Add SDT definitions for SRAT + SLIT tables
Co-authored-by: Zejun Zhao <jelly.zhao.42@gmail.com>
1 parent dc17d31 commit b231b6c

File tree

4 files changed

+277
-2
lines changed

4 files changed

+277
-2
lines changed

src/sdt/madt.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use core::{
99
mem,
1010
pin::Pin,
1111
};
12+
use log::warn;
1213

1314
#[derive(Clone, Copy, Debug)]
1415
pub enum MadtError {
@@ -114,8 +115,16 @@ impl<'a> Iterator for MadtEntryIter<'a> {
114115
let entry_pointer = self.pointer;
115116
let header = unsafe { *(self.pointer as *const EntryHeader) };
116117

117-
self.pointer = unsafe { self.pointer.offset(header.length as isize) };
118-
self.remaining_length -= header.length as u32;
118+
if header.length as u32 > self.remaining_length {
119+
warn!(
120+
"Invalid entry of type {} in MADT - extending past length of table. Ignoring",
121+
header.entry_type
122+
);
123+
return None;
124+
}
125+
126+
self.pointer = unsafe { self.pointer.byte_offset(header.length as isize) };
127+
self.remaining_length = self.remaining_length.saturating_sub(header.length as u32);
119128

120129
macro_rules! construct_entry {
121130
($entry_type:expr,

src/sdt/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ pub mod fadt;
44
pub mod hpet;
55
pub mod madt;
66
pub mod mcfg;
7+
pub mod slit;
78
pub mod spcr;
9+
pub mod srat;
810

911
use crate::AcpiError;
1012
use core::{fmt, mem::MaybeUninit, str};

src/sdt/slit.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use crate::{
2+
AcpiTable,
3+
sdt::{SdtHeader, Signature},
4+
};
5+
use core::{marker::PhantomPinned, mem, pin::Pin, slice};
6+
use log::warn;
7+
8+
/// The SLIT (System Locality Information Table) provides a matrix of relative distances between
9+
/// all proximity domains. It encodes a list of N*N entries, where each entry is `u8` and the
10+
/// relative distance between proximity domains `(i, j)` is the entry at `i*N+j`. The distance
11+
/// between a proximity domain and itself is normalised to a value of `10`.
12+
#[derive(Debug)]
13+
#[repr(C, packed)]
14+
pub struct Slit {
15+
pub header: SdtHeader,
16+
pub num_proximity_domains: 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+
pub fn matrix(self: Pin<&Self>) -> &[u8] {
30+
let mut num_entries = self.num_proximity_domains * self.num_proximity_domains;
31+
if (mem::size_of::<Slit>() + num_entries as usize * num_entries as usize * mem::size_of::<u8>())
32+
> self.header.length as usize
33+
{
34+
warn!("SLIT too short for given number of proximity domains! Returning empty matrix");
35+
num_entries = 0;
36+
}
37+
38+
unsafe {
39+
let ptr = Pin::into_inner_unchecked(self) as *const Slit as *const u8;
40+
slice::from_raw_parts(ptr.byte_add(mem::size_of::<Slit>()), num_entries as usize)
41+
}
42+
}
43+
44+
pub fn entry(self: Pin<&Self>, i: u32, j: u32) -> Option<u8> {
45+
if i as u64 <= self.num_proximity_domains && j as u64 <= self.num_proximity_domains {
46+
let matrix = self.matrix();
47+
Some(matrix[i as usize + j as usize * self.num_proximity_domains as usize])
48+
} else {
49+
None
50+
}
51+
}
52+
}

src/sdt/srat.rs

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
use crate::{
2+
AcpiTable,
3+
sdt::{SdtHeader, Signature},
4+
};
5+
use bit_field::BitField;
6+
use core::{
7+
marker::{PhantomData, PhantomPinned},
8+
mem,
9+
pin::Pin,
10+
};
11+
use log::warn;
12+
13+
/// Represents the SRAT (System Resource Affinity Table). This is a variable length table that
14+
/// allows devices (processors, memory ranges, and generic 'initiators') to be associated with
15+
/// system locality / proximity domains and clock domains.
16+
#[derive(Debug)]
17+
#[repr(C, packed)]
18+
pub struct Srat {
19+
pub header: SdtHeader,
20+
_reserved0: u32,
21+
_reserved1: u64,
22+
_pinned: PhantomPinned,
23+
}
24+
25+
unsafe impl AcpiTable for Srat {
26+
const SIGNATURE: Signature = Signature::SRAT;
27+
28+
fn header(&self) -> &SdtHeader {
29+
&self.header
30+
}
31+
}
32+
33+
impl Srat {
34+
pub fn entries(self: Pin<&Self>) -> SratEntryIter<'_> {
35+
let ptr = unsafe { Pin::into_inner_unchecked(self) as *const Srat as *const u8 };
36+
SratEntryIter {
37+
pointer: unsafe { ptr.add(mem::size_of::<Srat>()) },
38+
remaining_length: self.header.length - mem::size_of::<Srat>() as u32,
39+
_phantom: PhantomData,
40+
}
41+
}
42+
}
43+
44+
#[derive(Debug)]
45+
pub struct SratEntryIter<'a> {
46+
pointer: *const u8,
47+
/*
48+
* The iterator can only have at most `u32::MAX` remaining bytes, because the length of the
49+
* whole SDT can only be at most `u32::MAX`.
50+
*/
51+
remaining_length: u32,
52+
_phantom: PhantomData<&'a ()>,
53+
}
54+
55+
#[derive(Debug)]
56+
pub enum SratEntry<'a> {
57+
LocalApicAffinity(&'a LocalApicAffinity),
58+
MemoryAffinity(&'a MemoryAffinity),
59+
LocalApicX2Affinity(&'a LocalApicX2Affinity),
60+
GiccAffinity(&'a GiccAffinity),
61+
GicItsAffinity(&'a GicItsAffinity),
62+
GicInitiatorAffinity(&'a GicInitiatorAffinity),
63+
}
64+
65+
impl<'a> Iterator for SratEntryIter<'a> {
66+
type Item = SratEntry<'a>;
67+
68+
fn next(&mut self) -> Option<Self::Item> {
69+
while self.remaining_length > 0 {
70+
let entry_pointer = self.pointer;
71+
let header = unsafe { *(self.pointer as *const EntryHeader) };
72+
73+
if header.length as u32 > self.remaining_length {
74+
warn!("Invalid entry of type {} in SRAT - extending past length of table. Ignoring", header.typ);
75+
return None;
76+
}
77+
78+
self.pointer = unsafe { self.pointer.byte_offset(header.length as isize) };
79+
self.remaining_length = self.remaining_length.saturating_sub(header.length as u32);
80+
81+
match header.typ {
82+
0 => {
83+
return Some(SratEntry::LocalApicAffinity(unsafe {
84+
&*(entry_pointer as *const LocalApicAffinity)
85+
}));
86+
}
87+
1 => {
88+
return Some(SratEntry::MemoryAffinity(unsafe { &*(entry_pointer as *const MemoryAffinity) }));
89+
}
90+
2 => {
91+
return Some(SratEntry::LocalApicX2Affinity(unsafe {
92+
&*(entry_pointer as *const LocalApicX2Affinity)
93+
}));
94+
}
95+
3 => return Some(SratEntry::GiccAffinity(unsafe { &*(entry_pointer as *const GiccAffinity) })),
96+
4 => {
97+
return Some(SratEntry::GicItsAffinity(unsafe { &*(entry_pointer as *const GicItsAffinity) }));
98+
}
99+
5 => {
100+
return Some(SratEntry::GicInitiatorAffinity(unsafe {
101+
&*(entry_pointer as *const GicInitiatorAffinity)
102+
}));
103+
}
104+
other => warn!("Unrecognised entry in SRAT of type {}", other),
105+
}
106+
}
107+
108+
None
109+
}
110+
}
111+
112+
#[derive(Clone, Copy, Debug)]
113+
#[repr(C, packed)]
114+
pub struct EntryHeader {
115+
pub typ: u8,
116+
pub length: u16,
117+
}
118+
119+
#[derive(Clone, Copy, Debug)]
120+
#[repr(C, packed)]
121+
pub struct LocalApicAffinity {
122+
pub header: EntryHeader,
123+
pub proximity_domain_low: u8,
124+
pub apic_id: u8,
125+
pub flags: u32,
126+
pub local_sapic_eid: u8,
127+
pub proximity_domain_high: [u8; 3],
128+
pub clock_domain: u32,
129+
}
130+
131+
impl LocalApicAffinity {
132+
pub fn proximity_domain(&self) -> u32 {
133+
u32::from_le_bytes([
134+
self.proximity_domain_low,
135+
self.proximity_domain_high[0],
136+
self.proximity_domain_high[1],
137+
self.proximity_domain_high[2],
138+
])
139+
}
140+
}
141+
142+
#[derive(Clone, Copy, Debug)]
143+
#[repr(C, packed)]
144+
pub struct MemoryAffinity {
145+
pub header: EntryHeader,
146+
pub proximity_domain: u32,
147+
_reserved0: u16,
148+
pub base_address_low: u32,
149+
pub base_address_high: u32,
150+
pub length_low: u32,
151+
pub length_high: u32,
152+
_reserved1: u32,
153+
pub flags: u32,
154+
_reserved2: u64,
155+
}
156+
157+
impl MemoryAffinity {
158+
pub fn base_address(&self) -> u64 {
159+
let mut address = self.base_address_low as u64;
160+
address.set_bits(32..64, self.base_address_high as u64);
161+
address
162+
}
163+
164+
pub fn length(&self) -> u64 {
165+
let mut length = self.length_low as u64;
166+
length.set_bits(32..64, self.base_address_high as u64);
167+
length
168+
}
169+
}
170+
171+
#[derive(Clone, Copy, Debug)]
172+
#[repr(C, packed)]
173+
pub struct LocalApicX2Affinity {
174+
pub header: EntryHeader,
175+
_reserved0: u16,
176+
pub proximity_domain: u32,
177+
pub x2apic_id: u32,
178+
pub flags: u32,
179+
pub clock_domain: u32,
180+
_reserved1: u32,
181+
}
182+
183+
#[derive(Clone, Copy, Debug)]
184+
#[repr(C, packed)]
185+
pub struct GiccAffinity {
186+
pub header: EntryHeader,
187+
pub proximity_domain: u32,
188+
pub acpi_processor_uid: u32,
189+
pub flags: u32,
190+
pub clock_domain: u32,
191+
}
192+
193+
#[derive(Clone, Copy, Debug)]
194+
#[repr(C, packed)]
195+
pub struct GicItsAffinity {
196+
pub header: EntryHeader,
197+
pub proximity_domain: u32,
198+
_reserved0: u16,
199+
pub its_id: u32,
200+
}
201+
202+
#[derive(Clone, Copy, Debug)]
203+
#[repr(C, packed)]
204+
pub struct GicInitiatorAffinity {
205+
pub header: EntryHeader,
206+
_reserved0: u8,
207+
pub device_handle_type: u8,
208+
pub proximity_domain: u32,
209+
pub device_handle: [u8; 16],
210+
pub flags: u32,
211+
_reserved1: u32,
212+
}

0 commit comments

Comments
 (0)