Browse Source

Parse DefMethod

This just extracts the information needed to add it to the namespace and
progress with the parse. It does not actually parse the contents of the
method, as this only needs to be done if we want to execute it.
Isaac Woods 5 years ago
parent
commit
206de53042

+ 0 - 1
aml_parser/src/lib.rs

@@ -50,7 +50,6 @@ impl AmlContext {
             return Err(AmlError::UnexpectedEndOfStream);
         }
 
-
         let table_length = PkgLength::from_raw_length(stream, stream.len() as u32) as PkgLength;
         match term_object::term_list(table_length).parse(stream, self) {
             Ok(_) => Ok(()),

+ 14 - 4
aml_parser/src/parser.rs

@@ -1,4 +1,4 @@
-use crate::{AmlContext, AmlError};
+use crate::{pkg_length::PkgLength, AmlContext, AmlError};
 use alloc::vec::Vec;
 use core::marker::PhantomData;
 use log::trace;
@@ -138,20 +138,30 @@ where
     }
 }
 
-pub fn take_n<'a, 'c>(n: usize) -> impl Parser<'a, 'c, &'a [u8]>
+pub fn take_n<'a, 'c>(n: u32) -> impl Parser<'a, 'c, &'a [u8]>
 where
     'c: 'a,
 {
     move |input: &'a [u8], context| {
-        if input.len() < n {
+        if (input.len() as u32) < n {
             return Err((input, context, AmlError::UnexpectedEndOfStream));
         }
 
-        let (result, new_input) = input.split_at(n);
+        let (result, new_input) = input.split_at(n as usize);
         Ok((new_input, context, result))
     }
 }
 
+pub fn take_to_end_of_pkglength<'a, 'c>(length: PkgLength) -> impl Parser<'a, 'c, &'a [u8]>
+where
+    'c: 'a,
+{
+    move |input: &'a [u8], context| {
+        let bytes_to_take = (input.len() as u32) - length.end_offset;
+        take_n(bytes_to_take).parse(input, context)
+    }
+}
+
 // TODO: can we use const generics (e.g. [R; N]) to avoid allocating?
 pub fn n_of<'a, 'c, P, R>(parser: P, n: usize) -> impl Parser<'a, 'c, Vec<R>>
 where

+ 1 - 1
aml_parser/src/pkg_length.rs

@@ -64,7 +64,7 @@ where
         }
 
         let (new_input, context, length): (&[u8], &mut AmlContext, u32) =
-            match take_n(byte_count as usize).parse(new_input, context) {
+            match take_n(byte_count as u32).parse(new_input, context) {
                 Ok((new_input, context, bytes)) => {
                     let initial_length = u32::from(lead_byte.get_bits(0..4));
                     (

+ 61 - 3
aml_parser/src/term_object.rs

@@ -1,7 +1,17 @@
 use crate::{
     name_object::{name_seg, name_string},
     opcode::{self, ext_opcode, opcode},
-    parser::{choice, comment_scope, take, take_u16, take_u32, take_u64, ParseResult, Parser},
+    parser::{
+        choice,
+        comment_scope,
+        take,
+        take_to_end_of_pkglength,
+        take_u16,
+        take_u32,
+        take_u64,
+        ParseResult,
+        Parser,
+    },
     pkg_length::{pkg_length, PkgLength},
     value::{AmlValue, FieldFlags},
     AmlContext,
@@ -30,7 +40,6 @@ where
     }
 }
 
-// TODO: maybe return `AmlValue` on success
 pub fn term_object<'a, 'c>() -> impl Parser<'a, 'c, ()>
 where
     'c: 'a,
@@ -39,7 +48,23 @@ where
      * TermObj := NamespaceModifierObj | NamedObj | Type1Opcode | Type2Opcode
      * NamespaceModifierObj := DefAlias | DefName | DefScope
      */
-    comment_scope("TermObj", choice!(def_scope(), def_op_region(), def_field()))
+    comment_scope("TermObj", choice!(def_scope(), named_obj()))
+}
+
+pub fn named_obj<'a, 'c>() -> impl Parser<'a, 'c, ()>
+where
+    'c: 'a,
+{
+    /*
+     * NamedObj := DefBankField | DefCreateBitField | DefCreateByteField | DefCreateDWordField |
+     *             DefCreateField | DefCreateQWordField | DefCreateWordField | DefDataRegion |
+     *             DefExternal | DefOpRegion | DefPowerRes | DefProcessor | DefThermalZone |
+     *             DefMethod | DefMutex
+     *
+     * XXX: DefMethod and DefMutex (at least) are not included in any rule in the AML grammar,
+     * but are defined in the NamedObj section so we assume they're part of NamedObj
+     */
+    comment_scope("NamedObj", choice!(def_op_region(), def_field(), def_method()))
 }
 
 pub fn def_scope<'a, 'c>() -> impl Parser<'a, 'c, ()>
@@ -174,6 +199,39 @@ where
     choice!(reserved_field, access_field, named_field)
 }
 
+pub fn def_method<'a, 'c>() -> impl Parser<'a, 'c, ()>
+where
+    'c: 'a,
+{
+    /*
+     * DefMethod := 0x14 PkgLength NameString MethodFlags TermList
+     * MethodFlags := ByteData (where bits 0-2: ArgCount (0 to 7)
+     *                                bit 3: SerializeFlag (0 = Not Serialized, 1 = Serialized)
+     *                                bits 4-7: SyncLevel (0x00 to 0x0f))
+     */
+    opcode(opcode::METHOD_OP)
+        .then(comment_scope(
+            "DefMethod",
+            pkg_length()
+                .then(name_string())
+                .then(take())
+                .feed(|((length, name), flags)| {
+                    take_to_end_of_pkglength(length).map(move |code| (name.clone(), flags, code))
+                })
+                .map_with_context(|(name, flags, code), context| {
+                    // TODO: put it in the namespace
+                    trace!(
+                        "Method with name {} with flags {:#b}, length = {}",
+                        name,
+                        flags,
+                        code.len()
+                    );
+                    ((), context)
+                }),
+        ))
+        .discard_result()
+}
+
 pub fn term_arg<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
 where
     'c: 'a,

+ 22 - 0
aml_parser/src/value.rs

@@ -68,6 +68,28 @@ impl FieldFlags {
         }
     }
 }
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub struct MethodFlags(u8);
+
+impl MethodFlags {
+    pub fn new(value: u8) -> MethodFlags {
+        MethodFlags(value)
+    }
+
+    pub fn arg_count(&self) -> u8 {
+        self.0.get_bits(0..3)
+    }
+
+    pub fn serialize(&self) -> bool {
+        self.0.get_bit(3)
+    }
+
+    pub fn sync_level(&self) -> u8 {
+        self.0.get_bits(4..8)
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub enum AmlValue {
     Integer(u64),