1 use crate::{AcpiError, AcpiHandler, AcpiResult, AcpiTable, PhysicalMapping};
2 use core::{fmt, mem::MaybeUninit, str};
3 
4 /// Represents a field which may or may not be present within an ACPI structure, depending on the version of ACPI
5 /// that a system supports. If the field is not present, it is not safe to treat the data as initialised.
6 #[derive(Debug, Clone, Copy)]
7 #[repr(transparent)]
8 pub struct ExtendedField<T: Copy, const MIN_REVISION: u8>(MaybeUninit<T>);
9 
10 impl<T: Copy, const MIN_REVISION: u8> ExtendedField<T, MIN_REVISION> {
11     /// Access the field if it's present for the given revision of the table.
12     ///
13     /// ### Safety
14     /// If a bogus ACPI version is passed, this function may access uninitialised data.
access(&self, revision: u8) -> Option<T>15     pub unsafe fn access(&self, revision: u8) -> Option<T> {
16         if revision >= MIN_REVISION {
17             Some(unsafe { self.0.assume_init() })
18         } else {
19             None
20         }
21     }
22 }
23 
24 /// All SDTs share the same header, and are `length` bytes long. The signature tells us which SDT
25 /// this is.
26 ///
27 /// The ACPI Spec (Version 6.4) defines the following SDT signatures:
28 ///
29 /// * APIC - Multiple APIC Description Table (MADT)
30 /// * BERT - Boot Error Record Table
31 /// * BGRT - Boot Graphics Resource Table
32 /// * CPEP - Corrected Platform Error Polling Table
33 /// * DSDT - Differentiated System Description Table (DSDT)
34 /// * ECDT - Embedded Controller Boot Resources Table
35 /// * EINJ - Error Injection Table
36 /// * ERST - Error Record Serialization Table
37 /// * FACP - Fixed ACPI Description Table (FADT)
38 /// * FACS - Firmware ACPI Control Structure
39 /// * FPDT - Firmware Performance Data Table
40 /// * GTDT - Generic Timer Description Table
41 /// * HEST - Hardware Error Source Table
42 /// * MSCT - Maximum System Characteristics Table
43 /// * MPST - Memory Power StateTable
44 /// * NFIT - NVDIMM Firmware Interface Table
45 /// * OEMx - OEM Specific Information Tables
46 /// * PCCT - Platform Communications Channel Table
47 /// * PHAT - Platform Health Assessment Table
48 /// * PMTT - Platform Memory Topology Table
49 /// * PSDT - Persistent System Description Table
50 /// * RASF - ACPI RAS Feature Table
51 /// * RSDT - Root System Description Table
52 /// * SBST - Smart Battery Specification Table
53 /// * SDEV - Secure DEVices Table
54 /// * SLIT - System Locality Distance Information Table
55 /// * SRAT - System Resource Affinity Table
56 /// * SSDT - Secondary System Description Table
57 /// * XSDT - Extended System Description Table
58 ///
59 /// Acpi reserves the following signatures and the specifications for them can be found [here](https://uefi.org/acpi):
60 ///
61 /// * AEST - ARM Error Source Table
62 /// * BDAT - BIOS Data ACPI Table
63 /// * CDIT - Component Distance Information Table
64 /// * CEDT - CXL Early Discovery Table
65 /// * CRAT - Component Resource Attribute Table
66 /// * CSRT - Core System Resource Table
67 /// * DBGP - Debug Port Table
68 /// * DBG2 - Debug Port Table 2 (note: ACPI 6.4 defines this as "DBPG2" but this is incorrect)
69 /// * DMAR - DMA Remapping Table
70 /// * DRTM -Dynamic Root of Trust for Measurement Table
71 /// * ETDT - Event Timer Description Table (obsolete, superseeded by HPET)
72 /// * HPET - IA-PC High Precision Event Timer Table
73 /// * IBFT - iSCSI Boot Firmware Table
74 /// * IORT - I/O Remapping Table
75 /// * IVRS - I/O Virtualization Reporting Structure
76 /// * LPIT - Low Power Idle Table
77 /// * MCFG - PCI Express Memory-mapped Configuration Space base address description table
78 /// * MCHI - Management Controller Host Interface table
79 /// * MPAM - ARM Memory Partitioning And Monitoring table
80 /// * MSDM - Microsoft Data Management Table
81 /// * PRMT - Platform Runtime Mechanism Table
82 /// * RGRT - Regulatory Graphics Resource Table
83 /// * SDEI - Software Delegated Exceptions Interface table
84 /// * SLIC - Microsoft Software Licensing table
85 /// * SPCR - Microsoft Serial Port Console Redirection table
86 /// * SPMI - Server Platform Management Interface table
87 /// * STAO - _STA Override table
88 /// * SVKL - Storage Volume Key Data table (Intel TDX only)
89 /// * TCPA - Trusted Computing Platform Alliance Capabilities Table
90 /// * TPM2 - Trusted Platform Module 2 Table
91 /// * UEFI - Unified Extensible Firmware Interface Specification table
92 /// * WAET - Windows ACPI Emulated Devices Table
93 /// * WDAT - Watch Dog Action Table
94 /// * WDRT - Watchdog Resource Table
95 /// * WPBT - Windows Platform Binary Table
96 /// * WSMT - Windows Security Mitigations Table
97 /// * XENV - Xen Project
98 #[derive(Debug, Clone, Copy)]
99 #[repr(C, packed)]
100 pub struct SdtHeader {
101     pub signature: Signature,
102     pub length: u32,
103     pub revision: u8,
104     pub checksum: u8,
105     pub oem_id: [u8; 6],
106     pub oem_table_id: [u8; 8],
107     pub oem_revision: u32,
108     pub creator_id: u32,
109     pub creator_revision: u32,
110 }
111 
112 impl SdtHeader {
113     /// Whether values of header fields are permitted.
validate_header_fields(&self, signature: Signature) -> AcpiResult<()>114     fn validate_header_fields(&self, signature: Signature) -> AcpiResult<()> {
115         // Check the signature
116         if self.signature != signature || str::from_utf8(&self.signature.0).is_err() {
117             return Err(AcpiError::SdtInvalidSignature(signature));
118         }
119 
120         // Check the OEM id
121         if str::from_utf8(&self.oem_id).is_err() {
122             return Err(AcpiError::SdtInvalidOemId(signature));
123         }
124 
125         // Check the OEM table id
126         if str::from_utf8(&self.oem_table_id).is_err() {
127             return Err(AcpiError::SdtInvalidTableId(signature));
128         }
129 
130         Ok(())
131     }
132 
133     /// Whether table is valid according to checksum.
validate_checksum(&self, signature: Signature) -> AcpiResult<()>134     fn validate_checksum(&self, signature: Signature) -> AcpiResult<()> {
135         // SAFETY: Entire table is mapped.
136         let table_bytes =
137             unsafe { core::slice::from_raw_parts((self as *const SdtHeader).cast::<u8>(), self.length as usize) };
138         let sum = table_bytes.iter().fold(0u8, |sum, &byte| sum.wrapping_add(byte));
139 
140         if sum == 0 {
141             Ok(())
142         } else {
143             Err(AcpiError::SdtInvalidChecksum(signature))
144         }
145     }
146 
147     /// Checks that:
148     ///
149     /// 1. The signature matches the one given.
150     /// 2. The values of various fields in the header are allowed.
151     /// 3. The checksum of the SDT is valid.
152     ///
153     /// This assumes that the whole SDT is mapped.
validate(&self, signature: Signature) -> AcpiResult<()>154     pub fn validate(&self, signature: Signature) -> AcpiResult<()> {
155         self.validate_header_fields(signature)?;
156         self.validate_checksum(signature)?;
157 
158         Ok(())
159     }
160 
161     /// Validates header, proceeding with checking entire table and returning a [`PhysicalMapping`] to it if
162     /// successful.
163     ///
164     /// The same checks are performed as [`SdtHeader::validate`], but `header_mapping` does not have to map the
165     /// entire table when calling. This is useful to avoid completely mapping a table that will be immediately
166     /// unmapped if it does not have a particular signature or has an invalid header.
validate_lazy<H: AcpiHandler, T: AcpiTable>( header_mapping: PhysicalMapping<H, Self>, handler: H, ) -> AcpiResult<PhysicalMapping<H, T>>167     pub(crate) fn validate_lazy<H: AcpiHandler, T: AcpiTable>(
168         header_mapping: PhysicalMapping<H, Self>,
169         handler: H,
170     ) -> AcpiResult<PhysicalMapping<H, T>> {
171         header_mapping.validate_header_fields(T::SIGNATURE)?;
172 
173         // Reuse `header_mapping` to access the rest of the table if the latter is already mapped entirely
174         let table_length = header_mapping.length as usize;
175         let table_mapping = if header_mapping.mapped_length() >= table_length {
176             // Avoid requesting table unmap twice (from both `header_mapping` and `table_mapping`)
177             let header_mapping = core::mem::ManuallyDrop::new(header_mapping);
178 
179             // SAFETY: `header_mapping` maps entire table.
180             unsafe {
181                 PhysicalMapping::new(
182                     header_mapping.physical_start(),
183                     header_mapping.virtual_start().cast::<T>(),
184                     table_length,
185                     header_mapping.mapped_length(),
186                     handler,
187                 )
188             }
189         } else {
190             // Unmap header as soon as possible
191             let table_phys_start = header_mapping.physical_start();
192             drop(header_mapping);
193 
194             // SAFETY: `table_phys_start` is the physical address of the header and the rest of the table.
195             unsafe { handler.map_physical_region(table_phys_start, table_length) }
196         };
197 
198         // This is usually redundant compared to simply calling `validate_checksum` but respects custom
199         // `AcpiTable::validate` implementations.
200         table_mapping.validate()?;
201 
202         Ok(table_mapping)
203     }
204 
oem_id(&self) -> &str205     pub fn oem_id(&self) -> &str {
206         // Safe to unwrap because checked in `validate`
207         str::from_utf8(&self.oem_id).unwrap()
208     }
209 
oem_table_id(&self) -> &str210     pub fn oem_table_id(&self) -> &str {
211         // Safe to unwrap because checked in `validate`
212         str::from_utf8(&self.oem_table_id).unwrap()
213     }
214 }
215 
216 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
217 #[repr(transparent)]
218 pub struct Signature([u8; 4]);
219 
220 impl Signature {
221     pub const RSDT: Signature = Signature(*b"RSDT");
222     pub const XSDT: Signature = Signature(*b"XSDT");
223     pub const FADT: Signature = Signature(*b"FACP");
224     pub const HPET: Signature = Signature(*b"HPET");
225     pub const MADT: Signature = Signature(*b"APIC");
226     pub const MCFG: Signature = Signature(*b"MCFG");
227     pub const SSDT: Signature = Signature(*b"SSDT");
228     pub const BERT: Signature = Signature(*b"BERT");
229     pub const BGRT: Signature = Signature(*b"BGRT");
230     pub const CPEP: Signature = Signature(*b"CPEP");
231     pub const DSDT: Signature = Signature(*b"DSDT");
232     pub const ECDT: Signature = Signature(*b"ECDT");
233     pub const EINJ: Signature = Signature(*b"EINJ");
234     pub const ERST: Signature = Signature(*b"ERST");
235     pub const FACS: Signature = Signature(*b"FACS");
236     pub const FPDT: Signature = Signature(*b"FPDT");
237     pub const GTDT: Signature = Signature(*b"GTDT");
238     pub const HEST: Signature = Signature(*b"HEST");
239     pub const MSCT: Signature = Signature(*b"MSCT");
240     pub const MPST: Signature = Signature(*b"MPST");
241     pub const NFIT: Signature = Signature(*b"NFIT");
242     pub const PCCT: Signature = Signature(*b"PCCT");
243     pub const PHAT: Signature = Signature(*b"PHAT");
244     pub const PMTT: Signature = Signature(*b"PMTT");
245     pub const PSDT: Signature = Signature(*b"PSDT");
246     pub const RASF: Signature = Signature(*b"RASF");
247     pub const SBST: Signature = Signature(*b"SBST");
248     pub const SDEV: Signature = Signature(*b"SDEV");
249     pub const SLIT: Signature = Signature(*b"SLIT");
250     pub const SRAT: Signature = Signature(*b"SRAT");
251     pub const AEST: Signature = Signature(*b"AEST");
252     pub const BDAT: Signature = Signature(*b"BDAT");
253     pub const CDIT: Signature = Signature(*b"CDIT");
254     pub const CEDT: Signature = Signature(*b"CEDT");
255     pub const CRAT: Signature = Signature(*b"CRAT");
256     pub const CSRT: Signature = Signature(*b"CSRT");
257     pub const DBGP: Signature = Signature(*b"DBGP");
258     pub const DBG2: Signature = Signature(*b"DBG2");
259     pub const DMAR: Signature = Signature(*b"DMAR");
260     pub const DRTM: Signature = Signature(*b"DRTM");
261     pub const ETDT: Signature = Signature(*b"ETDT");
262     pub const IBFT: Signature = Signature(*b"IBFT");
263     pub const IORT: Signature = Signature(*b"IORT");
264     pub const IVRS: Signature = Signature(*b"IVRS");
265     pub const LPIT: Signature = Signature(*b"LPIT");
266     pub const MCHI: Signature = Signature(*b"MCHI");
267     pub const MPAM: Signature = Signature(*b"MPAM");
268     pub const MSDM: Signature = Signature(*b"MSDM");
269     pub const PRMT: Signature = Signature(*b"PRMT");
270     pub const RGRT: Signature = Signature(*b"RGRT");
271     pub const SDEI: Signature = Signature(*b"SDEI");
272     pub const SLIC: Signature = Signature(*b"SLIC");
273     pub const SPCR: Signature = Signature(*b"SPCR");
274     pub const SPMI: Signature = Signature(*b"SPMI");
275     pub const STAO: Signature = Signature(*b"STAO");
276     pub const SVKL: Signature = Signature(*b"SVKL");
277     pub const TCPA: Signature = Signature(*b"TCPA");
278     pub const TPM2: Signature = Signature(*b"TPM2");
279     pub const UEFI: Signature = Signature(*b"UEFI");
280     pub const WAET: Signature = Signature(*b"WAET");
281     pub const WDAT: Signature = Signature(*b"WDAT");
282     pub const WDRT: Signature = Signature(*b"WDRT");
283     pub const WPBT: Signature = Signature(*b"WPBT");
284     pub const WSMT: Signature = Signature(*b"WSMT");
285     pub const XENV: Signature = Signature(*b"XENV");
286 
as_str(&self) -> &str287     pub fn as_str(&self) -> &str {
288         str::from_utf8(&self.0).unwrap()
289     }
290 }
291 
292 impl fmt::Display for Signature {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result293     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294         write!(f, "{}", self.as_str())
295     }
296 }
297 
298 impl fmt::Debug for Signature {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result299     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300         write!(f, "\"{}\"", self.as_str())
301     }
302 }
303