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