lib.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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 mod resource;
  48. pub(crate) mod term_object;
  49. pub(crate) mod type1;
  50. pub(crate) mod type2;
  51. pub mod value;
  52. pub use crate::{
  53. namespace::{AmlHandle, AmlName, Namespace},
  54. value::AmlValue,
  55. };
  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. /// Describes how much debug information the parser should emit. Set the "maximum" expected verbosity in
  66. /// the context's `debug_verbosity` - everything will be printed that is less or equal in 'verbosity'.
  67. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
  68. pub enum DebugVerbosity {
  69. /// Print no debug information
  70. None,
  71. /// Print heads and tails when entering and leaving scopes of major objects, but not more minor ones.
  72. Scopes,
  73. /// Print heads and tails when entering and leaving scopes of all objects.
  74. AllScopes,
  75. /// Print heads and tails of all objects, and extra debug information as it's parsed.
  76. All,
  77. }
  78. #[derive(Debug)]
  79. pub struct AmlContext {
  80. pub namespace: Namespace,
  81. /*
  82. * AML local variables. These are used when we invoke a control method. A `None` value
  83. * represents a null AML object.
  84. */
  85. local_0: Option<AmlValue>,
  86. local_1: Option<AmlValue>,
  87. local_2: Option<AmlValue>,
  88. local_3: Option<AmlValue>,
  89. local_4: Option<AmlValue>,
  90. local_5: Option<AmlValue>,
  91. local_6: Option<AmlValue>,
  92. local_7: Option<AmlValue>,
  93. /// If we're currently invoking a control method, this stores the arguments that were passed to
  94. /// it. It's `None` if we aren't invoking a method.
  95. current_args: Option<Args>,
  96. /*
  97. * These track the state of the context while it's parsing an AML table.
  98. */
  99. current_scope: AmlName,
  100. scope_indent: usize,
  101. debug_verbosity: DebugVerbosity,
  102. }
  103. impl AmlContext {
  104. pub fn new(debug_verbosity: DebugVerbosity) -> AmlContext {
  105. AmlContext {
  106. namespace: Namespace::new(),
  107. local_0: None,
  108. local_1: None,
  109. local_2: None,
  110. local_3: None,
  111. local_4: None,
  112. local_5: None,
  113. local_6: None,
  114. local_7: None,
  115. current_args: None,
  116. current_scope: AmlName::root(),
  117. scope_indent: 0,
  118. debug_verbosity,
  119. }
  120. }
  121. pub fn parse_table(&mut self, stream: &[u8]) -> Result<(), AmlError> {
  122. if stream.len() == 0 {
  123. return Err(AmlError::UnexpectedEndOfStream);
  124. }
  125. let table_length = PkgLength::from_raw_length(stream, stream.len() as u32) as PkgLength;
  126. match term_object::term_list(table_length).parse(stream, self) {
  127. Ok(_) => Ok(()),
  128. Err((_, _, err)) => {
  129. error!("Failed to parse AML stream. Err = {:?}", err);
  130. Err(err)
  131. }
  132. }
  133. }
  134. /// Invoke a method referred to by its path in the namespace, with the given arguments.
  135. pub fn invoke_method(&mut self, path: &AmlName, args: Args) -> Result<AmlValue, AmlError> {
  136. if let AmlValue::Method { flags, code } = self.namespace.get_by_path(path)?.clone() {
  137. /*
  138. * First, set up the state we expect to enter the method with, but clearing local
  139. * variables to "null" and setting the arguments.
  140. */
  141. self.current_scope = path.clone();
  142. self.current_args = Some(args);
  143. self.local_0 = None;
  144. self.local_1 = None;
  145. self.local_2 = None;
  146. self.local_3 = None;
  147. self.local_4 = None;
  148. self.local_5 = None;
  149. self.local_6 = None;
  150. self.local_7 = None;
  151. log::trace!("Invoking method with {} arguments, code: {:x?}", flags.arg_count(), code);
  152. let return_value =
  153. match term_list(PkgLength::from_raw_length(&code, code.len() as u32)).parse(&code, self) {
  154. // If the method doesn't return a value, we implicitly return `0`
  155. Ok(_) => Ok(AmlValue::Integer(0)),
  156. Err((_, _, AmlError::Return(result))) => Ok(result),
  157. Err((_, _, err)) => {
  158. error!("Failed to execute control method: {:?}", err);
  159. Err(err)
  160. }
  161. };
  162. /*
  163. * Now clear the state.
  164. */
  165. self.current_args = None;
  166. self.local_0 = None;
  167. self.local_1 = None;
  168. self.local_2 = None;
  169. self.local_3 = None;
  170. self.local_4 = None;
  171. self.local_5 = None;
  172. self.local_6 = None;
  173. self.local_7 = None;
  174. return_value
  175. } else {
  176. Err(AmlError::IncompatibleValueConversion)
  177. }
  178. }
  179. pub(crate) fn current_arg(&self, arg: ArgNum) -> Result<&AmlValue, AmlError> {
  180. self.current_args.as_ref().ok_or(AmlError::InvalidArgumentAccess(0xff))?.arg(arg)
  181. }
  182. /// Get the current value of a local by its local number.
  183. ///
  184. /// ### Panics
  185. /// Panics if an invalid local number is passed (valid local numbers are `0..=7`)
  186. pub(crate) fn local(&self, local: LocalNum) -> Result<&AmlValue, AmlError> {
  187. match local {
  188. 0 => self.local_0.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  189. 1 => self.local_1.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  190. 2 => self.local_2.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  191. 3 => self.local_3.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  192. 4 => self.local_4.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  193. 5 => self.local_5.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  194. 6 => self.local_6.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  195. 7 => self.local_7.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
  196. _ => panic!("Invalid local number: {}", local),
  197. }
  198. }
  199. }
  200. #[derive(Clone, Debug, PartialEq, Eq)]
  201. pub enum AmlError {
  202. /*
  203. * Errors produced parsing the AML stream.
  204. */
  205. UnexpectedEndOfStream,
  206. UnexpectedByte(u8),
  207. InvalidNameSeg,
  208. InvalidFieldFlags,
  209. IncompatibleValueConversion,
  210. UnterminatedStringConstant,
  211. InvalidStringConstant,
  212. InvalidRegionSpace(u8),
  213. /// Emitted by a parser when it's clear that the stream doesn't encode the object parsed by
  214. /// that parser (e.g. the wrong opcode starts the stream). This is handled specially by some
  215. /// parsers such as `or` and `choice!`.
  216. WrongParser,
  217. /*
  218. * Errors produced manipulating AML names.
  219. */
  220. EmptyNamesAreInvalid,
  221. /// Produced when trying to normalize a path that does not point to a valid level of the
  222. /// namespace. E.g. `\_SB.^^PCI0` goes above the root of the namespace. The contained value is the name that
  223. /// normalization was attempted upon.
  224. InvalidNormalizedName(AmlName),
  225. RootHasNoParent,
  226. /*
  227. * Errors produced working with the namespace.
  228. */
  229. /// Produced when a sub-level or value is added to a level that has not yet been added to the namespace. The
  230. /// `AmlName` is the name of the entire sub-level/value.
  231. LevelDoesNotExist(AmlName),
  232. ValueDoesNotExist(AmlName),
  233. /// Produced when two values with the same name are added to the namespace.
  234. NameCollision(AmlName),
  235. /*
  236. * Errors produced executing control methods.
  237. */
  238. /// Produced when a method accesses an argument it does not have (e.g. a method that takes 2
  239. /// arguments accesses `Arg4`). The inner value is the number of the argument accessed. If any
  240. /// arguments are accessed when a method is not being executed, this error is produced with an
  241. /// argument number of `0xff`.
  242. InvalidArgumentAccess(ArgNum),
  243. InvalidLocalAccess(LocalNum),
  244. /// This is not a real error, but is used to propagate return values from within the deep
  245. /// parsing call-stack. It should only be emitted when parsing a `DefReturn`. We use the
  246. /// error system here because the way errors are propagated matches how we want to handle
  247. /// return values.
  248. Return(AmlValue),
  249. /*
  250. * Errors produced parsing the PCI routing tables (_PRT objects).
  251. */
  252. PrtInvalidAddress,
  253. PrtInvalidPin,
  254. PrtInvalidSource,
  255. PrtInvalidGsi,
  256. /// Produced when the PRT doesn't contain an entry for the requested address + pin
  257. PrtNoEntry,
  258. /*
  259. * Errors produced parsing Resource Descriptors.
  260. */
  261. ReservedResourceType,
  262. ResourceDescriptorTooShort,
  263. }