lib.rs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. #![no_std]
  2. #[cfg(test)]
  3. extern crate std;
  4. mod rsdp;
  5. mod sdt;
  6. use core::ops::Deref;
  7. use core::ptr::NonNull;
  8. use rsdp::Rsdp;
  9. #[derive(Debug)]
  10. pub enum AcpiError
  11. {
  12. RsdpIncorrectSignature,
  13. RsdpInvalidOemId,
  14. RsdpInvalidChecksum,
  15. }
  16. /// Describes a physical mapping created by `AcpiHandler::map_physical_region` and unmapped by
  17. /// `AcpiHandler::unmap_physical_region`. The region mapped must be at least `mem::size_of::<T>()`
  18. /// bytes, but may be bigger.
  19. pub struct PhysicalMapping<T>
  20. {
  21. pub physical_start : usize,
  22. pub virtual_start : NonNull<T>,
  23. pub mapped_length : usize, // Differs from `region_length` if padding is added to align to page boundaries
  24. }
  25. impl<T> Deref for PhysicalMapping<T>
  26. {
  27. type Target = T;
  28. fn deref(&self) -> &T
  29. {
  30. unsafe
  31. {
  32. self.virtual_start.as_ref()
  33. }
  34. }
  35. }
  36. /// The kernel must provide an implementation of this trait for `acpi` to interface with. It has
  37. /// utility methods `acpi` uses to for e.g. mapping physical memory, but also an interface for
  38. /// `acpi` to tell the kernel about the tables it's parsing, such as how the kernel should
  39. /// configure the APIC or PCI routing.
  40. pub trait AcpiHandler
  41. {
  42. /// Given a starting physical address, map a region of physical memory that contains a `T`
  43. /// somewhere in the virtual address space. The address doesn't have to be page-aligned, so
  44. /// the implementation may have to add padding to either end.
  45. fn map_physical_region<T>(&mut self, physical_address : usize) -> PhysicalMapping<T>;
  46. /// Unmap the given physical mapping. Safe because we consume the mapping, and so it can't be
  47. /// used after being passed to this function.
  48. fn unmap_physical_region<T>(&mut self, region : PhysicalMapping<T>);
  49. }
  50. /// This is the entry point of `acpi`. Given the **physical** address of the RSDP, it parses all
  51. /// the SDTs in the RSDT, calling the relevant handlers in the implementation's `AcpiHandler`.
  52. pub fn parse_acpi<T>(handler : &mut T, rsdp_address : usize) -> Result<(), AcpiError>
  53. where T : AcpiHandler
  54. {
  55. let rsdp_mapping = handler.map_physical_region::<Rsdp>(rsdp_address);
  56. (*rsdp_mapping).validate()?;
  57. // TODO: map the RSDT
  58. // TODO: parse the RSDT
  59. handler.unmap_physical_region(rsdp_mapping);
  60. Ok(())
  61. }
  62. /// This module tests against idealistic sets of ACPI tables, which we construct on the fly. This
  63. /// should cover all standard-compliant implementations eventually, but does not guarantee we can
  64. /// handle all hardware's tables, obviously.
  65. #[cfg(test)]
  66. mod constructed_table_tests
  67. {
  68. use std::mem;
  69. use std::ptr::NonNull;
  70. use std::boxed::Box;
  71. use {AcpiHandler, PhysicalMapping, parse_acpi, rsdp::Rsdp};
  72. const OEM_ID : &[u8; 6] = b"RUST ";
  73. /*
  74. * We use fake physical addresses to track what is being requested. When a particular table or
  75. * resource is requested, we just allocate it on the heap and return the "virtual address"
  76. * (a pointer onto the heap).
  77. */
  78. const RSDP_ADDRESS : usize = 0x0;
  79. const RSDT_ADDRESS : usize = 0x1;
  80. struct TestHandler { }
  81. impl AcpiHandler for TestHandler
  82. {
  83. fn map_physical_region<T>(&mut self, physical_address : usize) -> PhysicalMapping<T>
  84. {
  85. match physical_address
  86. {
  87. RSDP_ADDRESS =>
  88. {
  89. let rsdp = Rsdp::make_testcase(*b"RSD PTR ",
  90. None,
  91. *OEM_ID,
  92. 0,
  93. RSDT_ADDRESS as u32,
  94. 0,
  95. 0x0,
  96. None,
  97. [0, 0, 0]
  98. );
  99. PhysicalMapping
  100. {
  101. physical_start : RSDP_ADDRESS,
  102. virtual_start : unsafe
  103. {
  104. NonNull::<T>::new_unchecked(Box::into_raw(Box::new(rsdp)) as *mut T)
  105. },
  106. mapped_length : mem::size_of::<Rsdp>(),
  107. }
  108. },
  109. _ => panic!("ACPI requested invalid physical address: {:#x}", physical_address),
  110. }
  111. }
  112. fn unmap_physical_region<T>(&mut self, region : PhysicalMapping<T>)
  113. {
  114. match region.physical_start
  115. {
  116. RSDP_ADDRESS =>
  117. {
  118. let _ = unsafe { Box::from_raw(region.virtual_start.as_ptr()) };
  119. },
  120. address => panic!("ACPI tried to unmap a region not created by test harness: {:#x}", address),
  121. }
  122. }
  123. }
  124. #[test]
  125. fn test_constructed_tables()
  126. {
  127. let mut test_handler = TestHandler { };
  128. match parse_acpi(&mut test_handler, RSDP_ADDRESS)
  129. {
  130. Ok(_) => (),
  131. Err(err) =>
  132. {
  133. panic!("Failed to parse ACPI: {:#?}", err);
  134. },
  135. }
  136. }
  137. }