sdt.rs 7.4 KB

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