2
0

rsdp_search.rs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. use crate::{parse_validated_rsdp, rsdp::Rsdp, Acpi, AcpiError, AcpiHandler};
  2. use core::{mem, ops::RangeInclusive};
  3. use log::warn;
  4. /// The pointer to the EBDA (Extended Bios Data Area) start segment pointer
  5. const EBDA_START_SEGMENT_PTR: usize = 0x40e;
  6. /// The earliest (lowest) memory address an EBDA (Extended Bios Data Area) can start
  7. const EBDA_EARLIEST_START: usize = 0x80000;
  8. /// The end of the EBDA (Extended Bios Data Area)
  9. const EBDA_END: usize = 0x9ffff;
  10. /// The start of the main bios area below 1mb in which to search for the RSDP
  11. /// (Root System Description Pointer)
  12. const RSDP_BIOS_AREA_START: usize = 0xe0000;
  13. /// The end of the main bios area below 1mb in which to search for the RSDP
  14. /// (Root System Description Pointer)
  15. const RSDP_BIOS_AREA_END: usize = 0xfffff;
  16. /// The RSDP (Root System Description Pointer)'s signature, "RSD PTR " (note trailing space)
  17. const RSDP_SIGNATURE: &'static [u8; 8] = b"RSD PTR ";
  18. /// Find the begining of the EBDA (Extended Bios Data Area) and return `None` if the ptr at
  19. /// `0x40e` is invalid.
  20. pub fn find_search_areas<H>(handler: &mut H) -> [RangeInclusive<usize>; 2]
  21. where
  22. H: AcpiHandler,
  23. {
  24. // Read base segment from BIOS area. This is not always given by the bios, so it needs to be
  25. // checked. We left shift 4 because it is a segment ptr.
  26. let ebda_start_mapping =
  27. handler.map_physical_region::<u16>(EBDA_START_SEGMENT_PTR, mem::size_of::<u16>());
  28. let ebda_start = (*ebda_start_mapping as usize) << 4;
  29. handler.unmap_physical_region(ebda_start_mapping);
  30. [
  31. // Main bios area below 1 mb
  32. // In practice (from my [Restioson's] testing, at least), the RSDP is more often here than
  33. // the in EBDA. Also, if we cannot find the EBDA, then we don't want to search the largest
  34. // possible EBDA first.
  35. RSDP_BIOS_AREA_START..=RSDP_BIOS_AREA_END,
  36. // Check if base segment ptr is in valid range for EBDA base
  37. if (EBDA_EARLIEST_START..EBDA_END).contains(&ebda_start) {
  38. // First kb of EBDA
  39. ebda_start..=ebda_start + 1024
  40. } else {
  41. // We don't know where the EBDA starts, so just search the largest possible EBDA
  42. EBDA_EARLIEST_START..=EBDA_END
  43. },
  44. ]
  45. }
  46. /// This is the entry point of `acpi` if you have no information except that the machine is running
  47. /// BIOS and not UEFI. It maps the RSDP, works out what version of ACPI the hardware supports, and
  48. /// passes the physical address of the RSDT/XSDT to `parse_rsdt`.
  49. ///
  50. /// # Unsafety
  51. ///
  52. /// This function is unsafe because it may read from protected memory if the computer is using UEFI.
  53. /// Only use this function if you are sure the computer is using BIOS.
  54. pub unsafe fn search_for_rsdp_bios<H>(handler: &mut H) -> Result<Acpi, AcpiError>
  55. where
  56. H: AcpiHandler,
  57. {
  58. // The areas that will be searched for the RSDP
  59. let areas = find_search_areas(handler);
  60. // On x86 it is more efficient to map 4096 bytes at a time because of how paging works
  61. let mut area_mapping = handler.map_physical_region::<[[u8; 8]; 0x1000 / 8]>(
  62. areas[0].clone().next().unwrap() & !0xfff, // Get frame addr
  63. 0x1000,
  64. );
  65. // Signature is always on a 16 byte boundary so only search there
  66. for address in areas.iter().flat_map(|i| i.clone()).step_by(16) {
  67. let mut mapping_start = area_mapping.physical_start as usize;
  68. if !(mapping_start..mapping_start + 0x1000).contains(&address) {
  69. handler.unmap_physical_region(area_mapping);
  70. area_mapping = handler.map_physical_region::<[[u8; 8]; 0x1000 / 8]>(
  71. address & !0xfff, // Get frame addr
  72. 0x1000,
  73. );
  74. // Update if mapping remapped
  75. mapping_start = area_mapping.physical_start as usize;
  76. }
  77. let index = (address - mapping_start) / 8;
  78. let signature = (*area_mapping)[index];
  79. if signature != *RSDP_SIGNATURE {
  80. continue;
  81. }
  82. let rsdp_mapping = handler.map_physical_region::<Rsdp>(address, mem::size_of::<Rsdp>());
  83. if let Err(e) = (*rsdp_mapping).validate() {
  84. warn!("Invalid RSDP found at 0x{:x}: {:?}", address, e);
  85. continue;
  86. }
  87. handler.unmap_physical_region(area_mapping);
  88. return parse_validated_rsdp(handler, rsdp_mapping);
  89. }
  90. Err(AcpiError::NoValidRsdp)
  91. }