type2.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. use crate::{
  2. name_object::{name_string, super_name, target},
  3. opcode::{self, opcode},
  4. parser::{
  5. choice,
  6. comment_scope,
  7. make_parser_concrete,
  8. n_of,
  9. take,
  10. take_to_end_of_pkglength,
  11. try_with_context,
  12. Parser,
  13. },
  14. pkg_length::pkg_length,
  15. term_object::{data_ref_object, term_arg},
  16. value::{AmlValue, Args},
  17. AmlError,
  18. DebugVerbosity,
  19. };
  20. use alloc::vec::Vec;
  21. use core::convert::TryInto;
  22. /// Type 2 opcodes return a value and so can be used in expressions.
  23. pub fn type2_opcode<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  24. where
  25. 'c: 'a,
  26. {
  27. /*
  28. * Type2Opcode := DefAquire | DefAdd | DefAnd | DefBuffer | DefConcat | DefConcatRes |
  29. * DefCondRefOf | DefCopyObject | DefDecrement | DefDerefOf | DefDivide |
  30. * DefFindSetLeftBit | DefFindSetRightBit | DefFromBCD | DefIncrement | DefIndex |
  31. * DefLAnd | DefLEqual | DefLGreater | DefLGreaterEqual | DefLLess | DefLLessEqual |
  32. * DefMid | DefLNot | DefLNotEqual | DefLoadTable | DefLOr | DefMatch | DefMod |
  33. * DefMultiply | DefNAnd | DefNOr | DefNot | DefObjectType | DefOr | DefPackage |
  34. * DefVarPackage | DefRefOf | DefShiftLeft | DefShitRight | DefSizeOf | DefStore |
  35. * DefSubtract | DefTimer | DefToBCD | DefToBuffer | DefToDecimalString |
  36. * DefToHexString | DefToInteger | DefToString | DefWait | DefXOr | MethodInvocation
  37. *
  38. * NOTE: MethodInvocation should always appear last in the choice.
  39. */
  40. make_parser_concrete!(comment_scope(
  41. DebugVerbosity::AllScopes,
  42. "Type2Opcode",
  43. choice!(
  44. def_and(),
  45. def_buffer(),
  46. def_l_equal(),
  47. def_l_or(),
  48. def_package(),
  49. def_shift_left(),
  50. def_shift_right(),
  51. def_store(),
  52. method_invocation()
  53. ),
  54. ))
  55. }
  56. pub fn def_and<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  57. where
  58. 'c: 'a,
  59. {
  60. /*
  61. * DefAnd := 0x7b Operand Operand Target
  62. * Operand := TermArg => Integer
  63. */
  64. opcode(opcode::DEF_AND_OP)
  65. .then(comment_scope(
  66. DebugVerbosity::AllScopes,
  67. "DefAnd",
  68. term_arg().then(term_arg()).then(target()).map_with_context(
  69. |((left_arg, right_arg), target), context| {
  70. let left = try_with_context!(context, left_arg.as_integer(context));
  71. let right = try_with_context!(context, right_arg.as_integer(context));
  72. (Ok(AmlValue::Integer(left & right)), context)
  73. },
  74. ),
  75. ))
  76. .map(|((), result)| Ok(result))
  77. }
  78. pub fn def_buffer<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  79. where
  80. 'c: 'a,
  81. {
  82. /*
  83. * DefBuffer := 0x11 PkgLength BufferSize ByteList
  84. * BufferSize := TermArg => Integer
  85. *
  86. * XXX: The spec says that zero-length buffers (e.g. the PkgLength is 0) are illegal, but
  87. * we've encountered them in QEMU-generated tables, so we return an empty buffer in these
  88. * cases.
  89. */
  90. opcode(opcode::DEF_BUFFER_OP)
  91. .then(comment_scope(
  92. DebugVerbosity::AllScopes,
  93. "DefBuffer",
  94. pkg_length().then(term_arg()).feed(|(pkg_length, buffer_size)| {
  95. take_to_end_of_pkglength(pkg_length).map_with_context(move |bytes, context| {
  96. let length = try_with_context!(context, buffer_size.as_integer(context));
  97. (Ok((bytes.to_vec(), length)), context)
  98. })
  99. }),
  100. ))
  101. .map(|((), (bytes, buffer_size))| Ok(AmlValue::Buffer { bytes, size: buffer_size }))
  102. }
  103. fn def_l_or<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  104. where
  105. 'c: 'a,
  106. {
  107. /*
  108. * DefLOr := 0x91 Operand Operand
  109. * Operand := TermArg => Integer
  110. */
  111. opcode(opcode::DEF_L_OR_OP)
  112. .then(comment_scope(
  113. DebugVerbosity::AllScopes,
  114. "DefLOr",
  115. term_arg().then(term_arg()).map_with_context(|(left_arg, right_arg), context| {
  116. let left = try_with_context!(context, left_arg.as_bool());
  117. let right = try_with_context!(context, right_arg.as_bool());
  118. (Ok(AmlValue::Boolean(left || right)), context)
  119. }),
  120. ))
  121. .map(|((), result)| Ok(result))
  122. }
  123. fn def_l_equal<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  124. where
  125. 'c: 'a,
  126. {
  127. /*
  128. * DefLEqual := 0x93 Operand Operand
  129. * Operand := TermArg => Integer
  130. */
  131. opcode(opcode::DEF_L_EQUAL_OP)
  132. .then(comment_scope(
  133. DebugVerbosity::AllScopes,
  134. "DefLEqual",
  135. term_arg().then(term_arg()).map_with_context(|(left_arg, right_arg), context| {
  136. /*
  137. * TODO: we should also be able to compare strings and buffers. `left_arg` decides the type that we
  138. * need to use - we have to try and convert `right_arg` into that type and then compare them in the
  139. * correct way.
  140. */
  141. let left = try_with_context!(context, left_arg.as_integer(context));
  142. let right = try_with_context!(context, right_arg.as_integer(context));
  143. (Ok(AmlValue::Boolean(left == right)), context)
  144. }),
  145. ))
  146. .map(|((), result)| Ok(result))
  147. }
  148. pub fn def_package<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  149. where
  150. 'c: 'a,
  151. {
  152. /*
  153. * DefPackage := 0x12 PkgLength NumElements PackageElementList
  154. * NumElements := ByteData
  155. * PackageElementList := Nothing | <PackageElement PackageElementList>
  156. * PackageElement := DataRefObject | NameString
  157. */
  158. opcode(opcode::DEF_PACKAGE_OP)
  159. .then(comment_scope(
  160. DebugVerbosity::AllScopes,
  161. "DefPackage",
  162. pkg_length().then(take()).feed(|(pkg_length, num_elements)| {
  163. move |mut input, mut context| {
  164. let mut package_contents = Vec::new();
  165. while pkg_length.still_parsing(input) {
  166. let (new_input, new_context, value) = package_element().parse(input, context)?;
  167. input = new_input;
  168. context = new_context;
  169. package_contents.push(value);
  170. }
  171. assert_eq!(package_contents.len(), num_elements as usize);
  172. Ok((input, context, AmlValue::Package(package_contents)))
  173. }
  174. }),
  175. ))
  176. .map(|((), package)| Ok(package))
  177. }
  178. pub fn package_element<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  179. where
  180. 'c: 'a,
  181. {
  182. choice!(data_ref_object(), name_string().map(|string| Ok(AmlValue::String(string.as_string()))))
  183. }
  184. fn def_shift_left<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  185. where
  186. 'c: 'a,
  187. {
  188. /*
  189. * DefShiftLeft := 0x79 Operand ShiftCount Target
  190. * Operand := TermArg => Integer
  191. * ShiftCount := TermArg => Integer
  192. */
  193. opcode(opcode::DEF_SHIFT_LEFT)
  194. .then(comment_scope(DebugVerbosity::Scopes, "DefShiftLeft", term_arg().then(term_arg()).then(target())))
  195. .map_with_context(|((), ((operand, shift_count), target)), context| {
  196. let operand = try_with_context!(context, operand.as_integer(context));
  197. let shift_count = try_with_context!(context, shift_count.as_integer(context));
  198. let shift_count =
  199. try_with_context!(context, shift_count.try_into().map_err(|_| AmlError::InvalidShiftLeft));
  200. let result = AmlValue::Integer(try_with_context!(
  201. context,
  202. operand.checked_shl(shift_count).ok_or(AmlError::InvalidShiftLeft)
  203. ));
  204. try_with_context!(context, context.store(target, result.clone()));
  205. (Ok(result), context)
  206. })
  207. }
  208. fn def_shift_right<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  209. where
  210. 'c: 'a,
  211. {
  212. /*
  213. * DefShiftRight := 0x7a Operand ShiftCount Target
  214. * Operand := TermArg => Integer
  215. * ShiftCount := TermArg => Integer
  216. */
  217. opcode(opcode::DEF_SHIFT_RIGHT)
  218. .then(comment_scope(DebugVerbosity::Scopes, "DefShiftRight", term_arg().then(term_arg()).then(target())))
  219. .map_with_context(|((), ((operand, shift_count), target)), context| {
  220. let operand = try_with_context!(context, operand.as_integer(context));
  221. let shift_count = try_with_context!(context, shift_count.as_integer(context));
  222. let shift_count =
  223. try_with_context!(context, shift_count.try_into().map_err(|_| AmlError::InvalidShiftRight));
  224. let result = AmlValue::Integer(try_with_context!(
  225. context,
  226. operand.checked_shr(shift_count).ok_or(AmlError::InvalidShiftRight)
  227. ));
  228. try_with_context!(context, context.store(target, result.clone()));
  229. (Ok(result), context)
  230. })
  231. }
  232. fn def_store<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  233. where
  234. 'c: 'a,
  235. {
  236. /*
  237. * DefStore := 0x70 TermArg SuperName
  238. *
  239. * Implicit conversion is only applied when the destination target is a `Name` - not when we
  240. * are storing into a method local or argument (these stores are semantically identical to
  241. * CopyObject). We must also make sure to return a copy of the data that is in the destination
  242. * after the store (as opposed to the data we think we put into it), because some stores can
  243. * alter the data during the store.
  244. */
  245. opcode(opcode::DEF_STORE_OP)
  246. .then(comment_scope(DebugVerbosity::Scopes, "DefStore", term_arg().then(super_name())))
  247. .map_with_context(|((), (value, target)), context| {
  248. (Ok(try_with_context!(context, context.store(target, value))), context)
  249. })
  250. }
  251. fn method_invocation<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  252. where
  253. 'c: 'a,
  254. {
  255. /*
  256. * MethodInvocation := NameString TermArgList
  257. *
  258. * MethodInvocation is the worst of the AML structures, because you're meant to figure out how much you're
  259. * meant to parse using the name of the method (by knowing from its definition how how many arguments it
  260. * takes). However, the definition of a method can in theory appear after an invocation of that method, and
  261. * so parsing them properly can be very difficult.
  262. * NOTE: We don't support the case of the definition appearing after the invocation.
  263. */
  264. comment_scope(
  265. DebugVerbosity::Scopes,
  266. "MethodInvocation",
  267. name_string()
  268. .map_with_context(move |name, context| {
  269. let (full_path, handle) =
  270. try_with_context!(context, context.namespace.search(&name, &context.current_scope)).clone();
  271. /*
  272. * `None` if the path is not a method and so doesn't have arguments, or `Some(the number of
  273. * arguments to parse)` if it's a method.
  274. */
  275. let num_args = if let AmlValue::Method { flags, .. } =
  276. try_with_context!(context, context.namespace.get(handle))
  277. {
  278. Some(flags.arg_count())
  279. } else {
  280. None
  281. };
  282. (Ok((full_path, num_args)), context)
  283. })
  284. .feed(|(path, num_args)| {
  285. n_of(term_arg(), num_args.unwrap_or(0) as usize).map_with_context(move |arg_list, context| {
  286. if num_args.is_some() {
  287. let result = context.invoke_method(&path, Args::from_list(arg_list));
  288. (Ok(try_with_context!(context, result)), context)
  289. } else {
  290. (Ok(try_with_context!(context, context.namespace.get_by_path(&path)).clone()), context)
  291. }
  292. })
  293. }),
  294. )
  295. }