acpi/
sdt.rs

1use crate::{AcpiError, AcpiHandler, AcpiResult, AcpiTable, PhysicalMapping};
2use 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)]
8pub struct ExtendedField<T: Copy, const MIN_REVISION: u8>(MaybeUninit<T>);
9
10impl<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.
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)]
100pub 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
112impl SdtHeader {
113    /// Whether values of header fields are permitted.
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.
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.
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.
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.get().validate()?;
201
202        Ok(table_mapping)
203    }
204
205    pub fn oem_id(&self) -> &str {
206        // Safe to unwrap because checked in `validate`
207        str::from_utf8(&self.oem_id).unwrap()
208    }
209
210    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)]
218pub struct Signature([u8; 4]);
219
220impl 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
287    pub fn as_str(&self) -> &str {
288        str::from_utf8(&self.0).unwrap()
289    }
290}
291
292impl fmt::Display for Signature {
293    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294        write!(f, "{}", self.as_str())
295    }
296}
297
298impl fmt::Debug for Signature {
299    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300        write!(f, "\"{}\"", self.as_str())
301    }
302}