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 }
48}
49
50#[repr(C)]
51#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
52pub struct SratApic {
53 pub typ: SratType,
54 pub length: u8,
55 pub proximity_domain_byte1: u8,
56 pub apic_id: u8,
57 pub flags: u32_ne,
58 pub local_sapic_eid: u8,
59 pub proximity_domain_byte2: u8,
60 pub proximity_domain_byte3: u8,
61 pub proximity_domain_byte4: u8,
62 pub clock_domain: u32_ne,
63}
64
65const_assert_eq!(size_of::<SratApic>(), 16);
66
67pub const SRAT_APIC_ENABLED: u32 = 1 << 0;
68
69impl SratApic {
70 pub fn new(apic_id: u8, vnode: u32) -> Self {
71 let vnode = vnode.to_le_bytes();
72 Self {
73 typ: SratType::APIC,
74 length: size_of::<Self>() as u8,
75 proximity_domain_byte1: vnode[0],
76 apic_id,
77 flags: SRAT_APIC_ENABLED.into(),
78 local_sapic_eid: 0,
79 proximity_domain_byte2: vnode[1],
80 proximity_domain_byte3: vnode[2],
81 proximity_domain_byte4: vnode[3],
82 clock_domain: 0.into(),
83 }
84 }
85}
86
87#[repr(C)]
88#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
89pub struct SratX2Apic {
90 pub typ: SratType,
91 pub length: u8,
92 pub reserved: u16_ne,
93 pub proximity_domain: u32_ne,
94 pub x2_apic_id: u32_ne,
95 pub flags: u32_ne,
96 pub clock_domain: u32_ne,
97 pub reserved2: u32_ne,
98}
99
100const_assert_eq!(size_of::<SratX2Apic>(), 24);
101
102impl SratX2Apic {
103 pub fn new(x2_apic_id: u32, vnode: u32) -> Self {
104 Self {
105 typ: SratType::X2APIC,
106 length: size_of::<Self>() as u8,
107 x2_apic_id: x2_apic_id.into(),
108 flags: SRAT_APIC_ENABLED.into(),
109 clock_domain: 0.into(),
110 reserved: 0.into(),
111 proximity_domain: vnode.into(),
112 reserved2: 0.into(),
113 }
114 }
115}
116
117#[repr(C)]
118#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
119pub struct SratGicc {
120 pub typ: SratType,
121 pub length: u8,
122 pub proximity_domain: u32_ne,
123 pub acpi_processor_uid: u32_ne,
124 pub flags: u32_ne,
125 pub clock_domain: u32_ne,
126}
127
128const_assert_eq!(size_of::<SratGicc>(), 18);
129
130impl SratGicc {
131 pub fn new(acpi_processor_uid: u32, vnode: u32) -> Self {
132 Self {
133 typ: SratType::GICC,
134 length: size_of::<Self>() as u8,
135 acpi_processor_uid: acpi_processor_uid.into(),
136 flags: SRAT_APIC_ENABLED.into(),
137 clock_domain: 0.into(),
138 proximity_domain: vnode.into(),
139 }
140 }
141}
142
143#[repr(C)]
144#[derive(Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
145pub struct SratMemory {
146 pub typ: SratType,
147 pub length: u8,
148 pub proximity_domain: u32_ne,
149 pub rsvd1: u16_ne,
150 pub low_address: u32_ne,
151 pub high_address: u32_ne,
152 pub low_length: u32_ne,
153 pub high_length: u32_ne,
154 pub rsvd2: u32_ne,
155 pub flags: u32_ne,
156 pub rsvd3: u64_ne,
157}
158
159impl core::fmt::Debug for SratMemory {
160 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
161 let address =
162 u64::read_from_bytes([self.low_address, self.high_address].as_bytes()).unwrap();
163 let length = u64::read_from_bytes([self.low_length, self.high_length].as_bytes()).unwrap();
164
165 f.debug_struct("SratMemory")
166 .field("typ", &self.typ)
167 .field("length", &self.length)
168 .field("proximity_domain", &self.proximity_domain)
169 .field("rsvd1", &self.rsvd1)
170 .field("address", &address)
171 .field("_end_address", &(address + length))
172 .field("length", &length)
173 .field("rsvd2", &self.rsvd2)
174 .field("flags", &self.flags)
175 .field("rsvd3", &self.rsvd3)
176 .finish()
177 }
178}
179
180const_assert_eq!(size_of::<SratMemory>(), 40);
181
182open_enum::open_enum! {
183 pub enum SratMemoryFlags: u32 {
184 ENABLED = 1 << 0,
185 HOT_PLUGGABLE = 1 << 1,
186 NVRAM = 1 << 2,
187 }
188}
189
190impl SratMemory {
191 pub fn new(addr: u64, len: u64, vnode: u32) -> Self {
192 Self {
193 typ: SratType::MEMORY,
194 length: size_of::<Self>() as u8,
195 proximity_domain: vnode.into(),
196 rsvd1: 0.into(),
197 low_address: (addr as u32).into(),
198 high_address: ((addr >> 32) as u32).into(),
199 low_length: (len as u32).into(),
200 high_length: ((len >> 32) as u32).into(),
201 rsvd2: 0.into(),
202 flags: SratMemoryFlags::ENABLED.0.into(),
203 rsvd3: 0.into(),
204 }
205 }
206}
207
208#[derive(Debug)]
209pub enum ParseSratError {
210 MissingAcpiHeader,
211 InvalidSignature([u8; 4]),
212 MismatchedLength { in_header: usize, actual: usize },
213 MissingFixedHeader,
214 BadApic,
215 BadMemory,
216 UnknownType(u8),
217}
218
219impl core::fmt::Display for ParseSratError {
220 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
221 match self {
222 Self::MissingAcpiHeader => write!(f, "could not read standard ACPI header"),
223 Self::InvalidSignature(sig) => {
224 write!(f, "invalid signature. expected b\"SRAT\", found {sig:?}")
225 }
226 Self::MismatchedLength { in_header, actual } => {
227 write!(f, "mismatched len. in_header: {in_header}, actual {actual}")
228 }
229 Self::MissingFixedHeader => write!(f, "missing fixed SRAT header"),
230 Self::BadApic => write!(f, "could not read APIC structure"),
231 Self::BadMemory => write!(f, "could not read MEMORY structure"),
232 Self::UnknownType(ty) => write!(f, "unknown SRAT structure type: {ty}"),
233 }
234 }
235}
236
237impl core::error::Error for ParseSratError {}
238
239pub fn parse_srat<'a>(
240 raw_srat: &'a [u8],
241 mut on_apic: impl FnMut(&'a SratApic),
242 mut on_memory: impl FnMut(&'a SratMemory),
243) -> Result<(&'a crate::Header, &'a SratHeader), ParseSratError> {
244 let raw_srat_len = raw_srat.len();
245 let (acpi_header, buf) = Ref::<_, crate::Header>::from_prefix(raw_srat)
246 .map_err(|_| ParseSratError::MissingAcpiHeader)?; if acpi_header.signature != *b"SRAT" {
249 return Err(ParseSratError::InvalidSignature(acpi_header.signature));
250 }
251
252 if acpi_header.length.get() as usize != raw_srat_len {
253 return Err(ParseSratError::MismatchedLength {
254 in_header: acpi_header.length.get() as usize,
255 actual: raw_srat_len,
256 });
257 }
258
259 let (srat_header, mut buf) =
260 Ref::<_, SratHeader>::from_prefix(buf).map_err(|_| ParseSratError::MissingFixedHeader)?; while !buf.is_empty() {
263 buf = match SratType(buf[0]) {
264 SratType::APIC => {
265 let (apic, rest) =
266 Ref::<_, SratApic>::from_prefix(buf).map_err(|_| ParseSratError::BadApic)?; on_apic(Ref::into_ref(apic));
268 rest
269 }
270 SratType::MEMORY => {
271 let (mem, rest) = Ref::<_, SratMemory>::from_prefix(buf)
272 .map_err(|_| ParseSratError::BadMemory)?; on_memory(Ref::into_ref(mem));
274 rest
275 }
276 _ => return Err(ParseSratError::UnknownType(buf[0])),
277 }
278 }
279
280 Ok((Ref::into_ref(acpi_header), Ref::into_ref(srat_header)))
281}
282
283#[cfg(feature = "alloc")]
284pub mod alloc_parse {
285 use super::*;
286 use alloc::vec::Vec;
287
288 #[derive(Debug)]
289 pub struct BorrowedSrat<'a> {
290 pub acpi_header: &'a crate::Header,
291 pub srat_header: &'a SratHeader,
292 pub apics: Vec<&'a SratApic>,
293 pub memory: Vec<&'a SratMemory>,
294 }
295
296 #[derive(Debug)]
297 pub struct OwnedSrat {
298 pub acpi_header: crate::Header,
299 pub srat_header: SratHeader,
300 pub apics: Vec<SratApic>,
301 pub memory: Vec<SratMemory>,
302 }
303
304 impl From<BorrowedSrat<'_>> for OwnedSrat {
305 fn from(b: BorrowedSrat<'_>) -> Self {
306 OwnedSrat {
307 acpi_header: *b.acpi_header,
308 srat_header: *b.srat_header,
309 apics: b.apics.into_iter().cloned().collect(),
310 memory: b.memory.into_iter().cloned().collect(),
311 }
312 }
313 }
314
315 impl BorrowedSrat<'_> {
316 pub fn new(raw_srat: &[u8]) -> Result<BorrowedSrat<'_>, ParseSratError> {
317 let mut apics = Vec::new();
318 let mut memory = Vec::new();
319 let (acpi_header, srat_header) =
320 parse_srat(raw_srat, |x| apics.push(x), |x| memory.push(x))?;
321
322 Ok(BorrowedSrat {
323 acpi_header,
324 srat_header,
325 apics,
326 memory,
327 })
328 }
329 }
330
331 impl OwnedSrat {
332 pub fn new(raw_srat: &[u8]) -> Result<OwnedSrat, ParseSratError> {
333 Ok(BorrowedSrat::new(raw_srat)?.into())
334 }
335 }
336}