2
0

lib.rs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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` 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 know
  19. //! 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(const_generics, unsafe_block_in_unsafe_fn)]
  25. extern crate alloc;
  26. #[cfg_attr(test, macro_use)]
  27. #[cfg(test)]
  28. extern crate std;
  29. mod fadt;
  30. pub mod handler;
  31. mod hpet;
  32. pub mod interrupt;
  33. mod madt;
  34. mod mcfg;
  35. mod rsdp;
  36. mod rsdp_search;
  37. mod sdt;
  38. pub use crate::{
  39. fadt::PowerProfile,
  40. handler::{AcpiHandler, PhysicalMapping},
  41. hpet::HpetInfo,
  42. interrupt::InterruptModel,
  43. madt::MadtError,
  44. mcfg::PciConfigRegions,
  45. rsdp_search::search_for_rsdp_bios,
  46. };
  47. use crate::{
  48. rsdp::Rsdp,
  49. sdt::{SdtHeader, Signature},
  50. };
  51. use alloc::vec::Vec;
  52. use core::mem;
  53. #[derive(Debug)]
  54. pub enum AcpiError {
  55. RsdpIncorrectSignature,
  56. RsdpInvalidOemId,
  57. RsdpInvalidChecksum,
  58. NoValidRsdp,
  59. SdtInvalidSignature(Signature),
  60. SdtInvalidOemId(Signature),
  61. SdtInvalidTableId(Signature),
  62. SdtInvalidChecksum(Signature),
  63. InvalidMadt(MadtError),
  64. }
  65. #[derive(Clone, Copy, Debug)]
  66. #[repr(C, packed)]
  67. pub(crate) struct GenericAddress {
  68. address_space: u8,
  69. bit_width: u8,
  70. bit_offset: u8,
  71. access_size: u8,
  72. address: u64,
  73. }
  74. #[derive(Clone, Copy, Debug, PartialEq, Eq)]
  75. pub enum ProcessorState {
  76. /// A processor in this state is unusable, and you must not attempt to bring it up.
  77. Disabled,
  78. /// A processor waiting for a SIPI (Startup Inter-processor Interrupt) is currently not active,
  79. /// but may be brought up.
  80. WaitingForSipi,
  81. /// A Running processor is currently brought up and running code.
  82. Running,
  83. }
  84. #[derive(Clone, Copy, Debug, PartialEq, Eq)]
  85. pub struct Processor {
  86. pub processor_uid: u8,
  87. pub local_apic_id: u8,
  88. /// The state of this processor. Always check that the processor is not `Disabled` before
  89. /// attempting to bring it up!
  90. pub state: ProcessorState,
  91. /// Whether this processor is the Bootstrap Processor (BSP), or an Application Processor (AP).
  92. /// When the bootloader is entered, the BSP is the only processor running code. To run code on
  93. /// more than one processor, you need to "bring up" the APs.
  94. pub is_ap: bool,
  95. }
  96. #[derive(Debug)]
  97. pub struct AmlTable {
  98. /// Physical address of the start of the AML stream (excluding the table header).
  99. pub address: usize,
  100. /// Length (in bytes) of the AML stream.
  101. pub length: u32,
  102. }
  103. impl AmlTable {
  104. /// Create an `AmlTable` from the address and length of the table **including the SDT header**.
  105. pub(crate) fn new(address: usize, length: u32) -> AmlTable {
  106. AmlTable {
  107. address: address + mem::size_of::<SdtHeader>(),
  108. length: length - mem::size_of::<SdtHeader>() as u32,
  109. }
  110. }
  111. }
  112. #[derive(Debug)]
  113. pub struct Acpi {
  114. pub acpi_revision: u8,
  115. /// The boot processor. Until you bring up any APs, this is the only processor running code.
  116. pub boot_processor: Option<Processor>,
  117. /// Application processes. These are not brought up until you do so, and must be brought up in
  118. /// the order they appear in this list.
  119. pub application_processors: Vec<Processor>,
  120. /// ACPI theoretically allows for more than one interrupt model to be supported by the same
  121. /// hardware. For simplicity and because hardware practically will only support one model, we
  122. /// just error in cases that the tables detail more than one.
  123. pub interrupt_model: Option<InterruptModel>,
  124. pub hpet: Option<HpetInfo>,
  125. pub power_profile: PowerProfile,
  126. /// Info about the DSDT, if we find it.
  127. pub dsdt: Option<AmlTable>,
  128. /// Info about any SSDTs, if there are any.
  129. pub ssdts: Vec<AmlTable>,
  130. /// Info about the PCI-E configuration memory regions, collected from the MCFG.
  131. pub pci_config_regions: Option<PciConfigRegions>,
  132. }
  133. /// This is the entry point of `acpi` if you have the **physical** address of the RSDP. It maps
  134. /// the RSDP, works out what version of ACPI the hardware supports, and passes the physical
  135. /// address of the RSDT/XSDT to `parse_rsdt`.
  136. pub unsafe fn parse_rsdp<H>(handler: &mut H, rsdp_address: usize) -> Result<Acpi, AcpiError>
  137. where
  138. H: AcpiHandler,
  139. {
  140. let rsdp_mapping = unsafe { handler.map_physical_region::<Rsdp>(rsdp_address, mem::size_of::<Rsdp>()) };
  141. (*rsdp_mapping).validate()?;
  142. parse_validated_rsdp(handler, rsdp_mapping)
  143. }
  144. fn parse_validated_rsdp<H>(handler: &mut H, rsdp_mapping: PhysicalMapping<Rsdp>) -> Result<Acpi, AcpiError>
  145. where
  146. H: AcpiHandler,
  147. {
  148. let revision = (*rsdp_mapping).revision();
  149. if revision == 0 {
  150. /*
  151. * We're running on ACPI Version 1.0. We should use the 32-bit RSDT address.
  152. */
  153. let rsdt_address = (*rsdp_mapping).rsdt_address();
  154. handler.unmap_physical_region(rsdp_mapping);
  155. unsafe { parse_rsdt(handler, revision, rsdt_address as usize) }
  156. } else {
  157. /*
  158. * We're running on ACPI Version 2.0+. We should use the 64-bit XSDT address, truncated
  159. * to 32 bits on x86.
  160. */
  161. let xsdt_address = (*rsdp_mapping).xsdt_address();
  162. handler.unmap_physical_region(rsdp_mapping);
  163. unsafe { parse_rsdt(handler, revision, xsdt_address as usize) }
  164. }
  165. }
  166. /// This is the entry point of `acpi` if you already have the **physical** address of the
  167. /// RSDT/XSDT; it parses all the SDTs in the RSDT/XSDT, calling the relevant handlers in the
  168. /// implementation's `AcpiHandler`.
  169. ///
  170. /// If the given revision is 0, an address to the RSDT is expected. Otherwise, an address to
  171. /// the XSDT is expected.
  172. pub unsafe fn parse_rsdt<H>(handler: &mut H, revision: u8, physical_address: usize) -> Result<Acpi, AcpiError>
  173. where
  174. H: AcpiHandler,
  175. {
  176. let mut acpi = Acpi {
  177. acpi_revision: revision,
  178. boot_processor: None,
  179. application_processors: Vec::new(),
  180. interrupt_model: None,
  181. hpet: None,
  182. power_profile: PowerProfile::Unspecified,
  183. dsdt: None,
  184. ssdts: Vec::new(),
  185. pci_config_regions: None,
  186. };
  187. let header = sdt::peek_at_sdt_header(handler, physical_address);
  188. let mapping = unsafe { handler.map_physical_region::<SdtHeader>(physical_address, header.length as usize) };
  189. if revision == 0 {
  190. /*
  191. * ACPI Version 1.0. It's a RSDT!
  192. */
  193. (*mapping).validate(sdt::Signature::RSDT)?;
  194. let num_tables = ((*mapping).length as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u32>();
  195. let tables_base = ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u32;
  196. for i in 0..num_tables {
  197. sdt::dispatch_sdt(&mut acpi, handler, unsafe { *tables_base.offset(i as isize) } as usize)?;
  198. }
  199. } else {
  200. /*
  201. * ACPI Version 2.0+. It's a XSDT!
  202. */
  203. (*mapping).validate(sdt::Signature::XSDT)?;
  204. let num_tables = ((*mapping).length as usize - mem::size_of::<SdtHeader>()) / mem::size_of::<u64>();
  205. let tables_base = ((mapping.virtual_start.as_ptr() as usize) + mem::size_of::<SdtHeader>()) as *const u64;
  206. for i in 0..num_tables {
  207. sdt::dispatch_sdt(&mut acpi, handler, unsafe { *tables_base.offset(i as isize) } as usize)?;
  208. }
  209. }
  210. handler.unmap_physical_region(mapping);
  211. Ok(acpi)
  212. }