sdt.rs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. use core::{mem, str};
  2. use fadt::Fadt;
  3. use hpet::Hpet;
  4. use {Acpi, AcpiError, AcpiHandler};
  5. /// All SDTs share the same header, and are `length` bytes long. The signature tells us which SDT
  6. /// this is.
  7. ///
  8. /// The ACPI Spec (Version 6.2) defines the following SDT signatures:
  9. /// "APIC" - Multiple APIC Descriptor Table (MADT)
  10. /// "BGRT" - Boot Graphics Resource Table
  11. /// "BERT" - Boot Error Record Table
  12. /// "CPEP" - Corrected Platform Error Polling Table
  13. /// "DSDT" - Differentiated System Descriptor Table
  14. /// "ECDT" - Embedded Controller Boot Resources Table
  15. /// "EINJ" - Error Injection Table
  16. /// "ERST" - Error Record Serialization Table
  17. /// "FACP" - Fixed ACPI Description Table (FADT)
  18. /// "FACS" - Firmware ACPI Control Structure
  19. /// "FPDT" - Firmware Performance Data Table
  20. /// "GTDT" - Generic Timer Description Table
  21. /// "HEST" - Hardware Error Source Table
  22. /// "HMAT" - Heterogeneous Memory Attributes Table
  23. /// "MSCT" - Maximum System Characteristics Table
  24. /// "MPST" - Memory Power State Table
  25. /// "NFIT" - NVDIMM Firmware Interface Table
  26. /// "OEMx" - Various OEM-specific tables
  27. /// "PDTT" - Platform Debug Trigger Table
  28. /// "PMTT" - Platform Memory Topology Table
  29. /// "PPTT" - Processor Properties Topology Table
  30. /// "PSDT" - Persistent System Description Table
  31. /// "RASF" - ACPI RAS Feature Table
  32. /// "RSDT" - Root System Descriptor Table
  33. /// "SBST" - Smart Battery Specification Table
  34. /// "SLIT" - System Locality Information Table
  35. /// "SRAT" - System Resource Affinity Table
  36. /// "SSDT" - Secondary System Description Table
  37. /// "XSDT" - eXtended System Descriptor Table
  38. #[derive(Clone)]
  39. #[repr(C, packed)]
  40. pub struct SdtHeader {
  41. signature: [u8; 4],
  42. length: u32,
  43. revision: u8,
  44. checksum: u8,
  45. oem_id: [u8; 6],
  46. oem_table_id: [u8; 8],
  47. oem_revision: u32,
  48. creator_id: u32,
  49. creator_revision: u32,
  50. }
  51. impl SdtHeader {
  52. /// Check that:
  53. /// a) The signature matches the one given
  54. /// b) The checksum of the SDT
  55. ///
  56. /// This assumes that the whole SDT is mapped.
  57. pub fn validate(&self, signature: &[u8; 4]) -> Result<(), AcpiError> {
  58. // Check the signature
  59. if &self.signature != signature {
  60. return Err(AcpiError::SdtInvalidSignature(*signature));
  61. }
  62. // Check the OEM id
  63. if str::from_utf8(&self.oem_id).is_err() {
  64. return Err(AcpiError::SdtInvalidOemId(*signature));
  65. }
  66. // Check the OEM table id
  67. if str::from_utf8(&self.oem_table_id).is_err() {
  68. return Err(AcpiError::SdtInvalidTableId(*signature));
  69. }
  70. // Validate the checksum
  71. let self_ptr = self as *const SdtHeader as *const u8;
  72. let mut sum: u8 = 0;
  73. for i in 0..self.length {
  74. sum = sum.wrapping_add(unsafe { *(self_ptr.offset(i as isize)) } as u8);
  75. }
  76. if sum > 0 {
  77. return Err(AcpiError::SdtInvalidChecksum(*signature));
  78. }
  79. Ok(())
  80. }
  81. pub fn raw_signature(&self) -> [u8; 4] {
  82. self.signature
  83. }
  84. pub fn signature<'a>(&'a self) -> &'a str {
  85. // Safe to unwrap because we check signature is valid UTF8 in `validate`
  86. str::from_utf8(&self.signature).unwrap()
  87. }
  88. pub fn length(&self) -> u32 {
  89. self.length
  90. }
  91. pub fn revision(&self) -> u8 {
  92. self.revision
  93. }
  94. pub fn oem_id<'a>(&'a self) -> &'a str {
  95. // Safe to unwrap because checked in `validate`
  96. str::from_utf8(&self.oem_id).unwrap()
  97. }
  98. pub fn oem_table_id<'a>(&'a self) -> &'a str {
  99. // Safe to unwrap because checked in `validate`
  100. str::from_utf8(&self.oem_table_id).unwrap()
  101. }
  102. #[cfg(test)]
  103. pub(crate) fn make_testcase(
  104. signature: [u8; 4],
  105. length: u32,
  106. revision: u8,
  107. checksum: u8,
  108. oem_id: [u8; 6],
  109. oem_table_id: [u8; 8],
  110. oem_revision: u32,
  111. creator_id: u32,
  112. creator_revision: u32,
  113. ) -> SdtHeader {
  114. SdtHeader {
  115. signature,
  116. length,
  117. revision,
  118. checksum,
  119. oem_id,
  120. oem_table_id,
  121. oem_revision,
  122. creator_id,
  123. creator_revision,
  124. }
  125. }
  126. }
  127. /// Takes the physical address of an SDT, and maps, clones and unmaps its header. Useful for
  128. /// finding out how big it is to map it correctly later.
  129. pub(crate) fn peek_at_sdt_header<H>(handler: &mut H, physical_address: usize) -> SdtHeader
  130. where
  131. H: AcpiHandler,
  132. {
  133. let mapping =
  134. handler.map_physical_region::<SdtHeader>(physical_address, mem::size_of::<SdtHeader>());
  135. let header = (*mapping).clone();
  136. handler.unmap_physical_region(mapping);
  137. header
  138. }
  139. /// This takes the physical address of an SDT, maps it correctly and dispatches it to whatever
  140. /// function parses that table.
  141. pub(crate) fn dispatch_sdt<'a, 'h, H>(
  142. acpi: &'a mut Acpi<'h, H>,
  143. physical_address: usize,
  144. ) -> Result<(), AcpiError>
  145. where
  146. 'h: 'a,
  147. H: AcpiHandler + 'a,
  148. {
  149. let header = peek_at_sdt_header(acpi.handler, physical_address);
  150. info!(
  151. "Dispatching SDT with signature {:?} and length {:?}",
  152. header.signature(),
  153. header.length()
  154. );
  155. /*
  156. * For a recognised signature, a new physical mapping should be created with the correct type
  157. * and length, and then the dispatched to the correct function to actually parse the table.
  158. */
  159. match header.signature() {
  160. "FACP" => {
  161. let fadt_mapping = acpi
  162. .handler
  163. .map_physical_region::<Fadt>(physical_address, mem::size_of::<Fadt>());
  164. ::fadt::parse_fadt(acpi, &fadt_mapping)?;
  165. acpi.handler.unmap_physical_region(fadt_mapping);
  166. }
  167. "HPET" => {
  168. let hpet_mapping = acpi
  169. .handler
  170. .map_physical_region::<Hpet>(physical_address, mem::size_of::<Hpet>());
  171. ::hpet::parse_hpet(&hpet_mapping)?;
  172. acpi.handler.unmap_physical_region(hpet_mapping);
  173. }
  174. signature => {
  175. /*
  176. * We don't recognise this signature. Early on, this probably just means we don't
  177. * have support yet, but later on maybe this should become an actual error
  178. */
  179. warn!("Unsupported SDT signature: {}. Skipping.", signature);
  180. }
  181. }
  182. Ok(())
  183. }