lib.rs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  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 to query and change the state of devices in a
  4. //! hardware-independent way.
  5. //!
  6. //! ### Using the library
  7. //! To use the library, you should create an `AmlContext` using `AmlContext::new()`, and then pass it tables
  8. //! containing AML (probably from the `acpi` crate), which you've mapped into the virtual address space. This will
  9. //! parse the table, populating the namespace with objects encoded by the AML. After this, you may unmap the memory
  10. //! the table was mapped into - all the information needed will be extracted and allocated on the heap.
  11. //!
  12. //! You can then access specific objects by name like so: e.g.
  13. //! ```ignore
  14. //! let my_aml_value = aml_context.lookup(&AmlName::from_str("\\_SB.PCI0.S08._ADR").unwrap());
  15. //! ```
  16. //!
  17. //! And invoke control methods like this: e.g.
  18. //! ```ignore
  19. //! let result = aml_context.invoke_method(&AmlName::from_str("\\_SB.HPET._CRS").unwrap(), value::Args::EMPTY);
  20. //! ```
  21. //!
  22. //! ### About the parser
  23. //! The parser is written using a set of custom parser combinators - the code can be confusing on
  24. //! first reading, but provides an extensible and type-safe way to write parsers. For an easy
  25. //! introduction to parser combinators and the foundations used for this library, I suggest reading
  26. //! [Bodil's fantastic blog post](https://bodil.lol/parser-combinators/).
  27. //!
  28. //! The actual combinators can be found in `parser.rs`. Various tricks are used to provide a nice
  29. //! API and work around limitations in the type system, such as the concrete types like
  30. //! `MapWithContext`.
  31. //!
  32. //! The actual parsers are then grouped into categories based loosely on the AML grammar sections in
  33. //! the ACPI spec. Most are written in terms of combinators, but some have to be written in a more
  34. //! imperitive style, either because they're clearer, or because we haven't yet found good
  35. //! combinator patterns to express the parse.
  36. #![no_std]
  37. #![feature(decl_macro)]
  38. extern crate alloc;
  39. #[cfg(test)]
  40. extern crate std;
  41. #[cfg(test)]
  42. mod test_utils;
  43. pub(crate) mod expression;
  44. pub(crate) mod misc;
  45. pub(crate) mod name_object;
  46. pub(crate) mod namespace;
  47. pub(crate) mod opcode;
  48. pub mod opregion;
  49. pub(crate) mod parser;
  50. pub mod pci_routing;
  51. pub(crate) mod pkg_length;
  52. pub mod resource;
  53. pub(crate) mod statement;
  54. pub(crate) mod term_object;
  55. pub mod value;
  56. pub use crate::{namespace::*, value::AmlValue};
  57. use alloc::{
  58. boxed::Box,
  59. format,
  60. string::{String, ToString},
  61. };
  62. use core::mem;
  63. use log::{error, warn};
  64. use misc::{ArgNum, LocalNum};
  65. use name_object::Target;
  66. use parser::{Parser, Propagate};
  67. use pkg_length::PkgLength;
  68. use term_object::term_list;
  69. use value::{AmlType, Args};
  70. /// AML has a `RevisionOp` operator that returns the "AML interpreter revision". It's not clear
  71. /// what this is actually used for, but this is ours.
  72. pub const AML_INTERPRETER_REVISION: u64 = 0;
  73. /// Describes how much debug information the parser should emit. Set the "maximum" expected verbosity in
  74. /// the context's `debug_verbosity` - everything will be printed that is less or equal in 'verbosity'.
  75. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
  76. pub enum DebugVerbosity {
  77. /// Print no debug information
  78. None,
  79. /// Print heads and tails when entering and leaving scopes of major objects, but not more minor ones.
  80. Scopes,
  81. /// Print heads and tails when entering and leaving scopes of all objects.
  82. AllScopes,
  83. /// Print heads and tails of all objects, and extra debug information as it's parsed.
  84. All,
  85. }
  86. #[derive(Debug)]
  87. struct MethodContext {
  88. /// AML local variables. These are used when we invoke a control method. A `None` value represents a null AML
  89. /// object.
  90. locals: [Option<AmlValue>; 8],
  91. /// If we're currently invoking a control method, this stores the arguments that were passed to
  92. /// it. It's `None` if we aren't invoking a method.
  93. args: Args,
  94. }
  95. impl MethodContext {
  96. fn new(args: Args) -> MethodContext {
  97. // XXX: this is required because `Option<AmlValue>` is not `Copy`, so it can't be used to initialize an
  98. // array, but consts can :(
  99. const NONE_BUT_CONST: Option<AmlValue> = None;
  100. MethodContext { locals: [NONE_BUT_CONST; 8], args }
  101. }
  102. }
  103. pub struct AmlContext {
  104. /// The `Handler` passed from the library user. This is stored as a boxed trait object simply to avoid having
  105. /// to add a lifetime and type parameter to `AmlContext`, as they would massively complicate the parser types.
  106. handler: Box<dyn Handler>,
  107. pub namespace: Namespace,
  108. method_context: Option<MethodContext>,
  109. /*
  110. * These track the state of the context while it's parsing an AML table.
  111. */
  112. current_scope: AmlName,
  113. scope_indent: usize,
  114. debug_verbosity: DebugVerbosity,
  115. }
  116. impl AmlContext {
  117. /// Creates a new `AmlContext` - the central type in managing the AML tables. Only one of these should be
  118. /// created, and it should be passed the DSDT and all SSDTs defined by the hardware.
  119. pub fn new(handler: Box<dyn Handler>, debug_verbosity: DebugVerbosity) -> AmlContext {
  120. let mut context = AmlContext {
  121. handler,
  122. namespace: Namespace::new(),
  123. method_context: None,
  124. current_scope: AmlName::root(),
  125. scope_indent: 0,
  126. debug_verbosity,
  127. };
  128. context.add_predefined_objects();
  129. context
  130. }
  131. pub fn parse_table(&mut self, stream: &[u8]) -> Result<(), AmlError> {
  132. fn stream_context(stream: &[u8], err_buf: &[u8]) -> String {
  133. const BEFORE_LEN: usize = 4;
  134. const ABBREV_LEN: usize = 4;
  135. let abbreviated = if err_buf.len() >= ABBREV_LEN { &err_buf[..ABBREV_LEN] } else { err_buf };
  136. if let Some(position) = (err_buf.as_ptr() as usize).checked_sub(stream.as_ptr() as usize) {
  137. if position <= stream.len() {
  138. let before = if position > BEFORE_LEN {
  139. &stream[position - BEFORE_LEN..position]
  140. } else {
  141. &stream[..position]
  142. };
  143. return format!(
  144. "position {:#X}: preceding {:X?}, buf {:X?}",
  145. position + 36,
  146. before,
  147. abbreviated
  148. );
  149. }
  150. }
  151. format!("buf {:X?}", abbreviated)
  152. }
  153. if stream.len() == 0 {
  154. return Err(AmlError::UnexpectedEndOfStream);
  155. }
  156. let table_length = PkgLength::from_raw_length(stream, stream.len() as u32).unwrap();
  157. match term_object::term_list(table_length).parse(stream, self) {
  158. Ok(_) => Ok(()),
  159. Err((err_buf, _, Propagate::Err(err))) => {
  160. error!("Failed to parse AML stream. Err = {:?}, {}", err, stream_context(stream, err_buf));
  161. Err(err)
  162. }
  163. Err((_, _, other)) => {
  164. error!("AML table evaluated to unexpected result: {:?}", other);
  165. Err(AmlError::MalformedStream)
  166. }
  167. }
  168. }
  169. // TODO: docs
  170. pub fn invoke_method(&mut self, path: &AmlName, args: Args) -> Result<AmlValue, AmlError> {
  171. use value::MethodCode;
  172. match self.namespace.get_by_path(path)?.clone() {
  173. // TODO: respect the method's flags
  174. AmlValue::Method { flags: _, code } => {
  175. /*
  176. * First, set up the state we expect to enter the method with, but clearing local
  177. * variables to "null" and setting the arguments. Save the current method state and scope, so if we're
  178. * already executing another control method, we resume into it correctly.
  179. */
  180. let old_context = mem::replace(&mut self.method_context, Some(MethodContext::new(args)));
  181. let old_scope = mem::replace(&mut self.current_scope, path.clone());
  182. /*
  183. * Create a namespace level to store local objects created by the invocation.
  184. */
  185. self.namespace.add_level(path.clone(), LevelType::MethodLocals)?;
  186. let return_value = match code {
  187. MethodCode::Aml(ref code) => {
  188. match term_list(PkgLength::from_raw_length(code, code.len() as u32).unwrap())
  189. .parse(code, self)
  190. {
  191. // If the method doesn't return a value, we implicitly return `0`
  192. Ok(_) => Ok(AmlValue::Integer(0)),
  193. Err((_, _, Propagate::Return(result))) => Ok(result),
  194. Err((_, _, Propagate::Break)) => Err(AmlError::BreakInInvalidPosition),
  195. Err((_, _, Propagate::Continue)) => Err(AmlError::ContinueInInvalidPosition),
  196. Err((_, _, Propagate::Err(err))) => {
  197. error!("Failed to execute control method: {:?}", err);
  198. Err(err)
  199. }
  200. }
  201. }
  202. MethodCode::Native(ref method) => match (method)(self) {
  203. Ok(result) => Ok(result),
  204. Err(err) => {
  205. error!("Failed to execute control method: {:?}", err);
  206. Err(err)
  207. }
  208. },
  209. };
  210. /*
  211. * Locally-created objects should be destroyed on method exit (see §5.5.2.3 of the ACPI spec). We do
  212. * this by simply removing the method's local object layer.
  213. */
  214. // TODO: this should also remove objects created by the method outside the method's scope, if they
  215. // weren't statically created. This is harder.
  216. self.namespace.remove_level(path.clone())?;
  217. /*
  218. * Restore the old state.
  219. */
  220. self.method_context = old_context;
  221. self.current_scope = old_scope;
  222. return_value
  223. }
  224. /*
  225. * AML can encode methods that don't require any computation simply as the value that would otherwise be
  226. * returned (e.g. a `_STA` object simply being an `AmlValue::Integer`, instead of a method that just
  227. * returns an integer).
  228. */
  229. value => Ok(value),
  230. }
  231. }
  232. // TODO: docs
  233. pub fn initialize_objects(&mut self) -> Result<(), AmlError> {
  234. use name_object::NameSeg;
  235. use value::StatusObject;
  236. /*
  237. * If `\_SB._INI` exists, we unconditionally execute it at the beginning of device initialization.
  238. */
  239. match self.invoke_method(&AmlName::from_str("\\_SB._INI").unwrap(), Args::default()) {
  240. Ok(_) => (),
  241. Err(AmlError::ValueDoesNotExist(_)) => (),
  242. Err(err) => return Err(err),
  243. }
  244. /*
  245. * Next, we traverse the namespace, looking for devices.
  246. *
  247. * XXX: we clone the namespace here, which obviously drives up heap burden quite a bit (not as much as you
  248. * might first expect though - we're only duplicating the level data structure, not all the objects). The
  249. * issue here is that we need to access the namespace during traversal (e.g. to invoke a method), which the
  250. * borrow checker really doesn't like. A better solution could be a iterator-like traversal system that
  251. * keeps track of the namespace without keeping it borrowed. This works for now.
  252. */
  253. self.namespace.clone().traverse(|path, level: &NamespaceLevel| match level.typ {
  254. LevelType::Device => {
  255. let status = if level.values.contains_key(&NameSeg::from_str("_STA").unwrap()) {
  256. self.invoke_method(&AmlName::from_str("_STA").unwrap().resolve(&path)?, Args::default())?
  257. .as_status()?
  258. } else {
  259. StatusObject::default()
  260. };
  261. /*
  262. * If the device is present and has an `_INI` method, invoke it.
  263. */
  264. if status.present && level.values.contains_key(&NameSeg::from_str("_INI").unwrap()) {
  265. log::info!("Invoking _INI at level: {}", path);
  266. self.invoke_method(&AmlName::from_str("_INI").unwrap().resolve(&path)?, Args::default())?;
  267. }
  268. /*
  269. * We traverse the children of this device if it's present, or isn't present but is functional.
  270. */
  271. Ok(status.present || status.functional)
  272. }
  273. LevelType::Scope => Ok(true),
  274. // TODO: can any of these contain devices?
  275. LevelType::Processor => Ok(false),
  276. LevelType::PowerResource => Ok(false),
  277. LevelType::ThermalZone => Ok(false),
  278. LevelType::MethodLocals => Ok(false),
  279. })?;
  280. Ok(())
  281. }
  282. pub(crate) fn read_target(&self, target: &Target) -> Result<&AmlValue, AmlError> {
  283. match target {
  284. Target::Null => todo!(),
  285. Target::Name(name) => {
  286. let (_, handle) = self.namespace.search(name, &self.current_scope)?;
  287. self.namespace.get(handle)
  288. }
  289. Target::Debug => todo!(),
  290. Target::Arg(arg) => self.current_arg(*arg),
  291. Target::Local(local) => self.local(*local),
  292. }
  293. }
  294. /// Get the value of an argument by its argument number. Can only be executed from inside a control method.
  295. pub(crate) fn current_arg(&self, arg: ArgNum) -> Result<&AmlValue, AmlError> {
  296. self.method_context.as_ref().ok_or(AmlError::NotExecutingControlMethod)?.args.arg(arg)
  297. }
  298. /// Get the current value of a local by its local number. Can only be executed from inside a control method.
  299. pub(crate) fn local(&self, local: LocalNum) -> Result<&AmlValue, AmlError> {
  300. if let None = self.method_context {
  301. return Err(AmlError::NotExecutingControlMethod);
  302. }
  303. if local > 7 {
  304. return Err(AmlError::InvalidLocalAccess(local));
  305. }
  306. self.method_context.as_ref().unwrap().locals[local as usize]
  307. .as_ref()
  308. .ok_or(AmlError::InvalidLocalAccess(local))
  309. }
  310. /// Perform a store into a `Target`, according to the rules specified by §19.3.5.8. This returns a value read
  311. /// out of the target, if neccessary, as values can be altered during a store in some circumstances. When
  312. /// required, this also performs required implicit conversions, otherwise stores are semantically equivalent to
  313. /// a `CopyObject`.
  314. pub(crate) fn store(&mut self, target: Target, value: AmlValue) -> Result<AmlValue, AmlError> {
  315. match target {
  316. Target::Name(ref path) => {
  317. let (_, handle) = self.namespace.search(path, &self.current_scope)?;
  318. match self.namespace.get(handle).unwrap().type_of() {
  319. AmlType::FieldUnit => {
  320. let mut field = self.namespace.get(handle).unwrap().clone();
  321. field.write_field(value, self)?;
  322. field.read_field(self)
  323. }
  324. AmlType::BufferField => {
  325. let mut buffer_field = self.namespace.get(handle).unwrap().clone();
  326. buffer_field.write_buffer_field(value.clone(), self)?;
  327. Ok(value)
  328. }
  329. typ => {
  330. *self.namespace.get_mut(handle)? = value.as_type(typ, self)?;
  331. Ok(self.namespace.get(handle)?.clone())
  332. }
  333. }
  334. }
  335. Target::Debug => {
  336. // TODO
  337. unimplemented!()
  338. }
  339. Target::Arg(arg_num) => {
  340. if let None = self.method_context {
  341. return Err(AmlError::NotExecutingControlMethod);
  342. }
  343. /*
  344. * Stores into `Arg` objects are simply copied with no conversion applied, unless the `Arg`
  345. * contains an Object Reference, in which case an automatic de-reference occurs and the object is
  346. * copied to the target of the Object Reference, instead of overwriting the `Arg.`
  347. */
  348. // TODO: implement behaviour for object references
  349. self.method_context.as_mut().unwrap().args.store_arg(arg_num, value.clone())?;
  350. Ok(value)
  351. }
  352. Target::Local(local_num) => {
  353. if let None = self.method_context {
  354. return Err(AmlError::NotExecutingControlMethod);
  355. }
  356. /*
  357. * Stores into `Local` objects are always simply copied into the destination with no conversion
  358. * applied, even if it contains an Object Reference.
  359. */
  360. self.method_context.as_mut().unwrap().locals[local_num as usize] = Some(value.clone());
  361. Ok(value)
  362. }
  363. Target::Null => Ok(value),
  364. }
  365. }
  366. fn add_predefined_objects(&mut self) {
  367. /*
  368. * These are the scopes predefined by the spec. Some tables will try to access them without defining them
  369. * themselves, and so we have to pre-create them.
  370. */
  371. self.namespace.add_level(AmlName::from_str("\\_GPE").unwrap(), LevelType::Scope).unwrap();
  372. self.namespace.add_level(AmlName::from_str("\\_SB").unwrap(), LevelType::Scope).unwrap();
  373. self.namespace.add_level(AmlName::from_str("\\_SI").unwrap(), LevelType::Scope).unwrap();
  374. self.namespace.add_level(AmlName::from_str("\\_PR").unwrap(), LevelType::Scope).unwrap();
  375. self.namespace.add_level(AmlName::from_str("\\_TZ").unwrap(), LevelType::Scope).unwrap();
  376. /*
  377. * In the dark ages of ACPI 1.0, before `\_OSI`, `\_OS` was used to communicate to the firmware which OS
  378. * was running. This was predictably not very good, and so was replaced in ACPI 3.0 with `_OSI`, which
  379. * allows support for individual capabilities to be queried. `_OS` should not be used by modern firmwares,
  380. * but to avoid problems we follow Linux in returning `"Microsoft Windows NT"`.
  381. *
  382. * See https://www.kernel.org/doc/html/latest/firmware-guide/acpi/osi.html for more information.
  383. */
  384. self.namespace
  385. .add_value(AmlName::from_str("\\_OS").unwrap(), AmlValue::String("Microsoft Windows NT".to_string()))
  386. .unwrap();
  387. /*
  388. * `\_OSI` was introduced by ACPI 3.0 to improve the situation created by `\_OS`. Unfortunately, exactly
  389. * the same problem was immediately repeated by introducing capabilities reflecting that an ACPI
  390. * implementation is exactly the same as a particular version of Windows' (e.g. firmwares will call
  391. * `\_OSI("Windows 2001")`).
  392. *
  393. * We basically follow suit with whatever Linux does, as this will hopefully minimise breakage:
  394. * - We always claim `Windows *` compatability
  395. * - We answer 'yes' to `_OSI("Darwin")
  396. * - We answer 'no' to `_OSI("Linux")`, and report that the tables are doing the wrong thing
  397. */
  398. self.namespace
  399. .add_value(
  400. AmlName::from_str("\\_OSI").unwrap(),
  401. AmlValue::native_method(1, false, 0, |context| {
  402. let value = context.current_arg(0)?.clone();
  403. Ok(match value.as_string(context)?.as_str() {
  404. "Windows 2000" => true, // 2000
  405. "Windows 2001" => true, // XP
  406. "Windows 2001 SP1" => true, // XP SP1
  407. "Windows 2001 SP2" => true, // XP SP2
  408. "Windows 2001.1" => true, // Server 2003
  409. "Windows 2001.1 SP1" => true, // Server 2003 SP1
  410. "Windows 2006" => true, // Vista
  411. "Windows 2006 SP1" => true, // Vista SP1
  412. "Windows 2006 SP2" => true, // Vista SP2
  413. "Windows 2006.1" => true, // Server 2008
  414. "Windows 2009" => true, // 7 and Server 2008 R2
  415. "Windows 2012" => true, // 8 and Server 2012
  416. "Windows 2013" => true, // 8.1 and Server 2012 R2
  417. "Windows 2015" => true, // 10
  418. "Windows 2016" => true, // 10 version 1607
  419. "Windows 2017" => true, // 10 version 1703
  420. "Windows 2017.2" => true, // 10 version 1709
  421. "Windows 2018" => true, // 10 version 1803
  422. "Windows 2018.2" => true, // 10 version 1809
  423. "Windows 2019" => true, // 10 version 1903
  424. "Darwin" => true,
  425. "Linux" => {
  426. // TODO: should we allow users to specify that this should be true? Linux has a
  427. // command line option for this.
  428. warn!("ACPI evaluated `_OSI(\"Linux\")`. This is a bug. Reporting no support.");
  429. false
  430. }
  431. "Extended Address Space Descriptor" => true,
  432. // TODO: support module devices
  433. "Module Device" => false,
  434. "3.0 Thermal Model" => true,
  435. "3.0 _SCP Extensions" => true,
  436. // TODO: support processor aggregator devices
  437. "Processor Aggregator Device" => false,
  438. _ => false,
  439. }
  440. .then_some(AmlValue::ones())
  441. .unwrap_or(AmlValue::zero()))
  442. }),
  443. )
  444. .unwrap();
  445. /*
  446. * `\_REV` evaluates to the version of the ACPI specification supported by this interpreter. Linux did this
  447. * correctly until 2015, but firmwares misused this to detect Linux (as even modern versions of Windows
  448. * return `2`), and so they switched to just returning `2` (as we'll also do). `_REV` should be considered
  449. * useless and deprecated (this is mirrored in newer specs, which claim `2` means "ACPI 2 or greater").
  450. */
  451. self.namespace.add_value(AmlName::from_str("\\_REV").unwrap(), AmlValue::Integer(2)).unwrap();
  452. }
  453. }
  454. /// Trait type used by [`AmlContext`] to handle reading and writing to various types of memory in the system.
  455. pub trait Handler: Send + Sync {
  456. fn read_u8(&self, address: usize) -> u8;
  457. fn read_u16(&self, address: usize) -> u16;
  458. fn read_u32(&self, address: usize) -> u32;
  459. fn read_u64(&self, address: usize) -> u64;
  460. fn write_u8(&mut self, address: usize, value: u8);
  461. fn write_u16(&mut self, address: usize, value: u16);
  462. fn write_u32(&mut self, address: usize, value: u32);
  463. fn write_u64(&mut self, address: usize, value: u64);
  464. fn read_io_u8(&self, port: u16) -> u8;
  465. fn read_io_u16(&self, port: u16) -> u16;
  466. fn read_io_u32(&self, port: u16) -> u32;
  467. fn write_io_u8(&self, port: u16, value: u8);
  468. fn write_io_u16(&self, port: u16, value: u16);
  469. fn write_io_u32(&self, port: u16, value: u32);
  470. fn read_pci_u8(&self, segment: u16, bus: u8, device: u8, function: u8, offset: u16) -> u8;
  471. fn read_pci_u16(&self, segment: u16, bus: u8, device: u8, function: u8, offset: u16) -> u16;
  472. fn read_pci_u32(&self, segment: u16, bus: u8, device: u8, function: u8, offset: u16) -> u32;
  473. fn write_pci_u8(&self, segment: u16, bus: u8, device: u8, function: u8, offset: u16, value: u8);
  474. fn write_pci_u16(&self, segment: u16, bus: u8, device: u8, function: u8, offset: u16, value: u16);
  475. fn write_pci_u32(&self, segment: u16, bus: u8, device: u8, function: u8, offset: u16, value: u32);
  476. /// Stall for at least the given number of **microseconds**. An implementation should not relinquish control of
  477. /// the processor during the stall, and for this reason, firmwares should not stall for periods of more than
  478. /// 100 microseconds.
  479. fn stall(&self, microseconds: u64);
  480. /// Sleep for at least the given number of **milliseconds**. An implementation may round to the closest sleep
  481. /// time supported, and should relinquish the processor.
  482. fn sleep(&self, milliseconds: u64);
  483. fn handle_fatal_error(&self, fatal_type: u8, fatal_code: u32, fatal_arg: u64) {
  484. panic!("Fatal error while executing AML (encountered DefFatal op). fatal_type = {:?}, fatal_code = {:?}, fatal_arg = {:?}", fatal_type, fatal_code, fatal_arg);
  485. }
  486. }
  487. /// Used when an [`AmlContext`] encounters an error.
  488. #[derive(Clone, PartialEq, Eq, Debug)]
  489. pub enum AmlError {
  490. /*
  491. * Errors produced parsing the AML stream.
  492. */
  493. UnexpectedEndOfStream,
  494. UnexpectedByte(u8),
  495. /// Produced when the stream evaluates to something other than nothing or an error.
  496. MalformedStream,
  497. InvalidNameSeg,
  498. InvalidPkgLength,
  499. /// Invalid PkgLength relative to an OperationRegion
  500. InvalidRegionPkgLength {
  501. region_bit_length: u64,
  502. raw_length: u32,
  503. },
  504. InvalidFieldFlags,
  505. UnterminatedStringConstant,
  506. InvalidStringConstant,
  507. InvalidRegionSpace(u8),
  508. /// Produced when a `DefPackage` contains a different number of elements to the package's length.
  509. MalformedPackage,
  510. /// Produced when a `DefBuffer` contains more bytes that its size.
  511. MalformedBuffer,
  512. /// Emitted by a parser when it's clear that the stream doesn't encode the object parsed by
  513. /// that parser (e.g. the wrong opcode starts the stream). This is handled specially by some
  514. /// parsers such as `or` and `choice!`.
  515. WrongParser,
  516. /// Returned when a `DefFatal` op is encountered. This is separately reported using [`Handler::handle_fatal_error`].
  517. FatalError,
  518. /*
  519. * Errors produced manipulating AML names.
  520. */
  521. EmptyNamesAreInvalid,
  522. /// Produced when trying to normalize a path that does not point to a valid level of the
  523. /// namespace. E.g. `\_SB.^^PCI0` goes above the root of the namespace. The contained value is the name that
  524. /// normalization was attempted upon.
  525. InvalidNormalizedName(AmlName),
  526. RootHasNoParent,
  527. /*
  528. * Errors produced working with the namespace.
  529. */
  530. /// Produced when a sub-level or value is added to a level that has not yet been added to the namespace. The
  531. /// `AmlName` is the name of the entire sub-level/value.
  532. LevelDoesNotExist(AmlName),
  533. ValueDoesNotExist(AmlName),
  534. /// Produced when two values with the same name are added to the namespace.
  535. NameCollision(AmlName),
  536. TriedToRemoveRootNamespace,
  537. /*
  538. * Errors produced executing control methods.
  539. */
  540. /// Produced when AML tries to do something only possible in a control method (e.g. read from an argument)
  541. /// when there's no control method executing.
  542. NotExecutingControlMethod,
  543. /// Produced when a method accesses an argument it does not have (e.g. a method that takes 2
  544. /// arguments accesses `Arg4`). The inner value is the number of the argument accessed.
  545. InvalidArgAccess(ArgNum),
  546. /// Produced when a method accesses a local that it has not stored into.
  547. InvalidLocalAccess(LocalNum),
  548. /// Tried to invoke a method with too many arguments.
  549. TooManyArgs,
  550. /// A `DefBreak` operation was performed outside of a `DefWhile` or `DefSwitch`.
  551. BreakInInvalidPosition,
  552. /// A `DefContinue` operation was performed outside of a `DefWhile`.
  553. ContinueInInvalidPosition,
  554. /*
  555. * Errors produced parsing the PCI routing tables (_PRT objects).
  556. */
  557. PrtInvalidAddress,
  558. PrtInvalidPin,
  559. PrtInvalidSource,
  560. PrtInvalidGsi,
  561. /// Produced when the PRT doesn't contain an entry for the requested address + pin
  562. PrtNoEntry,
  563. /*
  564. * Errors produced parsing Resource Descriptors.
  565. */
  566. ReservedResourceType,
  567. ResourceDescriptorTooShort,
  568. ResourceDescriptorTooLong,
  569. UnexpectedResourceType,
  570. /*
  571. * Errors produced working with AML values.
  572. */
  573. IncompatibleValueConversion {
  574. current: AmlType,
  575. target: AmlType,
  576. },
  577. InvalidStatusObject,
  578. InvalidShiftLeft,
  579. InvalidShiftRight,
  580. FieldRegionIsNotOpRegion,
  581. FieldInvalidAddress,
  582. FieldInvalidAccessSize,
  583. TypeCannotBeCompared(AmlType),
  584. /// Produced when the `Mid` operator is applied to a value of a type other than `Buffer` or `String`.
  585. TypeCannotBeSliced(AmlType),
  586. TypeCannotBeWrittenToBufferField(AmlType),
  587. BufferFieldIndexesOutOfBounds,
  588. InvalidSizeOfApplication(AmlType),
  589. /// Unimplemented functionality - return error rather than abort
  590. Unimplemented,
  591. }
  592. #[cfg(test)]
  593. mod tests {
  594. use super::*;
  595. #[test]
  596. fn test_send_sync() {
  597. // verify that AmlContext implements Send and Sync
  598. fn test_send_sync<T: Send + Sync>() {}
  599. test_send_sync::<AmlContext>();
  600. }
  601. }