sdt.rs 7.1 KB

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