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#[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 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}