lib.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. //! A library for parsing ACPI tables. This crate can be used by bootloaders and kernels for architectures that
  2. //! support ACPI. This crate is not feature-complete, but can parse lots of the more common tables. Parsing the
  3. //! ACPI tables is required for correctly setting up the APICs, HPET, and provides useful information about power
  4. //! management and many other platform capabilities.
  5. //!
  6. //! This crate is designed to find and parse the static tables ACPI provides. It should be used in conjunction with
  7. //! the `aml` crate, which is the (much less complete) AML parser used to parse the DSDT and SSDTs. These crates
  8. //! are separate because some kernels may want to detect the static tables, but delay AML parsing to a later stage.
  9. //!
  10. //! This crate can be used in three configurations, depending on the environment it's being used from:
  11. //! - **Without allocator support** - this can be achieved by disabling the `allocator_api` and `alloc`
  12. //! features. The core parts of the library will still be usable, but with generally reduced functionality
  13. //! and ease-of-use.
  14. //! - **With a custom allocator** - by disabling just the `alloc` feature, you can use the `new_in` functions to
  15. //! access increased functionality with your own allocator. This allows `acpi` to be integrated more closely
  16. //! with environments that already provide a custom allocator, for example to gracefully handle allocation
  17. //! errors.
  18. //! - **With the globally-set allocator** - the `alloc` feature provides `new` functions that simply use the
  19. //! global allocator. This is the easiest option, and the one the majority of users will want. It is the
  20. //! default configuration of the crate.
  21. //!
  22. //! ### Usage
  23. //! To use the library, you will need to provide an implementation of the `AcpiHandler` trait, which allows the
  24. //! library to make requests such as mapping a particular region of physical memory into the virtual address space.
  25. //!
  26. //! You then need to construct an instance of `AcpiTables`, which can be done in a few ways depending on how much
  27. //! information you have:
  28. //! * Use `AcpiTables::from_rsdp` if you have the physical address of the RSDP
  29. //! * Use `AcpiTables::from_rsdt` if you have the physical address of the RSDT/XSDT
  30. //! * Use `AcpiTables::search_for_rsdp_bios` if you don't have the address of either, but **you know you are
  31. //! running on BIOS, not UEFI**
  32. //! * Use `AcpiTables::from_tables_direct` if you are using the library in an unusual setting, such as in usermode,
  33. //! and have a custom method to enumerate and access the tables.
  34. //!
  35. //! `AcpiTables` stores the addresses of all of the tables detected on a platform. The SDTs are parsed by this
  36. //! library, or can be accessed directly with `from_sdt`, while the `DSDT` and any `SSDTs` should be parsed with
  37. //! `aml`.
  38. //!
  39. //! To gather information out of the static tables, a few of the types you should take a look at are:
  40. //! - [`PlatformInfo`](crate::platform::PlatformInfo) parses the FADT and MADT to create a nice view of the
  41. //! processor topology and interrupt controllers on `x86_64`, and the interrupt controllers on other platforms.
  42. //! `AcpiTables::platform_info` is a convenience method for constructing a `PlatformInfo`.
  43. //! - [`HpetInfo`](crate::hpet::HpetInfo) parses the HPET table and tells you how to configure the High
  44. //! Precision Event Timer.
  45. //! - [`PciConfigRegions`](crate::mcfg::PciConfigRegions) parses the MCFG and tells you how PCIe configuration
  46. //! space is mapped into physical memory.
  47. /*
  48. * Contributing notes (you may find these useful if you're new to contributing to the library):
  49. * - Accessing packed fields without UB: Lots of the structures defined by ACPI are defined with `repr(packed)`
  50. * to prevent padding being introduced, which would make the structure's layout incorrect. In Rust, this
  51. * creates a problem as references to these fields could be unaligned, which is undefined behaviour. For the
  52. * majority of these fields, this problem can be easily avoided by telling the compiler to make a copy of the
  53. * field's contents: this is the perhaps unfamiliar pattern of e.g. `!{ entry.flags }.get_bit(0)` we use
  54. * around the codebase.
  55. */
  56. #![no_std]
  57. #![deny(unsafe_op_in_unsafe_fn)]
  58. #![cfg_attr(feature = "allocator_api", feature(allocator_api))]
  59. #[cfg_attr(test, macro_use)]
  60. #[cfg(test)]
  61. extern crate std;
  62. #[cfg(feature = "alloc")]
  63. extern crate alloc;
  64. pub mod address;
  65. pub mod bgrt;
  66. pub mod fadt;
  67. pub mod handler;
  68. pub mod hpet;
  69. pub mod madt;
  70. pub mod mcfg;
  71. pub mod rsdp;
  72. pub mod sdt;
  73. #[cfg(feature = "allocator_api")]
  74. mod managed_slice;
  75. #[cfg(feature = "allocator_api")]
  76. pub use managed_slice::*;
  77. #[cfg(feature = "allocator_api")]
  78. pub mod platform;
  79. #[cfg(feature = "allocator_api")]
  80. pub use crate::platform::{interrupt::InterruptModel, PlatformInfo};
  81. #[cfg(feature = "allocator_api")]
  82. pub use crate::mcfg::PciConfigRegions;
  83. pub use fadt::PowerProfile;
  84. pub use handler::{AcpiHandler, PhysicalMapping};
  85. pub use hpet::HpetInfo;
  86. pub use madt::MadtError;
  87. use crate::sdt::{SdtHeader, Signature};
  88. use core::mem;
  89. use rsdp::Rsdp;
  90. /// Result type used by error-returning functions.
  91. pub type AcpiResult<T> = core::result::Result<T, AcpiError>;
  92. /// All types representing ACPI tables should implement this trait.
  93. ///
  94. /// ### Safety
  95. ///
  96. /// The table's memory is naively interpreted, so you must be careful in providing a type that
  97. /// correctly represents the table's structure. Regardless of the provided type's size, the region mapped will
  98. /// be the size specified in the SDT's header. Providing a table impl that is larger than this, *may* lead to
  99. /// page-faults, aliasing references, or derefencing uninitialized memory (the latter two being UB).
  100. /// This isn't forbidden, however, because some tables rely on the impl being larger than a provided SDT in some
  101. /// versions of ACPI (the [`ExtendedField`](crate::sdt::ExtendedField) type will be useful if you need to do
  102. /// this. See our [`Fadt`](crate::fadt::Fadt) type for an example of this).
  103. pub unsafe trait AcpiTable {
  104. const SIGNATURE: Signature;
  105. fn header(&self) -> &sdt::SdtHeader;
  106. fn validate(&self) -> AcpiResult<()> {
  107. self.header().validate(Self::SIGNATURE)
  108. }
  109. }
  110. /// Error type used by functions that return an `AcpiResult<T>`.
  111. #[derive(Debug)]
  112. pub enum AcpiError {
  113. NoValidRsdp,
  114. RsdpIncorrectSignature,
  115. RsdpInvalidOemId,
  116. RsdpInvalidChecksum,
  117. SdtInvalidSignature(Signature),
  118. SdtInvalidOemId(Signature),
  119. SdtInvalidTableId(Signature),
  120. SdtInvalidChecksum(Signature),
  121. TableMissing(Signature),
  122. InvalidFacsAddress,
  123. InvalidDsdtAddress,
  124. InvalidMadt(MadtError),
  125. InvalidGenericAddress,
  126. AllocError,
  127. }
  128. /// Type capable of enumerating the existing ACPI tables on the system.
  129. ///
  130. ///
  131. /// ### Implementation Note
  132. ///
  133. /// When using the `allocator_api`±`alloc` features, [`PlatformInfo::new()`] or [`PlatformInfo::new_in()`] provide
  134. /// a much cleaner API for enumerating ACPI structures once an `AcpiTables` has been constructed.
  135. #[derive(Debug)]
  136. pub struct AcpiTables<H: AcpiHandler> {
  137. mapping: PhysicalMapping<H, SdtHeader>,
  138. revision: u8,
  139. handler: H,
  140. }
  141. impl<H> AcpiTables<H>
  142. where
  143. H: AcpiHandler,
  144. {
  145. /// Create an `AcpiTables` if you have the physical address of the RSDP.
  146. ///
  147. /// ### Safety: Caller must ensure the provided address is valid to read as an RSDP.
  148. pub unsafe fn from_rsdp(handler: H, address: usize) -> AcpiResult<Self> {
  149. let rsdp_mapping = unsafe { handler.map_physical_region::<Rsdp>(address, mem::size_of::<Rsdp>()) };
  150. rsdp_mapping.validate()?;
  151. // Safety: RSDP has been validated.
  152. unsafe { Self::from_validated_rsdp(handler, rsdp_mapping) }
  153. }
  154. /// Search for the RSDP on a BIOS platform. This accesses BIOS-specific memory locations and will probably not
  155. /// work on UEFI platforms. See [Rsdp::search_for_rsdp_bios](rsdp_search::Rsdp::search_for_rsdp_bios) for
  156. /// details.
  157. pub unsafe fn search_for_rsdp_bios(handler: H) -> AcpiResult<Self> {
  158. let rsdp_mapping = unsafe { Rsdp::search_for_on_bios(handler.clone())? };
  159. // Safety: RSDP has been validated from `Rsdp::search_for_on_bios`
  160. unsafe { Self::from_validated_rsdp(handler, rsdp_mapping) }
  161. }
  162. /// Create an `AcpiTables` if you have a `PhysicalMapping` of the RSDP that you know is correct. This is called
  163. /// from `from_rsdp` after validation, but can also be used if you've searched for the RSDP manually on a BIOS
  164. /// system.
  165. ///
  166. /// ### Safety: Caller must ensure that the provided mapping is a fully validated RSDP.
  167. pub unsafe fn from_validated_rsdp(handler: H, rsdp_mapping: PhysicalMapping<H, Rsdp>) -> AcpiResult<Self> {
  168. macro_rules! read_root_table {
  169. ($signature_name:ident, $address_getter:ident) => {{
  170. #[repr(transparent)]
  171. struct RootTable {
  172. header: SdtHeader,
  173. }
  174. unsafe impl AcpiTable for RootTable {
  175. const SIGNATURE: Signature = Signature::$signature_name;
  176. fn header(&self) -> &SdtHeader {
  177. &self.header
  178. }
  179. }
  180. // Unmap RSDP as soon as possible
  181. let table_phys_start = rsdp_mapping.$address_getter() as usize;
  182. drop(rsdp_mapping);
  183. // Map and validate root table
  184. // SAFETY: Addresses from a validated RSDP are also guaranteed to be valid.
  185. let table_mapping = unsafe { read_table::<_, RootTable>(handler.clone(), table_phys_start) }?;
  186. // Convert `table_mapping` to header mapping for storage
  187. // Avoid requesting table unmap twice (from both original and converted `table_mapping`s)
  188. let table_mapping = mem::ManuallyDrop::new(table_mapping);
  189. // SAFETY: `SdtHeader` is equivalent to `Sdt` memory-wise
  190. let table_mapping = unsafe {
  191. PhysicalMapping::new(
  192. table_mapping.physical_start(),
  193. table_mapping.virtual_start().cast::<SdtHeader>(),
  194. table_mapping.region_length(),
  195. table_mapping.mapped_length(),
  196. handler.clone(),
  197. )
  198. };
  199. table_mapping
  200. }};
  201. }
  202. let revision = rsdp_mapping.revision();
  203. let root_table_mapping = if revision == 0 {
  204. /*
  205. * We're running on ACPI Version 1.0. We should use the 32-bit RSDT address.
  206. */
  207. read_root_table!(RSDT, rsdt_address)
  208. } else {
  209. /*
  210. * We're running on ACPI Version 2.0+. We should use the 64-bit XSDT address, truncated
  211. * to 32 bits on x86.
  212. */
  213. read_root_table!(XSDT, xsdt_address)
  214. };
  215. Ok(Self { mapping: root_table_mapping, revision, handler })
  216. }
  217. /// The ACPI revision of the tables enumerated by this structure.
  218. #[inline]
  219. pub const fn revision(&self) -> u8 {
  220. self.revision
  221. }
  222. /// Constructs a [`TablesPhysPtrsIter`] over this table.
  223. fn tables_phys_ptrs(&self) -> TablesPhysPtrsIter<'_> {
  224. // SAFETY: The virtual address of the array of pointers follows the virtual address of the table in memory.
  225. let ptrs_virt_start = unsafe { self.mapping.virtual_start().as_ptr().add(1).cast::<u8>() };
  226. let ptrs_bytes_len = self.mapping.region_length() - mem::size_of::<SdtHeader>();
  227. // SAFETY: `ptrs_virt_start` points to an array of `ptrs_bytes_len` bytes that lives as long as `self`.
  228. let ptrs_bytes = unsafe { core::slice::from_raw_parts(ptrs_virt_start, ptrs_bytes_len) };
  229. let ptr_size = if self.revision == 0 {
  230. 4 // RSDT entry size
  231. } else {
  232. 8 // XSDT entry size
  233. };
  234. ptrs_bytes.chunks(ptr_size).map(|ptr_bytes_src| {
  235. // Construct a native pointer using as many bytes as required from `ptr_bytes_src` (note that ACPI is
  236. // little-endian)
  237. let mut ptr_bytes_dst = [0; mem::size_of::<usize>()];
  238. let common_ptr_size = usize::min(mem::size_of::<usize>(), ptr_bytes_src.len());
  239. ptr_bytes_dst[..common_ptr_size].copy_from_slice(&ptr_bytes_src[..common_ptr_size]);
  240. usize::from_le_bytes(ptr_bytes_dst) as *const SdtHeader
  241. })
  242. }
  243. /// Searches through the ACPI table headers and attempts to locate the table with a matching `T::SIGNATURE`.
  244. pub fn find_table<T: AcpiTable>(&self) -> AcpiResult<PhysicalMapping<H, T>> {
  245. self.tables_phys_ptrs()
  246. .find_map(|table_phys_ptr| {
  247. // SAFETY: Table guarantees its contained addresses to be valid.
  248. match unsafe { read_table(self.handler.clone(), table_phys_ptr as usize) } {
  249. Ok(table_mapping) => Some(table_mapping),
  250. Err(AcpiError::SdtInvalidSignature(_)) => None,
  251. Err(e) => {
  252. log::warn!(
  253. "Found invalid {} table at physical address {:p}: {:?}",
  254. T::SIGNATURE,
  255. table_phys_ptr,
  256. e
  257. );
  258. None
  259. }
  260. }
  261. })
  262. .ok_or(AcpiError::TableMissing(T::SIGNATURE))
  263. }
  264. /// Iterates through all of the table headers.
  265. pub fn headers(&self) -> SdtHeaderIterator<'_, H> {
  266. SdtHeaderIterator { tables_phys_ptrs: self.tables_phys_ptrs(), handler: self.handler.clone() }
  267. }
  268. /// Finds and returns the DSDT AML table, if it exists.
  269. pub fn dsdt(&self) -> AcpiResult<AmlTable> {
  270. self.find_table::<fadt::Fadt>().and_then(|fadt| {
  271. #[repr(transparent)]
  272. struct Dsdt {
  273. header: SdtHeader,
  274. }
  275. // Safety: Implementation properly represents a valid DSDT.
  276. unsafe impl AcpiTable for Dsdt {
  277. const SIGNATURE: Signature = Signature::DSDT;
  278. fn header(&self) -> &SdtHeader {
  279. &self.header
  280. }
  281. }
  282. let dsdt_address = fadt.dsdt_address()?;
  283. let dsdt = unsafe { read_table::<H, Dsdt>(self.handler.clone(), dsdt_address)? };
  284. Ok(AmlTable::new(dsdt_address, dsdt.header().length))
  285. })
  286. }
  287. /// Iterates through all of the SSDT tables.
  288. pub fn ssdts(&self) -> SsdtIterator<H> {
  289. SsdtIterator { tables_phys_ptrs: self.tables_phys_ptrs(), handler: self.handler.clone() }
  290. }
  291. /// Convenience method for contructing a [`PlatformInfo`](crate::platform::PlatformInfo). This is one of the
  292. /// first things you should usually do with an `AcpiTables`, and allows to collect helpful information about
  293. /// the platform from the ACPI tables.
  294. ///
  295. /// Like `platform_info_in`, but uses the global allocator.
  296. #[cfg(feature = "alloc")]
  297. pub fn platform_info(&self) -> AcpiResult<PlatformInfo<alloc::alloc::Global>> {
  298. PlatformInfo::new(self)
  299. }
  300. /// Convenience method for contructing a [`PlatformInfo`](crate::platform::PlatformInfo). This is one of the
  301. /// first things you should usually do with an `AcpiTables`, and allows to collect helpful information about
  302. /// the platform from the ACPI tables.
  303. #[cfg(feature = "allocator_api")]
  304. pub fn platform_info_in<A>(&self, allocator: A) -> AcpiResult<PlatformInfo<A>>
  305. where
  306. A: core::alloc::Allocator + Clone,
  307. {
  308. PlatformInfo::new_in(self, allocator)
  309. }
  310. }
  311. #[derive(Debug)]
  312. pub struct Sdt {
  313. /// Physical address of the start of the SDT, including the header.
  314. pub physical_address: usize,
  315. /// Length of the table in bytes.
  316. pub length: u32,
  317. /// Whether this SDT has been validated. This is set to `true` the first time it is mapped and validated.
  318. pub validated: bool,
  319. }
  320. /// An iterator over the physical table addresses in an RSDT or XSDT.
  321. type TablesPhysPtrsIter<'t> = core::iter::Map<core::slice::Chunks<'t, u8>, fn(&[u8]) -> *const SdtHeader>;
  322. #[derive(Debug)]
  323. pub struct AmlTable {
  324. /// Physical address of the start of the AML stream (excluding the table header).
  325. pub address: usize,
  326. /// Length (in bytes) of the AML stream.
  327. pub length: u32,
  328. }
  329. impl AmlTable {
  330. /// Create an `AmlTable` from the address and length of the table **including the SDT header**.
  331. pub(crate) fn new(address: usize, length: u32) -> AmlTable {
  332. AmlTable {
  333. address: address + mem::size_of::<SdtHeader>(),
  334. length: length - mem::size_of::<SdtHeader>() as u32,
  335. }
  336. }
  337. }
  338. /// ### Safety: Caller must ensure the provided address is valid for being read as an `SdtHeader`.
  339. unsafe fn read_table<H: AcpiHandler, T: AcpiTable>(
  340. handler: H,
  341. address: usize,
  342. ) -> AcpiResult<PhysicalMapping<H, T>> {
  343. // Attempt to peek at the SDT header to correctly enumerate the entire table.
  344. // SAFETY: `address` needs to be valid for the size of `SdtHeader`, or the ACPI tables are malformed (not a
  345. // software issue).
  346. let header_mapping = unsafe { handler.map_physical_region::<SdtHeader>(address, mem::size_of::<SdtHeader>()) };
  347. SdtHeader::validate_lazy(header_mapping, handler)
  348. }
  349. /// Iterator that steps through all of the tables, and returns only the SSDTs as `AmlTable`s.
  350. pub struct SsdtIterator<'t, H>
  351. where
  352. H: AcpiHandler,
  353. {
  354. tables_phys_ptrs: TablesPhysPtrsIter<'t>,
  355. handler: H,
  356. }
  357. impl<'t, H> Iterator for SsdtIterator<'t, H>
  358. where
  359. H: AcpiHandler,
  360. {
  361. type Item = AmlTable;
  362. fn next(&mut self) -> Option<Self::Item> {
  363. #[repr(transparent)]
  364. struct Ssdt {
  365. header: SdtHeader,
  366. }
  367. // SAFETY: Implementation properly represents a valid SSDT.
  368. unsafe impl AcpiTable for Ssdt {
  369. const SIGNATURE: Signature = Signature::SSDT;
  370. fn header(&self) -> &SdtHeader {
  371. &self.header
  372. }
  373. }
  374. // Borrow single field for closure to avoid immutable reference to `self` that inhibits `find_map`
  375. let handler = &self.handler;
  376. // Consume iterator until next valid SSDT and return the latter
  377. self.tables_phys_ptrs.find_map(|table_phys_ptr| {
  378. // SAFETY: Table guarantees its contained addresses to be valid.
  379. match unsafe { read_table::<_, Ssdt>(handler.clone(), table_phys_ptr as usize) } {
  380. Ok(ssdt_mapping) => Some(AmlTable::new(ssdt_mapping.physical_start(), ssdt_mapping.header.length)),
  381. Err(AcpiError::SdtInvalidSignature(_)) => None,
  382. Err(e) => {
  383. log::warn!("Found invalid SSDT at physical address {:p}: {:?}", table_phys_ptr, e);
  384. None
  385. }
  386. }
  387. })
  388. }
  389. }
  390. pub struct SdtHeaderIterator<'t, H>
  391. where
  392. H: AcpiHandler,
  393. {
  394. tables_phys_ptrs: TablesPhysPtrsIter<'t>,
  395. handler: H,
  396. }
  397. impl<'t, H> Iterator for SdtHeaderIterator<'t, H>
  398. where
  399. H: AcpiHandler,
  400. {
  401. type Item = SdtHeader;
  402. fn next(&mut self) -> Option<Self::Item> {
  403. loop {
  404. let table_phys_ptr = self.tables_phys_ptrs.next()?;
  405. // SAFETY: `address` needs to be valid for the size of `SdtHeader`, or the ACPI tables are malformed (not a
  406. // software issue).
  407. let header_mapping = unsafe {
  408. self.handler.map_physical_region::<SdtHeader>(table_phys_ptr as usize, mem::size_of::<SdtHeader>())
  409. };
  410. let r = header_mapping.validate(header_mapping.signature);
  411. if r.is_err() {
  412. log::warn!("Found invalid SDT at physical address {:p}: {:?}", table_phys_ptr, r);
  413. continue;
  414. }
  415. let result = header_mapping.clone();
  416. drop(header_mapping);
  417. return Some(result);
  418. }
  419. }
  420. }