|
@@ -1,12 +1,22 @@
|
|
|
use crate::{
|
|
|
name_object::{name_string, super_name, Target},
|
|
|
opcode::{self, opcode},
|
|
|
- parser::{choice, comment_scope, comment_scope_verbose, id, try_with_context, Parser},
|
|
|
- term_object::term_arg,
|
|
|
+ parser::{
|
|
|
+ choice,
|
|
|
+ comment_scope,
|
|
|
+ comment_scope_verbose,
|
|
|
+ id,
|
|
|
+ take,
|
|
|
+ take_to_end_of_pkglength,
|
|
|
+ try_with_context,
|
|
|
+ Parser,
|
|
|
+ },
|
|
|
+ pkg_length::pkg_length,
|
|
|
+ term_object::{data_ref_object, term_arg},
|
|
|
value::AmlValue,
|
|
|
AmlError,
|
|
|
};
|
|
|
-use alloc::boxed::Box;
|
|
|
+use alloc::{boxed::Box, vec::Vec};
|
|
|
|
|
|
/// Type 2 opcodes return a value and so can be used in expressions.
|
|
|
pub fn type2_opcode<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
|
|
@@ -24,7 +34,33 @@ where
|
|
|
* DefSubtract | DefTimer | DefToBCD | DefToBuffer | DefToDecimalString |
|
|
|
* DefToHexString | DefToInteger | DefToString | DefWait | DefXOr | MethodInvocation
|
|
|
*/
|
|
|
- comment_scope_verbose("Type2Opcode", choice!(def_l_equal(), def_store(), method_invocation()))
|
|
|
+ comment_scope_verbose(
|
|
|
+ "Type2Opcode",
|
|
|
+ choice!(def_buffer(), def_l_equal(), def_package(), def_store(), method_invocation()),
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+pub fn def_buffer<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
|
|
|
+where
|
|
|
+ 'c: 'a,
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * DefBuffer := 0x11 PkgLength BufferSize ByteList
|
|
|
+ * BufferSize := TermArg => Integer
|
|
|
+ *
|
|
|
+ * XXX: The spec says that zero-length buffers (e.g. the PkgLength is 0) are illegal, but
|
|
|
+ * we've encountered them in QEMU-generated tables, so we return an empty buffer in these
|
|
|
+ * cases.
|
|
|
+ */
|
|
|
+ opcode(opcode::DEF_BUFFER_OP)
|
|
|
+ .then(comment_scope(
|
|
|
+ "DefBuffer",
|
|
|
+ pkg_length().then(term_arg()).feed(|(pkg_length, buffer_size)| {
|
|
|
+ take_to_end_of_pkglength(pkg_length)
|
|
|
+ .map(move |bytes| Ok((bytes.to_vec(), buffer_size.as_integer()?)))
|
|
|
+ }),
|
|
|
+ ))
|
|
|
+ .map(|((), (bytes, buffer_size))| Ok(AmlValue::Buffer { bytes, size: buffer_size }))
|
|
|
}
|
|
|
|
|
|
fn def_l_equal<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
|
|
@@ -45,6 +81,46 @@ where
|
|
|
.map(|((), result)| Ok(result))
|
|
|
}
|
|
|
|
|
|
+pub fn def_package<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
|
|
|
+where
|
|
|
+ 'c: 'a,
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * DefPackage := 0x12 PkgLength NumElements PackageElementList
|
|
|
+ * NumElements := ByteData
|
|
|
+ * PackageElementList := Nothing | <PackageElement PackageElementList>
|
|
|
+ * PackageElement := DataRefObject | NameString
|
|
|
+ */
|
|
|
+ opcode(opcode::DEF_PACKAGE_OP)
|
|
|
+ .then(comment_scope(
|
|
|
+ "DefPackage",
|
|
|
+ pkg_length().then(take()).feed(|(pkg_length, num_elements)| {
|
|
|
+ move |mut input, mut context| {
|
|
|
+ let mut package_contents = Vec::new();
|
|
|
+
|
|
|
+ while pkg_length.still_parsing(input) {
|
|
|
+ let (new_input, new_context, value) = package_element().parse(input, context)?;
|
|
|
+ input = new_input;
|
|
|
+ context = new_context;
|
|
|
+
|
|
|
+ package_contents.push(value);
|
|
|
+ }
|
|
|
+
|
|
|
+ assert_eq!(package_contents.len(), num_elements as usize);
|
|
|
+ Ok((input, context, AmlValue::Package(package_contents)))
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ ))
|
|
|
+ .map(|((), package)| Ok(package))
|
|
|
+}
|
|
|
+
|
|
|
+pub fn package_element<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
|
|
|
+where
|
|
|
+ 'c: 'a,
|
|
|
+{
|
|
|
+ choice!(data_ref_object(), name_string().map(|string| Ok(AmlValue::String(string.as_string()))))
|
|
|
+}
|
|
|
+
|
|
|
fn def_store<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
|
|
|
where
|
|
|
'c: 'a,
|