rsdp.rs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. use crate::{AcpiError, AcpiHandler, AcpiResult, PhysicalMapping};
  2. use core::{mem, ops::Range, slice, str};
  3. /// The size in bytes of the ACPI 1.0 RSDP.
  4. const RSDP_V1_LENGTH: usize = 20;
  5. /// The total size in bytes of the RSDP fields introduced in ACPI 2.0.
  6. const RSDP_V2_EXT_LENGTH: usize = mem::size_of::<Rsdp>() - RSDP_V1_LENGTH;
  7. /// The first structure found in ACPI. It just tells us where the RSDT is.
  8. ///
  9. /// On BIOS systems, it is either found in the first 1KiB of the Extended Bios Data Area, or between `0x000e0000`
  10. /// and `0x000fffff`. The signature is always on a 16 byte boundary. On (U)EFI, it may not be located in these
  11. /// locations, and so an address should be found in the EFI configuration table instead.
  12. ///
  13. /// The recommended way of locating the RSDP is to let the bootloader do it - Multiboot2 can pass a
  14. /// tag with the physical address of it. If this is not possible, a manual scan can be done.
  15. ///
  16. /// If `revision > 0`, (the hardware ACPI version is Version 2.0 or greater), the RSDP contains
  17. /// some new fields. For ACPI Version 1.0, these fields are not valid and should not be accessed.
  18. /// For ACPI Version 2.0+, `xsdt_address` should be used (truncated to `u32` on x86) instead of
  19. /// `rsdt_address`.
  20. #[derive(Clone, Copy, Debug)]
  21. #[repr(C, packed)]
  22. pub struct Rsdp {
  23. signature: [u8; 8],
  24. checksum: u8,
  25. oem_id: [u8; 6],
  26. revision: u8,
  27. rsdt_address: u32,
  28. /*
  29. * These fields are only valid for ACPI Version 2.0 and greater
  30. */
  31. length: u32,
  32. xsdt_address: u64,
  33. ext_checksum: u8,
  34. reserved: [u8; 3],
  35. }
  36. impl Rsdp {
  37. /// This searches for a RSDP on BIOS systems.
  38. ///
  39. /// ### Safety
  40. /// This function probes memory in three locations:
  41. /// - It reads a word from `40:0e` to locate the EBDA.
  42. /// - The first 1KiB of the EBDA (Extended BIOS Data Area).
  43. /// - The BIOS memory area at `0xe0000..=0xfffff`.
  44. ///
  45. /// This should be fine on all BIOS systems. However, UEFI platforms are free to put the RSDP wherever they
  46. /// please, so this won't always find the RSDP. Further, prodding these memory locations may have unintended
  47. /// side-effects. On UEFI systems, the RSDP should be found in the Configuration Table, using two GUIDs:
  48. /// - ACPI v1.0 structures use `eb9d2d30-2d88-11d3-9a16-0090273fc14d`.
  49. /// - ACPI v2.0 or later structures use `8868e871-e4f1-11d3-bc22-0080c73c8881`.
  50. /// You should search the entire table for the v2.0 GUID before searching for the v1.0 one.
  51. pub unsafe fn search_for_on_bios<H>(handler: H) -> AcpiResult<PhysicalMapping<H, Rsdp>>
  52. where
  53. H: AcpiHandler,
  54. {
  55. let rsdp_address = find_search_areas(handler.clone()).iter().find_map(|area| {
  56. // Map the search area for the RSDP followed by `RSDP_V2_EXT_LENGTH` bytes so an ACPI 1.0 RSDP at the
  57. // end of the area can be read as an `Rsdp` (which always has the size of an ACPI 2.0 RSDP)
  58. let mapping = unsafe {
  59. handler.map_physical_region::<u8>(area.start, area.end - area.start + RSDP_V2_EXT_LENGTH)
  60. };
  61. let extended_area_bytes =
  62. unsafe { slice::from_raw_parts(mapping.virtual_start().as_ptr(), mapping.region_length()) };
  63. // Search `Rsdp`-sized windows at 16-byte boundaries relative to the base of the area (which is also
  64. // aligned to 16 bytes due to the implementation of `find_search_areas`)
  65. extended_area_bytes.windows(mem::size_of::<Rsdp>()).step_by(16).find_map(|maybe_rsdp_bytes_slice| {
  66. let maybe_rsdp_virt_ptr = maybe_rsdp_bytes_slice.as_ptr().cast::<Rsdp>();
  67. let maybe_rsdp_phys_start = maybe_rsdp_virt_ptr as usize
  68. - mapping.virtual_start().as_ptr() as usize
  69. + mapping.physical_start();
  70. // SAFETY: `maybe_rsdp_virt_ptr` points to an aligned, readable `Rsdp`-sized value, and the `Rsdp`
  71. // struct's fields are always initialized.
  72. let maybe_rsdp = unsafe { &*maybe_rsdp_virt_ptr };
  73. match maybe_rsdp.validate() {
  74. Ok(()) => Some(maybe_rsdp_phys_start),
  75. Err(AcpiError::RsdpIncorrectSignature) => None,
  76. Err(err) => {
  77. log::warn!("Invalid RSDP found at {:#x}: {:?}", maybe_rsdp_phys_start, err);
  78. None
  79. }
  80. }
  81. })
  82. });
  83. match rsdp_address {
  84. Some(address) => {
  85. let rsdp_mapping = unsafe { handler.map_physical_region::<Rsdp>(address, mem::size_of::<Rsdp>()) };
  86. Ok(rsdp_mapping)
  87. }
  88. None => Err(AcpiError::NoValidRsdp),
  89. }
  90. }
  91. /// Checks that:
  92. /// 1) The signature is correct
  93. /// 2) The checksum is correct
  94. /// 3) For Version 2.0+, that the extension checksum is correct
  95. pub fn validate(&self) -> AcpiResult<()> {
  96. // Check the signature
  97. if self.signature != RSDP_SIGNATURE {
  98. return Err(AcpiError::RsdpIncorrectSignature);
  99. }
  100. // Check the OEM id is valid UTF8 (allows use of unwrap)
  101. if str::from_utf8(&self.oem_id).is_err() {
  102. return Err(AcpiError::RsdpInvalidOemId);
  103. }
  104. /*
  105. * `self.length` doesn't exist on ACPI version 1.0, so we mustn't rely on it. Instead,
  106. * check for version 1.0 and use a hard-coded length instead.
  107. */
  108. let length = if self.revision > 0 {
  109. // For Version 2.0+, include the number of bytes specified by `length`
  110. self.length as usize
  111. } else {
  112. RSDP_V1_LENGTH
  113. };
  114. let bytes = unsafe { slice::from_raw_parts(self as *const Rsdp as *const u8, length) };
  115. let sum = bytes.iter().fold(0u8, |sum, &byte| sum.wrapping_add(byte));
  116. if sum != 0 {
  117. return Err(AcpiError::RsdpInvalidChecksum);
  118. }
  119. Ok(())
  120. }
  121. pub fn signature(&self) -> [u8; 8] {
  122. self.signature
  123. }
  124. pub fn checksum(&self) -> u8 {
  125. self.checksum
  126. }
  127. pub fn oem_id(&self) -> &str {
  128. str::from_utf8(&self.oem_id).unwrap()
  129. }
  130. pub fn revision(&self) -> u8 {
  131. self.revision
  132. }
  133. pub fn rsdt_address(&self) -> u32 {
  134. self.rsdt_address
  135. }
  136. pub fn length(&self) -> u32 {
  137. assert!(self.revision > 0, "Tried to read extended RSDP field with ACPI Version 1.0");
  138. self.length
  139. }
  140. pub fn xsdt_address(&self) -> u64 {
  141. assert!(self.revision > 0, "Tried to read extended RSDP field with ACPI Version 1.0");
  142. self.xsdt_address
  143. }
  144. pub fn ext_checksum(&self) -> u8 {
  145. assert!(self.revision > 0, "Tried to read extended RSDP field with ACPI Version 1.0");
  146. self.ext_checksum
  147. }
  148. }
  149. /// Find the areas we should search for the RSDP in.
  150. pub fn find_search_areas<H>(handler: H) -> [Range<usize>; 2]
  151. where
  152. H: AcpiHandler,
  153. {
  154. /*
  155. * Read the base address of the EBDA from its location in the BDA (BIOS Data Area). Not all BIOSs fill this out
  156. * unfortunately, so we might not get a sensible result. We shift it left 4, as it's a segment address.
  157. */
  158. let ebda_start_mapping =
  159. unsafe { handler.map_physical_region::<u16>(EBDA_START_SEGMENT_PTR, mem::size_of::<u16>()) };
  160. let ebda_start = (*ebda_start_mapping as usize) << 4;
  161. [
  162. /*
  163. * The main BIOS area below 1MiB. In practice, from my [Restioson's] testing, the RSDP is more often here
  164. * than the EBDA. We also don't want to search the entire possibele EBDA range, if we've failed to find it
  165. * from the BDA.
  166. */
  167. RSDP_BIOS_AREA_START..(RSDP_BIOS_AREA_END + 1),
  168. // Check if base segment ptr is in valid range for EBDA base
  169. if (EBDA_EARLIEST_START..EBDA_END).contains(&ebda_start) {
  170. // First KiB of EBDA
  171. ebda_start..ebda_start + 1024
  172. } else {
  173. // We don't know where the EBDA starts, so just search the largest possible EBDA
  174. EBDA_EARLIEST_START..(EBDA_END + 1)
  175. },
  176. ]
  177. }
  178. /// This (usually!) contains the base address of the EBDA (Extended Bios Data Area), shifted right by 4
  179. const EBDA_START_SEGMENT_PTR: usize = 0x40e;
  180. /// The earliest (lowest) memory address an EBDA (Extended Bios Data Area) can start
  181. const EBDA_EARLIEST_START: usize = 0x80000;
  182. /// The end of the EBDA (Extended Bios Data Area)
  183. const EBDA_END: usize = 0x9ffff;
  184. /// The start of the main BIOS area below 1MiB in which to search for the RSDP (Root System Description Pointer)
  185. const RSDP_BIOS_AREA_START: usize = 0xe0000;
  186. /// The end of the main BIOS area below 1MiB in which to search for the RSDP (Root System Description Pointer)
  187. const RSDP_BIOS_AREA_END: usize = 0xfffff;
  188. /// The RSDP (Root System Description Pointer)'s signature, "RSD PTR " (note trailing space)
  189. const RSDP_SIGNATURE: [u8; 8] = *b"RSD PTR ";