sdt.rs 7.1 KB

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