sdt.rs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. use crate::{fadt::Fadt, hpet::HpetTable, madt::Madt, mcfg::Mcfg, AcpiError, AcpiHandler, AmlTable};
  2. use core::{fmt, mem, mem::MaybeUninit, str};
  3. pub const ACPI_VERSION_2_0: u8 = 20;
  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. #[repr(C, packed)]
  7. pub struct ExtendedField<T: Copy, const MIN_VERSION: u8>(MaybeUninit<T>);
  8. impl<T: Copy, const MIN_VERSION: u8> ExtendedField<T, MIN_VERSION> {
  9. /// Access the field if it's present for the given ACPI version. You should get this version from another ACPI
  10. /// structure, such as the RSDT/XSDT.
  11. ///
  12. /// ### Safety
  13. /// If a bogus ACPI version is passed, this function may access uninitialised data, which is unsafe.
  14. pub unsafe fn access(&self, version: u8) -> Option<T> {
  15. if version >= MIN_VERSION {
  16. Some(self.0.assume_init())
  17. } else {
  18. None
  19. }
  20. }
  21. }
  22. /// All SDTs share the same header, and are `length` bytes long. The signature tells us which SDT
  23. /// this is.
  24. ///
  25. /// The ACPI Spec (Version 6.2) defines the following SDT signatures:
  26. /// "APIC" - Multiple APIC Descriptor Table (MADT)
  27. /// "BGRT" - Boot Graphics Resource Table
  28. /// "BERT" - Boot Error Record Table
  29. /// "CPEP" - Corrected Platform Error Polling Table
  30. /// "DSDT" - Differentiated System Descriptor Table
  31. /// "ECDT" - Embedded Controller Boot Resources Table
  32. /// "EINJ" - Error Injection Table
  33. /// "ERST" - Error Record Serialization Table
  34. /// "FACP" - Fixed ACPI Description Table (FADT)
  35. /// "FACS" - Firmware ACPI Control Structure
  36. /// "FPDT" - Firmware Performance Data Table
  37. /// "GTDT" - Generic Timer Description Table
  38. /// "HEST" - Hardware Error Source Table
  39. /// "HMAT" - Heterogeneous Memory Attributes Table
  40. /// "MSCT" - Maximum System Characteristics Table
  41. /// "MPST" - Memory Power State Table
  42. /// "NFIT" - NVDIMM Firmware Interface Table
  43. /// "OEMx" - Various OEM-specific tables
  44. /// "PDTT" - Platform Debug Trigger Table
  45. /// "PMTT" - Platform Memory Topology Table
  46. /// "PPTT" - Processor Properties Topology Table
  47. /// "PSDT" - Persistent System Description Table
  48. /// "RASF" - ACPI RAS Feature Table
  49. /// "RSDT" - Root System Descriptor Table
  50. /// "SBST" - Smart Battery Specification Table
  51. /// "SLIT" - System Locality Information Table
  52. /// "SRAT" - System Resource Affinity Table
  53. /// "SSDT" - Secondary System Description Table
  54. /// "XSDT" - eXtended System Descriptor Table
  55. ///
  56. /// We've come across some more ACPI tables in the wild:
  57. /// "WAET" - Windows ACPI Emulated device Table
  58. #[derive(Clone, Copy)]
  59. #[repr(C, packed)]
  60. pub struct SdtHeader {
  61. pub signature: Signature,
  62. pub length: u32,
  63. pub revision: u8,
  64. pub checksum: u8,
  65. pub oem_id: [u8; 6],
  66. pub oem_table_id: [u8; 8],
  67. pub oem_revision: u32,
  68. pub creator_id: u32,
  69. pub creator_revision: u32,
  70. }
  71. impl SdtHeader {
  72. /// Check that:
  73. /// a) The signature matches the one given
  74. /// b) The checksum of the SDT
  75. ///
  76. /// This assumes that the whole SDT is mapped.
  77. pub fn validate(&self, signature: Signature) -> Result<(), AcpiError> {
  78. // Check the signature
  79. if self.signature != signature {
  80. return Err(AcpiError::SdtInvalidSignature(signature));
  81. }
  82. // Check the OEM id
  83. if str::from_utf8(&self.oem_id).is_err() {
  84. return Err(AcpiError::SdtInvalidOemId(signature));
  85. }
  86. // Check the OEM table id
  87. if str::from_utf8(&self.oem_table_id).is_err() {
  88. return Err(AcpiError::SdtInvalidTableId(signature));
  89. }
  90. // Validate the checksum
  91. let self_ptr = self as *const SdtHeader as *const u8;
  92. let mut sum: u8 = 0;
  93. for i in 0..self.length {
  94. sum = sum.wrapping_add(unsafe { *(self_ptr.offset(i as isize)) } as u8);
  95. }
  96. if sum > 0 {
  97. return Err(AcpiError::SdtInvalidChecksum(signature));
  98. }
  99. Ok(())
  100. }
  101. pub fn oem_id<'a>(&'a self) -> &'a str {
  102. // Safe to unwrap because checked in `validate`
  103. str::from_utf8(&self.oem_id).unwrap()
  104. }
  105. pub fn oem_table_id<'a>(&'a self) -> &'a str {
  106. // Safe to unwrap because checked in `validate`
  107. str::from_utf8(&self.oem_table_id).unwrap()
  108. }
  109. }
  110. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
  111. #[repr(transparent)]
  112. pub struct Signature([u8; 4]);
  113. impl Signature {
  114. pub const RSDT: Signature = Signature(*b"RSDT");
  115. pub const XSDT: Signature = Signature(*b"XSDT");
  116. pub const FADT: Signature = Signature(*b"FACP");
  117. pub const HPET: Signature = Signature(*b"HPET");
  118. pub const MADT: Signature = Signature(*b"APIC");
  119. pub const MCFG: Signature = Signature(*b"MCFG");
  120. pub const SSDT: Signature = Signature(*b"SSDT");
  121. pub fn as_str(&self) -> &str {
  122. str::from_utf8(&self.0).unwrap()
  123. }
  124. }
  125. impl fmt::Display for Signature {
  126. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  127. write!(f, "{}", self.as_str())
  128. }
  129. }
  130. impl fmt::Debug for Signature {
  131. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  132. write!(f, "\"{}\"", self.as_str())
  133. }
  134. }
  135. /// Takes the physical address of an SDT, and maps, clones and unmaps its header. Useful for
  136. /// finding out how big it is to map it correctly later.
  137. pub(crate) fn peek_at_sdt_header<H>(handler: &mut H, physical_address: usize) -> SdtHeader
  138. where
  139. H: AcpiHandler,
  140. {
  141. let mapping =
  142. unsafe { handler.map_physical_region::<SdtHeader>(physical_address, mem::size_of::<SdtHeader>()) };
  143. (*mapping).clone()
  144. }