lib.rs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #![no_std]
  2. #![feature(nll)]
  3. #![feature(alloc)]
  4. #![feature(exclusive_range_pattern, range_contains)]
  5. #![feature(exhaustive_integer_patterns)]
  6. #[cfg_attr(test, macro_use)]
  7. #[cfg(test)]
  8. extern crate std;
  9. #[macro_use]
  10. extern crate log;
  11. extern crate alloc;
  12. extern crate bit_field;
  13. mod aml;
  14. mod fadt;
  15. mod hpet;
  16. pub mod interrupt;
  17. mod madt;
  18. mod rsdp;
  19. mod rsdp_search;
  20. mod sdt;
  21. pub use crate::aml::AmlError;
  22. pub use crate::madt::MadtError;
  23. pub use crate::rsdp_search::search_for_rsdp_bios;
  24. use crate::aml::AmlValue;
  25. use crate::interrupt::InterruptModel;
  26. use crate::rsdp::Rsdp;
  27. use crate::sdt::SdtHeader;
  28. use alloc::{collections::BTreeMap, string::String, vec::Vec};
  29. use core::mem;
  30. use core::ops::Deref;
  31. use core::ptr::NonNull;
  32. #[derive(Debug)]
  33. // TODO: manually implement Debug to print signatures correctly etc.
  34. pub enum AcpiError {
  35. RsdpIncorrectSignature,
  36. RsdpInvalidOemId,
  37. RsdpInvalidChecksum,
  38. NoValidRsdp,
  39. SdtInvalidSignature([u8; 4]),
  40. SdtInvalidOemId([u8; 4]),
  41. SdtInvalidTableId([u8; 4]),
  42. SdtInvalidChecksum([u8; 4]),
  43. InvalidAmlTable([u8; 4], AmlError),
  44. InvalidMadt(MadtError),
  45. }
  46. #[repr(C, packed)]
  47. pub(crate) struct GenericAddress {
  48. address_space: u8,
  49. bit_width: u8,
  50. bit_offset: u8,
  51. access_size: u8,
  52. address: u64,
  53. }
  54. #[derive(Clone, Copy, Debug)]
  55. pub enum ProcessorState {
  56. /// A processor in this state is unusable, and you must not attempt to bring it up.
  57. Disabled,
  58. /// A processor waiting for a SIPI (Startup Inter-processor Interrupt) is currently not active,
  59. /// but may be brought up.
  60. WaitingForSipi,
  61. /// A Running processor is currently brought up and running code.
  62. Running,
  63. }
  64. #[derive(Clone, Copy, Debug)]
  65. pub struct Processor {
  66. pub processor_uid: u8,
  67. pub local_apic_id: u8,
  68. /// The state of this processor. Always check that the processor is not `Disabled` before
  69. /// attempting to bring it up!
  70. pub state: ProcessorState,
  71. /// Whether this processor is the Bootstrap Processor (BSP), or an Application Processor (AP).
  72. /// When the bootloader is entered, the BSP is the only processor running code. To run code on
  73. /// more than one processor, you need to "bring up" the APs.
  74. pub is_ap: bool,
  75. }
  76. impl Processor {
  77. pub(crate) fn new(
  78. processor_uid: u8,
  79. local_apic_id: u8,
  80. state: ProcessorState,
  81. is_ap: bool,
  82. ) -> Processor {
  83. Processor {
  84. processor_uid,
  85. local_apic_id,
  86. state,
  87. is_ap,
  88. }
  89. }
  90. }
  91. /// Describes a physical mapping created by `AcpiHandler::map_physical_region` and unmapped by
  92. /// `AcpiHandler::unmap_physical_region`. The region mapped must be at least `size_of::<T>()`
  93. /// bytes, but may be bigger.
  94. pub struct PhysicalMapping<T> {
  95. pub physical_start: usize,
  96. pub virtual_start: NonNull<T>,
  97. pub region_length: usize, // Can be equal or larger than size_of::<T>()
  98. pub mapped_length: usize, // Differs from `region_length` if padding is added for alignment
  99. }
  100. impl<T> Deref for PhysicalMapping<T> {
  101. type Target = T;
  102. fn deref(&self) -> &T {
  103. unsafe { self.virtual_start.as_ref() }
  104. }
  105. }
  106. /// An implementation of this trait must be provided to allow `acpi` to access platform-specific
  107. /// functionality, such as mapping regions of physical memory. You are free to implement these
  108. /// however you please, as long as they conform to the documentation of each function.
  109. pub trait AcpiHandler {
  110. /// Given a starting physical address and a size, map a region of physical memory that contains
  111. /// a `T` (but may be bigger than `size_of::<T>()`). The address doesn't have to be page-aligned,
  112. /// so the implementation may have to add padding to either end. The given size must be greater
  113. /// or equal to the size of a `T`. The virtual address the memory is mapped to does not matter,
  114. /// as long as it is accessible from `acpi`.
  115. fn map_physical_region<T>(
  116. &mut self,
  117. physical_address: usize,
  118. size: usize,
  119. ) -> PhysicalMapping<T>;
  120. /// Unmap the given physical mapping. Safe because we consume the mapping, and so it can't be
  121. /// used after being passed to this function.
  122. fn unmap_physical_region<T>(&mut self, region: PhysicalMapping<T>);
  123. }
  124. #[derive(Debug)]
  125. pub struct Acpi {
  126. acpi_revision: u8,
  127. namespace: BTreeMap<String, AmlValue>,
  128. boot_processor: Option<Processor>,
  129. application_processors: Vec<Processor>,
  130. /// ACPI theoretically allows for more than one interrupt model to be supported by the same
  131. /// hardware. For simplicity and because hardware practically will only support one model, we
  132. /// just error in cases that the tables detail more than one.
  133. interrupt_model: Option<InterruptModel>,
  134. }
  135. impl Acpi {
  136. /// A description of the boot processor. Until you bring any more up, this is the only processor
  137. /// running code, even on SMP systems.
  138. pub fn boot_processor<'a>(&'a self) -> &'a Option<Processor> {
  139. &self.boot_processor
  140. }
  141. /// Descriptions of each of the application processors. These are not brought up until you do
  142. /// so. The application processors must be brought up in the order that they appear in this
  143. /// list.
  144. pub fn application_processors<'a>(&'a self) -> &'a Vec<Processor> {
  145. &self.application_processors
  146. }
  147. /// The interrupt model supported by this system.
  148. pub fn interrupt_model<'a>(&'a self) -> &'a Option<InterruptModel> {
  149. &self.interrupt_model
  150. }
  151. }
  152. /// This is the entry point of `acpi` if you have the **physical** address of the RSDP. It maps
  153. /// the RSDP, works out what version of ACPI the hardware supports, and passes the physical
  154. /// address of the RSDT/XSDT to `parse_rsdt`.
  155. pub fn parse_rsdp<H>(handler: &mut H, rsdp_address: usize) -> Result<Acpi, AcpiError>
  156. where
  157. H: AcpiHandler,
  158. {
  159. let rsdp_mapping = handler.map_physical_region::<Rsdp>(rsdp_address, mem::size_of::<Rsdp>());
  160. (*rsdp_mapping).validate()?;
  161. parse_validated_rsdp(handler, rsdp_mapping)
  162. }
  163. fn parse_validated_rsdp<H>(
  164. handler: &mut H,
  165. rsdp_mapping: PhysicalMapping<Rsdp>,
  166. ) -> Result<Acpi, AcpiError>
  167. where
  168. H: AcpiHandler,
  169. {
  170. let revision = (*rsdp_mapping).revision();
  171. if revision == 0 {
  172. /*
  173. * We're running on ACPI Version 1.0. We should use the 32-bit RSDT address.
  174. */
  175. let rsdt_address = (*rsdp_mapping).rsdt_address();
  176. handler.unmap_physical_region(rsdp_mapping);
  177. parse_rsdt(handler, revision, rsdt_address as usize)
  178. } else {
  179. /*
  180. * We're running on ACPI Version 2.0+. We should use the 64-bit XSDT address, truncated
  181. * to 32 bits on x86.
  182. */
  183. let xsdt_address = (*rsdp_mapping).xsdt_address();
  184. handler.unmap_physical_region(rsdp_mapping);
  185. parse_rsdt(handler, revision, xsdt_address as usize)
  186. }
  187. }
  188. /// This is the entry point of `acpi` if you already have the **physical** address of the
  189. /// RSDT/XSDT; it parses all the SDTs in the RSDT/XSDT, calling the relevant handlers in the
  190. /// implementation's `AcpiHandler`.
  191. ///
  192. /// If the given revision is 0, an address to the RSDT is expected. Otherwise, an address to
  193. /// the XSDT is expected.
  194. pub fn parse_rsdt<H>(
  195. handler: &mut H,
  196. revision: u8,
  197. physical_address: usize,
  198. ) -> Result<Acpi, AcpiError>
  199. where
  200. H: AcpiHandler,
  201. {
  202. let mut acpi = Acpi {
  203. acpi_revision: revision,
  204. namespace: BTreeMap::new(),
  205. boot_processor: None,
  206. application_processors: Vec::new(),
  207. interrupt_model: None,
  208. };
  209. let header = sdt::peek_at_sdt_header(handler, physical_address);
  210. let mapping =
  211. handler.map_physical_region::<SdtHeader>(physical_address, header.length() as usize);
  212. if revision == 0 {
  213. /*
  214. * ACPI Version 1.0. It's a RSDT!
  215. */
  216. (*mapping).validate(b"RSDT")?;
  217. let num_tables =
  218. ((*mapping).length() as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u32>();
  219. let tables_base =
  220. ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u32;
  221. for i in 0..num_tables {
  222. sdt::dispatch_sdt(
  223. &mut acpi,
  224. handler,
  225. unsafe { *tables_base.offset(i as isize) } as usize,
  226. )?;
  227. }
  228. } else {
  229. /*
  230. * ACPI Version 2.0+. It's a XSDT!
  231. */
  232. (*mapping).validate(b"XSDT")?;
  233. let num_tables =
  234. ((*mapping).length() as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u64>();
  235. let tables_base =
  236. ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u64;
  237. for i in 0..num_tables {
  238. sdt::dispatch_sdt(
  239. &mut acpi,
  240. handler,
  241. unsafe { *tables_base.offset(i as isize) } as usize,
  242. )?;
  243. }
  244. }
  245. info!("Parsed namespace: {:#?}", acpi.namespace);
  246. handler.unmap_physical_region(mapping);
  247. Ok(acpi)
  248. }