2
0

lib.rs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #![no_std]
  2. #![feature(nll)]
  3. #![feature(alloc)]
  4. #[cfg(test)]
  5. #[macro_use]
  6. extern crate std;
  7. #[macro_use]
  8. extern crate log;
  9. extern crate alloc;
  10. extern crate bit_field;
  11. mod aml;
  12. mod fadt;
  13. mod hpet;
  14. mod rsdp;
  15. mod sdt;
  16. use alloc::{BTreeMap, String};
  17. use aml::{AmlError, AmlValue};
  18. use core::mem;
  19. use core::ops::Deref;
  20. use core::ptr::NonNull;
  21. use rsdp::Rsdp;
  22. use sdt::SdtHeader;
  23. #[derive(Debug)]
  24. // TODO: manually implement Debug to print signatures correctly etc.
  25. pub enum AcpiError {
  26. RsdpIncorrectSignature,
  27. RsdpInvalidOemId,
  28. RsdpInvalidChecksum,
  29. SdtInvalidSignature([u8; 4]),
  30. SdtInvalidOemId([u8; 4]),
  31. SdtInvalidTableId([u8; 4]),
  32. SdtInvalidChecksum([u8; 4]),
  33. InvalidAmlTable([u8; 4], AmlError),
  34. }
  35. #[repr(C, packed)]
  36. pub struct GenericAddress {
  37. address_space: u8,
  38. bit_width: u8,
  39. bit_offset: u8,
  40. access_size: u8,
  41. address: u64,
  42. }
  43. /// Describes a physical mapping created by `AcpiHandler::map_physical_region` and unmapped by
  44. /// `AcpiHandler::unmap_physical_region`. The region mapped must be at least `size_of::<T>()`
  45. /// bytes, but may be bigger.
  46. pub struct PhysicalMapping<T> {
  47. pub physical_start: usize,
  48. pub virtual_start: NonNull<T>,
  49. pub region_length: usize, // Can be equal or larger than size_of::<T>()
  50. pub mapped_length: usize, // Differs from `region_length` if padding is added for alignment
  51. }
  52. impl<T> Deref for PhysicalMapping<T> {
  53. type Target = T;
  54. fn deref(&self) -> &T {
  55. unsafe { self.virtual_start.as_ref() }
  56. }
  57. }
  58. /// The kernel must provide an implementation of this trait for `acpi` to interface with. It has
  59. /// utility methods `acpi` uses to for e.g. mapping physical memory, but also an interface for
  60. /// `acpi` to tell the kernel about the tables it's parsing, such as how the kernel should
  61. /// configure the APIC or PCI routing.
  62. pub trait AcpiHandler {
  63. /// Given a starting physical address and a size, map a region of physical memory that contains
  64. /// a `T` (but may be bigger than `size_of::<T>()`). The address doesn't have to be page-aligned,
  65. /// so the implementation may have to add padding to either end. The given size must be greater
  66. /// or equal to the size of a `T`. The virtual address the memory is mapped to does not matter,
  67. /// as long as it is accessibly by `acpi`.
  68. fn map_physical_region<T>(
  69. &mut self,
  70. physical_address: usize,
  71. size: usize,
  72. ) -> PhysicalMapping<T>;
  73. /// Unmap the given physical mapping. Safe because we consume the mapping, and so it can't be
  74. /// used after being passed to this function.
  75. fn unmap_physical_region<T>(&mut self, region: PhysicalMapping<T>);
  76. }
  77. /// This struct manages the internal state of `acpi`. It is not visible to the user of the library.
  78. pub(crate) struct Acpi<'a, H>
  79. where
  80. H: AcpiHandler + 'a,
  81. {
  82. handler: &'a mut H,
  83. acpi_revision: u8,
  84. namespace: BTreeMap<String, AmlValue>,
  85. }
  86. /// This is the entry point of `acpi` if you have the **physical** address of the RSDP. It maps
  87. /// the RSDP, works out what version of ACPI the hardware supports, and passes the physical
  88. /// address of the RSDT/XSDT to `parse_rsdt`.
  89. pub fn parse_rsdp<H>(handler: &mut H, rsdp_address: usize) -> Result<(), AcpiError>
  90. where
  91. H: AcpiHandler,
  92. {
  93. let rsdp_mapping = handler.map_physical_region::<Rsdp>(rsdp_address, mem::size_of::<Rsdp>());
  94. (*rsdp_mapping).validate()?;
  95. let revision = (*rsdp_mapping).revision();
  96. if revision == 0 {
  97. /*
  98. * We're running on ACPI Version 1.0. We should use the 32-bit RSDT address.
  99. */
  100. let rsdt_address = (*rsdp_mapping).rsdt_address();
  101. handler.unmap_physical_region(rsdp_mapping);
  102. parse_rsdt(handler, revision, rsdt_address as usize)?;
  103. } else {
  104. /*
  105. * We're running on ACPI Version 2.0+. We should use the 64-bit XSDT address, truncated
  106. * to 32 bits on x86.
  107. */
  108. let xsdt_address = (*rsdp_mapping).xsdt_address();
  109. handler.unmap_physical_region(rsdp_mapping);
  110. parse_rsdt(handler, revision, xsdt_address as usize)?;
  111. }
  112. Ok(())
  113. }
  114. /// This is the entry point of `acpi` if you already have the **physical** address of the
  115. /// RSDT/XSDT; it parses all the SDTs in the RSDT/XSDT, calling the relevant handlers in the
  116. /// implementation's `AcpiHandler`.
  117. ///
  118. /// If the given revision is 0, an address to the RSDT is expected. Otherwise, an address to
  119. /// the XSDT is expected.
  120. pub fn parse_rsdt<H>(
  121. handler: &mut H,
  122. revision: u8,
  123. physical_address: usize,
  124. ) -> Result<(), AcpiError>
  125. where
  126. H: AcpiHandler,
  127. {
  128. let mut acpi = Acpi {
  129. handler,
  130. acpi_revision: revision,
  131. namespace: BTreeMap::new(),
  132. };
  133. let header = sdt::peek_at_sdt_header(acpi.handler, physical_address);
  134. let mapping = acpi
  135. .handler
  136. .map_physical_region::<SdtHeader>(physical_address, header.length() as usize);
  137. if revision == 0 {
  138. /*
  139. * ACPI Version 1.0. It's a RSDT!
  140. */
  141. (*mapping).validate(b"RSDT")?;
  142. let num_tables =
  143. ((*mapping).length() as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u32>();
  144. let tables_base =
  145. ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u32;
  146. for i in 0..num_tables {
  147. sdt::dispatch_sdt(&mut acpi, unsafe { *tables_base.offset(i as isize) }
  148. as usize)?;
  149. }
  150. } else {
  151. /*
  152. * ACPI Version 2.0+. It's a XSDT!
  153. */
  154. (*mapping).validate(b"XSDT")?;
  155. let num_tables =
  156. ((*mapping).length() as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u64>();
  157. let tables_base =
  158. ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u64;
  159. for i in 0..num_tables {
  160. sdt::dispatch_sdt(&mut acpi, unsafe { *tables_base.offset(i as isize) }
  161. as usize)?;
  162. }
  163. }
  164. acpi.handler.unmap_physical_region(mapping);
  165. Ok(())
  166. }
  167. #[cfg(test)]
  168. mod tests {
  169. use GenericAddress;
  170. impl GenericAddress {
  171. pub(crate) fn make_testcase() -> GenericAddress {
  172. GenericAddress {
  173. address_space: 0 as u8,
  174. bit_width: 0 as u8,
  175. bit_offset: 0 as u8,
  176. access_size: 0 as u8,
  177. address: 0 as u64,
  178. }
  179. }
  180. }
  181. }