Skip to main content

acpi/sdt/
srat.rs

1use crate::{
2    AcpiTable,
3    sdt::{SdtHeader, Signature},
4};
5use bit_field::BitField;
6use core::{
7    marker::{PhantomData, PhantomPinned},
8    mem,
9    pin::Pin,
10};
11use 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)]
18pub struct Srat {
19    pub header: SdtHeader,
20    _reserved0: u32,
21    _reserved1: u64,
22    _pinned: PhantomPinned,
23}
24
25unsafe impl AcpiTable for Srat {
26    const SIGNATURE: Signature = Signature::SRAT;
27
28    fn header(&self) -> &SdtHeader {
29        &self.header
30    }
31}
32
33impl 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)]
45pub 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)]
56pub 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
65impl<'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)]
114pub struct EntryHeader {
115    pub typ: u8,
116    pub length: u16,
117}
118
119#[derive(Clone, Copy, Debug)]
120#[repr(C, packed)]
121pub struct LocalApicAffinity {
122    pub header: EntryHeader,
123    pub proximity_domain_low: u8,
124    pub apic_id: u8,
125    pub flags: LocalApicAffinityFlags,
126    pub local_sapic_eid: u8,
127    pub proximity_domain_high: [u8; 3],
128    pub clock_domain: u32,
129}
130
131bitflags::bitflags! {
132    #[derive(Clone, Copy, Debug)]
133    pub struct LocalApicAffinityFlags: u32 {
134        const ENABLED = 1;
135    }
136}
137
138impl LocalApicAffinity {
139    pub fn proximity_domain(&self) -> u32 {
140        u32::from_le_bytes([
141            self.proximity_domain_low,
142            self.proximity_domain_high[0],
143            self.proximity_domain_high[1],
144            self.proximity_domain_high[2],
145        ])
146    }
147}
148
149#[derive(Clone, Copy, Debug)]
150#[repr(C, packed)]
151pub struct MemoryAffinity {
152    pub header: EntryHeader,
153    pub proximity_domain: u32,
154    _reserved0: u16,
155    pub base_address_low: u32,
156    pub base_address_high: u32,
157    pub length_low: u32,
158    pub length_high: u32,
159    _reserved1: u32,
160    pub flags: MemoryAffinityFlags,
161    _reserved2: u64,
162}
163
164bitflags::bitflags! {
165    #[derive(Clone, Copy, Debug)]
166    pub struct MemoryAffinityFlags: u32 {
167        const ENABLED = 1;
168        const HOT_PLUGGABLE = 1 << 1;
169        const NON_VOLATILE = 1 << 2;
170    }
171}
172
173impl MemoryAffinity {
174    pub fn base_address(&self) -> u64 {
175        let mut address = self.base_address_low as u64;
176        address.set_bits(32..64, self.base_address_high as u64);
177        address
178    }
179
180    pub fn length(&self) -> u64 {
181        let mut length = self.length_low as u64;
182        length.set_bits(32..64, self.base_address_high as u64);
183        length
184    }
185}
186
187#[derive(Clone, Copy, Debug)]
188#[repr(C, packed)]
189pub struct LocalApicX2Affinity {
190    pub header: EntryHeader,
191    _reserved0: u16,
192    pub proximity_domain: u32,
193    pub x2apic_id: u32,
194    pub flags: LocalApicAffinityFlags,
195    pub clock_domain: u32,
196    _reserved1: u32,
197}
198
199#[derive(Clone, Copy, Debug)]
200#[repr(C, packed)]
201pub struct GiccAffinity {
202    pub header: EntryHeader,
203    pub proximity_domain: u32,
204    pub acpi_processor_uid: u32,
205    pub flags: u32,
206    pub clock_domain: u32,
207}
208
209#[derive(Clone, Copy, Debug)]
210#[repr(C, packed)]
211pub struct GicItsAffinity {
212    pub header: EntryHeader,
213    pub proximity_domain: u32,
214    _reserved0: u16,
215    pub its_id: u32,
216}
217
218#[derive(Clone, Copy, Debug)]
219#[repr(C, packed)]
220pub struct GicInitiatorAffinity {
221    pub header: EntryHeader,
222    _reserved0: u8,
223    pub device_handle_type: u8,
224    pub proximity_domain: u32,
225    pub device_handle: [u8; 16],
226    pub flags: u32,
227    _reserved1: u32,
228}