lib.rs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. //! A library for parsing ACPI tables. This crate can be used by bootloaders and kernels for
  2. //! architectures that support ACPI. The crate is far from feature-complete, but can still be used
  3. //! for finding and parsing the static tables, which is enough to set up hardware such as the APIC
  4. //! and HPET on x86_64.
  5. //!
  6. //! The crate is designed for use in conjunction with the `aml_parser` crate, which is the (much
  7. //! less complete) AML parser used to parse the DSDT and SSDTs. These crates are separate because
  8. //! some kernels may want to detect the static tables, but delay AML parsing to a later stage.
  9. //!
  10. //! ### Usage
  11. //! To use the library, you will need to provide an implementation of the `AcpiHandler` trait,
  12. //! which allows the library to make requests such as mapping a particular region of physical
  13. //! memory into the virtual address space.
  14. //!
  15. //! You should then call one of the entry points, based on how much information you have:
  16. //! * Call `parse_rsdp` if you have the physical address of the RSDP
  17. //! * Call `parse_rsdt` if you have the physical address of the RSDT / XSDT
  18. //! * Call `search_for_rsdp_bios` if you don't have the address of either structure, but **you
  19. //! know you're running on BIOS, not UEFI**
  20. //!
  21. //! All of these methods return an instance of `Acpi`. This struct contains all the information
  22. //! gathered from the static tables, and can be queried to set up hardware etc.
  23. #![no_std]
  24. #![feature(nll)]
  25. #![feature(alloc)]
  26. #![feature(exclusive_range_pattern)]
  27. #[cfg_attr(test, macro_use)]
  28. #[cfg(test)]
  29. extern crate std;
  30. #[macro_use]
  31. extern crate log;
  32. extern crate alloc;
  33. extern crate bit_field;
  34. mod fadt;
  35. pub mod handler;
  36. mod hpet;
  37. pub mod interrupt;
  38. mod madt;
  39. mod rsdp;
  40. mod rsdp_search;
  41. mod sdt;
  42. pub use crate::{
  43. handler::{AcpiHandler, PhysicalMapping},
  44. madt::MadtError,
  45. rsdp_search::search_for_rsdp_bios,
  46. };
  47. use crate::{hpet::HpetInfo, interrupt::InterruptModel, rsdp::Rsdp, sdt::SdtHeader};
  48. use alloc::vec::Vec;
  49. use core::mem;
  50. #[derive(Debug)]
  51. // TODO: manually implement Debug to print signatures correctly etc.
  52. pub enum AcpiError {
  53. RsdpIncorrectSignature,
  54. RsdpInvalidOemId,
  55. RsdpInvalidChecksum,
  56. NoValidRsdp,
  57. SdtInvalidSignature([u8; 4]),
  58. SdtInvalidOemId([u8; 4]),
  59. SdtInvalidTableId([u8; 4]),
  60. SdtInvalidChecksum([u8; 4]),
  61. InvalidMadt(MadtError),
  62. }
  63. #[derive(Clone, Copy, Debug)]
  64. #[repr(C, packed)]
  65. pub(crate) struct GenericAddress {
  66. address_space: u8,
  67. bit_width: u8,
  68. bit_offset: u8,
  69. access_size: u8,
  70. address: u64,
  71. }
  72. #[derive(Clone, Copy, Debug, PartialEq, Eq)]
  73. pub enum ProcessorState {
  74. /// A processor in this state is unusable, and you must not attempt to bring it up.
  75. Disabled,
  76. /// A processor waiting for a SIPI (Startup Inter-processor Interrupt) is currently not active,
  77. /// but may be brought up.
  78. WaitingForSipi,
  79. /// A Running processor is currently brought up and running code.
  80. Running,
  81. }
  82. #[derive(Clone, Copy, Debug, PartialEq, Eq)]
  83. pub struct Processor {
  84. pub processor_uid: u8,
  85. pub local_apic_id: u8,
  86. /// The state of this processor. Always check that the processor is not `Disabled` before
  87. /// attempting to bring it up!
  88. pub state: ProcessorState,
  89. /// Whether this processor is the Bootstrap Processor (BSP), or an Application Processor (AP).
  90. /// When the bootloader is entered, the BSP is the only processor running code. To run code on
  91. /// more than one processor, you need to "bring up" the APs.
  92. pub is_ap: bool,
  93. }
  94. impl Processor {
  95. pub(crate) fn new(
  96. processor_uid: u8,
  97. local_apic_id: u8,
  98. state: ProcessorState,
  99. is_ap: bool,
  100. ) -> Processor {
  101. Processor { processor_uid, local_apic_id, state, is_ap }
  102. }
  103. }
  104. #[derive(Debug)]
  105. pub struct Acpi {
  106. acpi_revision: u8,
  107. boot_processor: Option<Processor>,
  108. application_processors: Vec<Processor>,
  109. /// ACPI theoretically allows for more than one interrupt model to be supported by the same
  110. /// hardware. For simplicity and because hardware practically will only support one model, we
  111. /// just error in cases that the tables detail more than one.
  112. interrupt_model: Option<InterruptModel>,
  113. hpet: Option<HpetInfo>,
  114. /// The physical address of the DSDT, if we manage to find it.
  115. dsdt_address: Option<usize>,
  116. /// The physical addresses of the SSDTs, if there are any,
  117. ssdt_addresses: Vec<usize>,
  118. }
  119. impl Acpi {
  120. /// A description of the boot processor. Until you bring any more up, this is the only processor
  121. /// running code, even on SMP systems.
  122. pub fn boot_processor<'a>(&'a self) -> &'a Option<Processor> {
  123. &self.boot_processor
  124. }
  125. /// Descriptions of each of the application processors. These are not brought up until you do
  126. /// so. The application processors must be brought up in the order that they appear in this
  127. /// list.
  128. pub fn application_processors<'a>(&'a self) -> &'a Vec<Processor> {
  129. &self.application_processors
  130. }
  131. /// The interrupt model supported by this system.
  132. pub fn interrupt_model<'a>(&'a self) -> &'a Option<InterruptModel> {
  133. &self.interrupt_model
  134. }
  135. }
  136. /// This is the entry point of `acpi` if you have the **physical** address of the RSDP. It maps
  137. /// the RSDP, works out what version of ACPI the hardware supports, and passes the physical
  138. /// address of the RSDT/XSDT to `parse_rsdt`.
  139. pub fn parse_rsdp<H>(handler: &mut H, rsdp_address: usize) -> Result<Acpi, AcpiError>
  140. where
  141. H: AcpiHandler,
  142. {
  143. let rsdp_mapping = handler.map_physical_region::<Rsdp>(rsdp_address, mem::size_of::<Rsdp>());
  144. (*rsdp_mapping).validate()?;
  145. parse_validated_rsdp(handler, rsdp_mapping)
  146. }
  147. fn parse_validated_rsdp<H>(
  148. handler: &mut H,
  149. rsdp_mapping: PhysicalMapping<Rsdp>,
  150. ) -> Result<Acpi, AcpiError>
  151. where
  152. H: AcpiHandler,
  153. {
  154. let revision = (*rsdp_mapping).revision();
  155. if revision == 0 {
  156. /*
  157. * We're running on ACPI Version 1.0. We should use the 32-bit RSDT address.
  158. */
  159. let rsdt_address = (*rsdp_mapping).rsdt_address();
  160. handler.unmap_physical_region(rsdp_mapping);
  161. parse_rsdt(handler, revision, rsdt_address as usize)
  162. } else {
  163. /*
  164. * We're running on ACPI Version 2.0+. We should use the 64-bit XSDT address, truncated
  165. * to 32 bits on x86.
  166. */
  167. let xsdt_address = (*rsdp_mapping).xsdt_address();
  168. handler.unmap_physical_region(rsdp_mapping);
  169. parse_rsdt(handler, revision, xsdt_address as usize)
  170. }
  171. }
  172. /// This is the entry point of `acpi` if you already have the **physical** address of the
  173. /// RSDT/XSDT; it parses all the SDTs in the RSDT/XSDT, calling the relevant handlers in the
  174. /// implementation's `AcpiHandler`.
  175. ///
  176. /// If the given revision is 0, an address to the RSDT is expected. Otherwise, an address to
  177. /// the XSDT is expected.
  178. pub fn parse_rsdt<H>(
  179. handler: &mut H,
  180. revision: u8,
  181. physical_address: usize,
  182. ) -> Result<Acpi, AcpiError>
  183. where
  184. H: AcpiHandler,
  185. {
  186. let mut acpi = Acpi {
  187. acpi_revision: revision,
  188. boot_processor: None,
  189. application_processors: Vec::new(),
  190. interrupt_model: None,
  191. hpet: None,
  192. dsdt_address: None,
  193. ssdt_addresses: Vec::with_capacity(0),
  194. };
  195. let header = sdt::peek_at_sdt_header(handler, physical_address);
  196. let mapping =
  197. handler.map_physical_region::<SdtHeader>(physical_address, header.length() as usize);
  198. if revision == 0 {
  199. /*
  200. * ACPI Version 1.0. It's a RSDT!
  201. */
  202. (*mapping).validate(b"RSDT")?;
  203. let num_tables =
  204. ((*mapping).length() as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u32>();
  205. let tables_base =
  206. ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u32;
  207. for i in 0..num_tables {
  208. sdt::dispatch_sdt(&mut acpi, handler, unsafe { *tables_base.offset(i as isize) }
  209. as usize)?;
  210. }
  211. } else {
  212. /*
  213. * ACPI Version 2.0+. It's a XSDT!
  214. */
  215. (*mapping).validate(b"XSDT")?;
  216. let num_tables =
  217. ((*mapping).length() as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u64>();
  218. let tables_base =
  219. ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u64;
  220. for i in 0..num_tables {
  221. sdt::dispatch_sdt(&mut acpi, handler, unsafe { *tables_base.offset(i as isize) }
  222. as usize)?;
  223. }
  224. }
  225. handler.unmap_physical_region(mapping);
  226. Ok(acpi)
  227. }