lib.rs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. //! `aml` is a pure-Rust AML (ACPI Machine Language) parser, used for parsing the DSDT and
  2. //! SSDT tables from ACPI. This crate can be used by kernels to gather information about the
  3. //! hardware, and invoke control methods (this is not yet supported) to query and change the state
  4. //! of devices in a hardware-independent way.
  5. //!
  6. //! ### Using the library
  7. //! To use the library, you will mostly interact with the `AmlContext` type. You should create an
  8. //! instance of this type using `AmlContext::new()`, and then pass it tables containing AML
  9. //! (probably from the `acpi` crate), which you've mapped into the virtual address space. This will
  10. //! parse the table, populating the namespace with objects encoded by the AML. After this, you may
  11. //! unmap the memory the table was mapped into - all the information needed will be extracted and
  12. //! allocated on the heap.
  13. //!
  14. //! You can then access specific objects by name like so: e.g.
  15. //! ```ignore
  16. //! let my_aml_value = aml_context.lookup(&AmlName::from_str("\\_SB.PCI0.S08._ADR").unwrap());
  17. //! ```
  18. //!
  19. //! ### About the parser
  20. //! The parser is written using a set of custom parser combinators - the code can be confusing on
  21. //! first reading, but provides an extensible and type-safe way to write parsers. For an easy
  22. //! introduction to parser combinators and the foundations used for this library, I suggest reading
  23. //! [Bodil's fantastic blog post](https://bodil.lol/parser-combinators/).
  24. //!
  25. //! The actual combinators can be found in `parser.rs`. Various tricks are used to provide a nice
  26. //! API and work around limitations in the type system, such as the concrete types like
  27. //! `MapWithContext`, and the `make_parser_concrete` hack macro.
  28. //!
  29. //! The actual parsers are then grouped into categories based loosely on the AML grammar sections in
  30. //! the ACPI spec. Most are written in terms of combinators, but some have to be written in a more
  31. //! imperitive style, either because they're clearer, or because we haven't yet found good
  32. //! combinator patterns to express the parse.
  33. #![no_std]
  34. #![feature(decl_macro, type_ascription, box_syntax)]
  35. extern crate alloc;
  36. #[cfg(test)]
  37. extern crate std;
  38. #[cfg(test)]
  39. mod test_utils;
  40. pub(crate) mod misc;
  41. pub(crate) mod name_object;
  42. pub(crate) mod namespace;
  43. pub(crate) mod opcode;
  44. pub(crate) mod parser;
  45. pub mod pci_routing;
  46. pub(crate) mod pkg_length;
  47. pub(crate) mod term_object;
  48. pub(crate) mod type1;
  49. pub(crate) mod type2;
  50. pub mod value;
  51. pub use crate::{
  52. namespace::{AmlHandle, AmlName, Namespace},
  53. value::AmlValue,
  54. };
  55. use alloc::string::String;
  56. use log::error;
  57. use misc::{ArgNum, LocalNum};
  58. use parser::Parser;
  59. use pkg_length::PkgLength;
  60. use term_object::term_list;
  61. use value::Args;
  62. /// AML has a `RevisionOp` operator that returns the "AML interpreter revision". It's not clear
  63. /// what this is actually used for, but this is ours.
  64. pub const AML_INTERPRETER_REVISION: u64 = 0;
  65. #[derive(Debug)]
  66. pub struct AmlContext {
  67. pub namespace: Namespace,
  68. current_scope: AmlName,
  69. /*
  70. * AML local variables. These are used when we invoke a control method. A `None` value
  71. * represents a null AML object.
  72. */
  73. local_0: Option<AmlValue>,
  74. local_1: Option<AmlValue>,
  75. local_2: Option<AmlValue>,
  76. local_3: Option<AmlValue>,
  77. local_4: Option<AmlValue>,
  78. local_5: Option<AmlValue>,
  79. local_6: Option<AmlValue>,
  80. local_7: Option<AmlValue>,
  81. /// If we're currently invoking a control method, this stores the arguments that were passed to
  82. /// it. It's `None` if we aren't invoking a method.
  83. current_args: Option<Args>,
  84. }
  85. impl AmlContext {
  86. pub fn new() -> AmlContext {
  87. AmlContext {
  88. namespace: Namespace::new(),
  89. current_scope: AmlName::root(),
  90. local_0: None,
  91. local_1: None,
  92. local_2: None,
  93. local_3: None,
  94. local_4: None,
  95. local_5: None,
  96. local_6: None,
  97. local_7: None,
  98. current_args: None,
  99. }
  100. }
  101. pub fn parse_table(&mut self, stream: &[u8]) -> Result<(), AmlError> {
  102. if stream.len() == 0 {
  103. return Err(AmlError::UnexpectedEndOfStream);
  104. }
  105. let table_length = PkgLength::from_raw_length(stream, stream.len() as u32) as PkgLength;
  106. match term_object::term_list(table_length).parse(stream, self) {
  107. Ok(_) => Ok(()),
  108. Err((_, _, err)) => {
  109. error!("Failed to parse AML stream. Err = {:?}", err);
  110. Err(err)
  111. }
  112. }
  113. }
  114. /// Invoke a method referred to by its path in the namespace, with the given arguments.
  115. pub fn invoke_method(&mut self, path: &AmlName, args: Args) -> Result<AmlValue, AmlError> {
  116. if let AmlValue::Method { flags, code } = self.namespace.get_by_path(path)?.clone() {
  117. /*
  118. * First, set up the state we expect to enter the method with, but clearing local
  119. * variables to "null" and setting the arguments.
  120. */
  121. self.current_scope = path.clone();
  122. self.current_args = Some(args);
  123. self.local_0 = None;
  124. self.local_1 = None;
  125. self.local_2 = None;
  126. self.local_3 = None;
  127. self.local_4 = None;
  128. self.local_5 = None;
  129. self.local_6 = None;
  130. self.local_7 = None;
  131. log::trace!("Invoking method with {} arguments, code: {:x?}", flags.arg_count(), code);
  132. let return_value =
  133. match term_list(PkgLength::from_raw_length(&code, code.len() as u32)).parse(&code, self) {
  134. // If the method doesn't return a value, we implicitly return `0`
  135. Ok(_) => Ok(AmlValue::Integer(0)),
  136. Err((_, _, AmlError::Return(result))) => Ok(result),
  137. Err((_, _, err)) => {
  138. error!("Failed to execute control method: {:?}", err);
  139. Err(err)
  140. }
  141. };
  142. /*
  143. * Now clear the state.
  144. */
  145. self.current_args = None;
  146. self.local_0 = None;
  147. self.local_1 = None;
  148. self.local_2 = None;
  149. self.local_3 = None;
  150. self.local_4 = None;
  151. self.local_5 = None;
  152. self.local_6 = None;
  153. self.local_7 = None;
  154. return_value
  155. } else {
  156. Err(AmlError::IncompatibleValueConversion)
  157. }
  158. }
  159. pub(crate) fn current_arg(&self, arg: ArgNum) -> Result<&AmlValue, AmlError> {
  160. self.current_args.as_ref().ok_or(AmlError::InvalidArgumentAccess(0xff))?.arg(arg)
  161. }
  162. /// Get the current value of a local by its local number.
  163. ///
  164. /// ### Panics
  165. /// Panics if an invalid local number is passed (valid local numbers are `0..=7`)
  166. pub(crate) fn local(&self, local: LocalNum) -> Result<&AmlValue, AmlError> {
  167. match local {
  168. 0 => self.local_0.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  169. 1 => self.local_1.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  170. 2 => self.local_2.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  171. 3 => self.local_3.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  172. 4 => self.local_4.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  173. 5 => self.local_5.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  174. 6 => self.local_6.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  175. 7 => self.local_7.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  176. _ => panic!("Invalid local number: {}", local),
  177. }
  178. }
  179. }
  180. #[derive(Clone, Debug, PartialEq, Eq)]
  181. pub enum AmlError {
  182. /*
  183. * Errors produced parsing the AML stream.
  184. */
  185. UnexpectedEndOfStream,
  186. UnexpectedByte(u8),
  187. InvalidNameSeg([u8; 4]),
  188. InvalidFieldFlags,
  189. IncompatibleValueConversion,
  190. UnterminatedStringConstant,
  191. InvalidStringConstant,
  192. InvalidRegionSpace(u8),
  193. /// Emitted by a parser when it's clear that the stream doesn't encode the object parsed by
  194. /// that parser (e.g. the wrong opcode starts the stream). This is handled specially by some
  195. /// parsers such as `or` and `choice!`.
  196. WrongParser,
  197. /*
  198. * Errors produced manipulating AML names.
  199. */
  200. /// Produced when trying to normalize a path that does not point to a valid level of the
  201. /// namespace. E.g. `\_SB.^^PCI0` goes above the root of the namespace.
  202. InvalidNormalizedName(String),
  203. RootHasNoParent,
  204. /*
  205. * Errors produced working with the namespace.
  206. */
  207. /// Produced when a path is given that does not point to an object in the AML namespace.
  208. ObjectDoesNotExist(String),
  209. HandleDoesNotExist(AmlHandle),
  210. /// Produced when two values with the same name are added to the namespace.
  211. NameCollision(AmlName),
  212. /*
  213. * Errors produced executing control methods.
  214. */
  215. /// Produced when a method accesses an argument it does not have (e.g. a method that takes 2
  216. /// arguments accesses `Arg4`). The inner value is the number of the argument accessed. If any
  217. /// arguments are accessed when a method is not being executed, this error is produced with an
  218. /// argument number of `0xff`.
  219. InvalidArgumentAccess(ArgNum),
  220. InvalidLocalAccess(LocalNum),
  221. /// This is not a real error, but is used to propagate return values from within the deep
  222. /// parsing call-stack. It should only be emitted when parsing a `DefReturn`. We use the
  223. /// error system here because the way errors are propagated matches how we want to handle
  224. /// return values.
  225. Return(AmlValue),
  226. /*
  227. * Errors produced parsing the PCI routing tables (_PRT objects).
  228. */
  229. PrtInvalidAddress,
  230. PrtInvalidPin,
  231. PrtInvalidSource,
  232. PrtInvalidGsi,
  233. }