1#[cfg(feature = "alloc")]
5pub use self::alloc_parse::*;
6
7use super::Table;
8use crate::packed_nums::*;
9use core::mem::size_of;
10use static_assertions::const_assert_eq;
11use zerocopy::FromBytes;
12use zerocopy::Immutable;
13use zerocopy::IntoBytes;
14use zerocopy::KnownLayout;
15use zerocopy::Ref;
16use zerocopy::Unaligned;
17
18#[repr(C)]
19#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
20pub struct SratHeader {
21 pub rsvd1: u32_ne,
22 pub rsvd2: u64_ne,
23}
24
25impl SratHeader {
26 pub fn new() -> SratHeader {
27 SratHeader {
28 rsvd1: 1.into(),
29 rsvd2: 0.into(),
30 }
31 }
32}
33
34impl Table for SratHeader {
35 const SIGNATURE: [u8; 4] = *b"SRAT";
36}
37
38pub const SRAT_REVISION: u8 = 3;
39
40open_enum::open_enum! {
41 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
42 pub enum SratType: u8 {
43 APIC = 0,
44 MEMORY = 1,
45 X2APIC = 2,
46 GICC = 3,
47 GENERIC_INITIATOR = 5,
48 }
49}
50
51open_enum::open_enum! {
52 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
54 pub enum SratDeviceHandleType: u8 {
55 ACPI = 0,
56 PCI = 1,
57 }
58}
59
60#[repr(C)]
61#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
62pub struct SratApic {
63 pub typ: SratType,
64 pub length: u8,
65 pub proximity_domain_byte1: u8,
66 pub apic_id: u8,
67 pub flags: u32_ne,
68 pub local_sapic_eid: u8,
69 pub proximity_domain_byte2: u8,
70 pub proximity_domain_byte3: u8,
71 pub proximity_domain_byte4: u8,
72 pub clock_domain: u32_ne,
73}
74
75const_assert_eq!(size_of::<SratApic>(), 16);
76
77pub const SRAT_APIC_ENABLED: u32 = 1 << 0;
78
79impl SratApic {
80 pub fn new(apic_id: u8, vnode: u32) -> Self {
81 let vnode = vnode.to_le_bytes();
82 Self {
83 typ: SratType::APIC,
84 length: size_of::<Self>() as u8,
85 proximity_domain_byte1: vnode[0],
86 apic_id,
87 flags: SRAT_APIC_ENABLED.into(),
88 local_sapic_eid: 0,
89 proximity_domain_byte2: vnode[1],
90 proximity_domain_byte3: vnode[2],
91 proximity_domain_byte4: vnode[3],
92 clock_domain: 0.into(),
93 }
94 }
95}
96
97#[repr(C)]
98#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
99pub struct SratX2Apic {
100 pub typ: SratType,
101 pub length: u8,
102 pub reserved: u16_ne,
103 pub proximity_domain: u32_ne,
104 pub x2_apic_id: u32_ne,
105 pub flags: u32_ne,
106 pub clock_domain: u32_ne,
107 pub reserved2: u32_ne,
108}
109
110const_assert_eq!(size_of::<SratX2Apic>(), 24);
111
112impl SratX2Apic {
113 pub fn new(x2_apic_id: u32, vnode: u32) -> Self {
114 Self {
115 typ: SratType::X2APIC,
116 length: size_of::<Self>() as u8,
117 x2_apic_id: x2_apic_id.into(),
118 flags: SRAT_APIC_ENABLED.into(),
119 clock_domain: 0.into(),
120 reserved: 0.into(),
121 proximity_domain: vnode.into(),
122 reserved2: 0.into(),
123 }
124 }
125}
126
127#[repr(C)]
128#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
129pub struct SratGicc {
130 pub typ: SratType,
131 pub length: u8,
132 pub proximity_domain: u32_ne,
133 pub acpi_processor_uid: u32_ne,
134 pub flags: u32_ne,
135 pub clock_domain: u32_ne,
136}
137
138const_assert_eq!(size_of::<SratGicc>(), 18);
139
140impl SratGicc {
141 pub fn new(acpi_processor_uid: u32, vnode: u32) -> Self {
142 Self {
143 typ: SratType::GICC,
144 length: size_of::<Self>() as u8,
145 acpi_processor_uid: acpi_processor_uid.into(),
146 flags: SRAT_APIC_ENABLED.into(),
147 clock_domain: 0.into(),
148 proximity_domain: vnode.into(),
149 }
150 }
151}
152
153#[repr(C)]
161#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
162pub struct SratGenericInitiator {
163 pub typ: SratType,
164 pub length: u8,
165 pub reserved1: u8,
166 pub device_handle_type: SratDeviceHandleType,
167 pub proximity_domain: u32_ne,
168 pub device_handle: [u8; 16],
169 pub flags: u32_ne,
170 pub reserved2: u32_ne,
171}
172
173const_assert_eq!(size_of::<SratGenericInitiator>(), 32);
174
175open_enum::open_enum! {
176 pub enum SratGenericInitiatorFlags: u32 {
177 ENABLED = 1 << 0,
178 ARCHITECTURAL_TRANSACTIONS = 1 << 1,
179 }
180}
181
182impl SratGenericInitiator {
183 pub fn new_pci(segment: u16, bus: u8, device: u8, function: u8, vnode: u32) -> Self {
187 let mut device_handle = [0u8; 16];
193 device_handle[0..2].copy_from_slice(&segment.to_le_bytes());
194 device_handle[2] = bus;
195 device_handle[3] = ((device & 0x1f) << 3) | (function & 0x7);
196 Self {
197 typ: SratType::GENERIC_INITIATOR,
198 length: size_of::<Self>() as u8,
199 reserved1: 0,
200 device_handle_type: SratDeviceHandleType::PCI,
201 proximity_domain: vnode.into(),
202 device_handle,
203 flags: SratGenericInitiatorFlags::ENABLED.0.into(),
204 reserved2: 0.into(),
205 }
206 }
207}
208
209#[repr(C)]
210#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
211pub struct SratMemory {
212 pub typ: SratType,
213 pub length: u8,
214 pub proximity_domain: u32_ne,
215 pub rsvd1: u16_ne,
216 pub low_address: u32_ne,
217 pub high_address: u32_ne,
218 pub low_length: u32_ne,
219 pub high_length: u32_ne,
220 pub rsvd2: u32_ne,
221 pub flags: u32_ne,
222 pub rsvd3: u64_ne,
223}
224
225impl core::fmt::Debug for SratMemory {
226 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
227 let address =
228 u64::read_from_bytes([self.low_address, self.high_address].as_bytes()).unwrap();
229 let length = u64::read_from_bytes([self.low_length, self.high_length].as_bytes()).unwrap();
230
231 f.debug_struct("SratMemory")
232 .field("typ", &self.typ)
233 .field("length", &self.length)
234 .field("proximity_domain", &self.proximity_domain)
235 .field("rsvd1", &self.rsvd1)
236 .field("address", &address)
237 .field("_end_address", &(address + length))
238 .field("length", &length)
239 .field("rsvd2", &self.rsvd2)
240 .field("flags", &self.flags)
241 .field("rsvd3", &self.rsvd3)
242 .finish()
243 }
244}
245
246const_assert_eq!(size_of::<SratMemory>(), 40);
247
248open_enum::open_enum! {
249 pub enum SratMemoryFlags: u32 {
250 ENABLED = 1 << 0,
251 HOT_PLUGGABLE = 1 << 1,
252 NVRAM = 1 << 2,
253 }
254}
255
256impl SratMemory {
257 pub fn new(addr: u64, len: u64, vnode: u32) -> Self {
258 Self {
259 typ: SratType::MEMORY,
260 length: size_of::<Self>() as u8,
261 proximity_domain: vnode.into(),
262 rsvd1: 0.into(),
263 low_address: (addr as u32).into(),
264 high_address: ((addr >> 32) as u32).into(),
265 low_length: (len as u32).into(),
266 high_length: ((len >> 32) as u32).into(),
267 rsvd2: 0.into(),
268 flags: SratMemoryFlags::ENABLED.0.into(),
269 rsvd3: 0.into(),
270 }
271 }
272}
273
274#[derive(Debug)]
275pub enum ParseSratError {
276 MissingAcpiHeader,
277 InvalidSignature([u8; 4]),
278 MismatchedLength { in_header: usize, actual: usize },
279 MissingFixedHeader,
280 BadApic,
281 BadMemory,
282 UnknownType(u8),
283}
284
285impl core::fmt::Display for ParseSratError {
286 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
287 match self {
288 Self::MissingAcpiHeader => write!(f, "could not read standard ACPI header"),
289 Self::InvalidSignature(sig) => {
290 write!(f, "invalid signature. expected b\"SRAT\", found {sig:?}")
291 }
292 Self::MismatchedLength { in_header, actual } => {
293 write!(f, "mismatched len. in_header: {in_header}, actual {actual}")
294 }
295 Self::MissingFixedHeader => write!(f, "missing fixed SRAT header"),
296 Self::BadApic => write!(f, "could not read APIC structure"),
297 Self::BadMemory => write!(f, "could not read MEMORY structure"),
298 Self::UnknownType(ty) => write!(f, "unknown SRAT structure type: {ty}"),
299 }
300 }
301}
302
303impl core::error::Error for ParseSratError {}
304
305pub fn parse_srat<'a>(
306 raw_srat: &'a [u8],
307 mut on_apic: impl FnMut(&'a SratApic),
308 mut on_memory: impl FnMut(&'a SratMemory),
309) -> Result<(&'a crate::Header, &'a SratHeader), ParseSratError> {
310 let raw_srat_len = raw_srat.len();
311 let (acpi_header, buf) = Ref::<_, crate::Header>::from_prefix(raw_srat)
312 .map_err(|_| ParseSratError::MissingAcpiHeader)?; if acpi_header.signature != *b"SRAT" {
315 return Err(ParseSratError::InvalidSignature(acpi_header.signature));
316 }
317
318 if acpi_header.length.get() as usize != raw_srat_len {
319 return Err(ParseSratError::MismatchedLength {
320 in_header: acpi_header.length.get() as usize,
321 actual: raw_srat_len,
322 });
323 }
324
325 let (srat_header, mut buf) =
326 Ref::<_, SratHeader>::from_prefix(buf).map_err(|_| ParseSratError::MissingFixedHeader)?; while !buf.is_empty() {
329 buf = match SratType(buf[0]) {
330 SratType::APIC => {
331 let (apic, rest) =
332 Ref::<_, SratApic>::from_prefix(buf).map_err(|_| ParseSratError::BadApic)?; on_apic(Ref::into_ref(apic));
334 rest
335 }
336 SratType::MEMORY => {
337 let (mem, rest) = Ref::<_, SratMemory>::from_prefix(buf)
338 .map_err(|_| ParseSratError::BadMemory)?; on_memory(Ref::into_ref(mem));
340 rest
341 }
342 _ => return Err(ParseSratError::UnknownType(buf[0])),
343 }
344 }
345
346 Ok((Ref::into_ref(acpi_header), Ref::into_ref(srat_header)))
347}
348
349#[cfg(feature = "alloc")]
350pub mod alloc_parse {
351 use super::*;
352 use alloc::vec::Vec;
353
354 #[derive(Debug)]
355 pub struct BorrowedSrat<'a> {
356 pub acpi_header: &'a crate::Header,
357 pub srat_header: &'a SratHeader,
358 pub apics: Vec<&'a SratApic>,
359 pub memory: Vec<&'a SratMemory>,
360 }
361
362 #[derive(Debug)]
363 pub struct OwnedSrat {
364 pub acpi_header: crate::Header,
365 pub srat_header: SratHeader,
366 pub apics: Vec<SratApic>,
367 pub memory: Vec<SratMemory>,
368 }
369
370 impl From<BorrowedSrat<'_>> for OwnedSrat {
371 fn from(b: BorrowedSrat<'_>) -> Self {
372 OwnedSrat {
373 acpi_header: *b.acpi_header,
374 srat_header: *b.srat_header,
375 apics: b.apics.into_iter().cloned().collect(),
376 memory: b.memory.into_iter().cloned().collect(),
377 }
378 }
379 }
380
381 impl BorrowedSrat<'_> {
382 pub fn new(raw_srat: &[u8]) -> Result<BorrowedSrat<'_>, ParseSratError> {
383 let mut apics = Vec::new();
384 let mut memory = Vec::new();
385 let (acpi_header, srat_header) =
386 parse_srat(raw_srat, |x| apics.push(x), |x| memory.push(x))?;
387
388 Ok(BorrowedSrat {
389 acpi_header,
390 srat_header,
391 apics,
392 memory,
393 })
394 }
395 }
396
397 impl OwnedSrat {
398 pub fn new(raw_srat: &[u8]) -> Result<OwnedSrat, ParseSratError> {
399 Ok(BorrowedSrat::new(raw_srat)?.into())
400 }
401 }
402}