type2.rs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. use crate::{
  2. name_object::{name_string, super_name, Target},
  3. opcode::{self, opcode},
  4. parser::{choice, comment_scope, id, take, take_to_end_of_pkglength, try_with_context, Parser},
  5. pkg_length::pkg_length,
  6. term_object::{data_ref_object, term_arg},
  7. value::AmlValue,
  8. AmlError,
  9. DebugVerbosity,
  10. };
  11. use alloc::vec::Vec;
  12. /// Type 2 opcodes return a value and so can be used in expressions.
  13. pub fn type2_opcode<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  14. where
  15. 'c: 'a,
  16. {
  17. /*
  18. * Type2Opcode := DefAquire | DefAdd | DefAnd | DefBuffer | DefConcat | DefConcatRes |
  19. * DefCondRefOf | DefCopyObject | DefDecrement | DefDerefOf | DefDivide |
  20. * DefFindSetLeftBit | DefFindSetRightBit | DefFromBCD | DefIncrement | DefIndex |
  21. * DefLAnd | DefLEqual | DefLGreater | DefLGreaterEqual | DefLLess | DefLLessEqual |
  22. * DefMid | DefLNot | DefLNotEqual | DefLoadTable | DefLOr | DefMatch | DefMod |
  23. * DefMultiply | DefNAnd | DefNOr | DefNot | DefObjectType | DefOr | DefPackage |
  24. * DefVarPackage | DefRefOf | DefShiftLeft | DefShitRight | DefSizeOf | DefStore |
  25. * DefSubtract | DefTimer | DefToBCD | DefToBuffer | DefToDecimalString |
  26. * DefToHexString | DefToInteger | DefToString | DefWait | DefXOr | MethodInvocation
  27. */
  28. comment_scope(
  29. DebugVerbosity::AllScopes,
  30. "Type2Opcode",
  31. choice!(def_buffer(), def_l_equal(), def_package(), def_store(), method_invocation()),
  32. )
  33. }
  34. pub fn def_buffer<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  35. where
  36. 'c: 'a,
  37. {
  38. /*
  39. * DefBuffer := 0x11 PkgLength BufferSize ByteList
  40. * BufferSize := TermArg => Integer
  41. *
  42. * XXX: The spec says that zero-length buffers (e.g. the PkgLength is 0) are illegal, but
  43. * we've encountered them in QEMU-generated tables, so we return an empty buffer in these
  44. * cases.
  45. */
  46. opcode(opcode::DEF_BUFFER_OP)
  47. .then(comment_scope(
  48. DebugVerbosity::Scopes,
  49. "DefBuffer",
  50. pkg_length().then(term_arg()).feed(|(pkg_length, buffer_size)| {
  51. take_to_end_of_pkglength(pkg_length)
  52. .map(move |bytes| Ok((bytes.to_vec(), buffer_size.as_integer()?)))
  53. }),
  54. ))
  55. .map(|((), (bytes, buffer_size))| Ok(AmlValue::Buffer { bytes, size: buffer_size }))
  56. }
  57. fn def_l_equal<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  58. where
  59. 'c: 'a,
  60. {
  61. /*
  62. * DefLEqual := 0x93 Operand Operand
  63. * Operand := TermArg => Integer
  64. */
  65. opcode(opcode::DEF_L_EQUAL_OP)
  66. .then(comment_scope(
  67. DebugVerbosity::AllScopes,
  68. "DefLEqual",
  69. term_arg().then(term_arg()).map(|(left_arg, right_arg)| {
  70. Ok(AmlValue::Boolean(left_arg.as_integer()? == right_arg.as_integer()?))
  71. }),
  72. ))
  73. .map(|((), result)| Ok(result))
  74. }
  75. pub fn def_package<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  76. where
  77. 'c: 'a,
  78. {
  79. /*
  80. * DefPackage := 0x12 PkgLength NumElements PackageElementList
  81. * NumElements := ByteData
  82. * PackageElementList := Nothing | <PackageElement PackageElementList>
  83. * PackageElement := DataRefObject | NameString
  84. */
  85. opcode(opcode::DEF_PACKAGE_OP)
  86. .then(comment_scope(
  87. DebugVerbosity::Scopes,
  88. "DefPackage",
  89. pkg_length().then(take()).feed(|(pkg_length, num_elements)| {
  90. move |mut input, mut context| {
  91. let mut package_contents = Vec::new();
  92. while pkg_length.still_parsing(input) {
  93. let (new_input, new_context, value) = package_element().parse(input, context)?;
  94. input = new_input;
  95. context = new_context;
  96. package_contents.push(value);
  97. }
  98. assert_eq!(package_contents.len(), num_elements as usize);
  99. Ok((input, context, AmlValue::Package(package_contents)))
  100. }
  101. }),
  102. ))
  103. .map(|((), package)| Ok(package))
  104. }
  105. pub fn package_element<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  106. where
  107. 'c: 'a,
  108. {
  109. choice!(data_ref_object(), name_string().map(|string| Ok(AmlValue::String(string.as_string()))))
  110. }
  111. fn def_store<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  112. where
  113. 'c: 'a,
  114. {
  115. /*
  116. * DefStore := 0x70 TermArg SuperName
  117. *
  118. * Implicit conversion is only applied when the destination target is a `Name` - not when we
  119. * are storing into a method local or argument (these stores are semantically identical to
  120. * CopyObject). We must also make sure to return a copy of the data that is in the destination
  121. * after the store (as opposed to the data we think we put into it), because some stores can
  122. * alter the data during the store.
  123. */
  124. opcode(opcode::DEF_STORE_OP)
  125. .then(comment_scope(DebugVerbosity::Scopes, "DefStore", term_arg().then(super_name())))
  126. .map_with_context(|((), (value, target)), context| {
  127. match target {
  128. Target::Name(ref path) => {
  129. let (_, handle) =
  130. try_with_context!(context, context.namespace.search(path, &context.current_scope));
  131. let desired_type = context.namespace.get(handle).unwrap().type_of();
  132. let converted_object = try_with_context!(context, value.as_type(desired_type));
  133. *try_with_context!(context, context.namespace.get_mut(handle)) = converted_object;
  134. (Ok(context.namespace.get(handle).unwrap().clone()), context)
  135. }
  136. Target::Debug => {
  137. // TODO
  138. unimplemented!()
  139. }
  140. Target::Arg(arg_num) => {
  141. // TODO
  142. unimplemented!()
  143. }
  144. Target::Local(local_num) => {
  145. // TODO
  146. unimplemented!()
  147. }
  148. }
  149. })
  150. }
  151. fn method_invocation<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
  152. where
  153. 'c: 'a,
  154. {
  155. /*
  156. * MethodInvocation := NameString TermArgList
  157. *
  158. * MethodInvocation is the worst of the AML structures, because you're meant to figure out how much you're
  159. * meant to parse using the name of the method (by knowing from its definition how how many arguments it
  160. * takes). However, the definition of a method can in theory appear after an invocation of that method, and
  161. * so parsing them properly can be very difficult.
  162. * NOTE: We don't support the case of the definition appearing after the invocation.
  163. */
  164. comment_scope(
  165. DebugVerbosity::Scopes,
  166. "MethodInvocation",
  167. name_string()
  168. .map_with_context(move |name, context| {
  169. let (_, handle) =
  170. try_with_context!(context, context.namespace.search(&name, &context.current_scope)).clone();
  171. (Ok(handle), context)
  172. })
  173. .feed(|handle| {
  174. id().map_with_context(move |(), context| {
  175. let object = try_with_context!(context, context.namespace.get(handle));
  176. if let AmlValue::Method { ref code, .. } = object {
  177. // TODO: we need to allow a method to be invoked from inside another method before we can
  178. // implement this (basically a stack of contexts) then implement this
  179. unimplemented!()
  180. } else {
  181. // We appear to be seeing AML where a MethodInvocation actually doesn't point to a method
  182. // at all, which isn't mentioned in the spec afaict. However, if we treat it as an
  183. // "invocation" with 0 arguments and simply return the object, the AML seems to do sensible
  184. // things.
  185. (Ok(object.clone()), context)
  186. }
  187. })
  188. }),
  189. )
  190. }