2
0
Эх сурвалжийг харах

Switch locals and args to being stored in arrays

Isaac Woods 3 жил өмнө
parent
commit
c1597aba3d
3 өөрчлөгдсөн 61 нэмэгдсэн , 99 устгасан
  1. 32 62
      aml/src/lib.rs
  2. 2 1
      aml/src/type2.rs
  3. 27 36
      aml/src/value.rs

+ 32 - 62
aml/src/lib.rs

@@ -91,19 +91,9 @@ pub enum DebugVerbosity {
 }
 
 struct MethodContext {
-    /*
-     * AML local variables. These are used when we invoke a control method. A `None` value
-     * represents a null AML object.
-     */
-    local_0: Option<AmlValue>,
-    local_1: Option<AmlValue>,
-    local_2: Option<AmlValue>,
-    local_3: Option<AmlValue>,
-    local_4: Option<AmlValue>,
-    local_5: Option<AmlValue>,
-    local_6: Option<AmlValue>,
-    local_7: Option<AmlValue>,
-
+    /// AML local variables. These are used when we invoke a control method. A `None` value represents a null AML
+    /// object.
+    locals: [Option<AmlValue>; 8],
     /// If we're currently invoking a control method, this stores the arguments that were passed to
     /// it. It's `None` if we aren't invoking a method.
     args: Args,
@@ -111,17 +101,11 @@ struct MethodContext {
 
 impl MethodContext {
     fn new(args: Args) -> MethodContext {
-        MethodContext {
-            local_0: None,
-            local_1: None,
-            local_2: None,
-            local_3: None,
-            local_4: None,
-            local_5: None,
-            local_6: None,
-            local_7: None,
-            args,
-        }
+        // XXX: this is required because `Option<AmlValue>` is not `Copy`, so it can't be used to initialize an
+        // array, but consts can :(
+        const NONE_BUT_CONST: Option<AmlValue> = None;
+
+        MethodContext { locals: [NONE_BUT_CONST; 8], args }
     }
 }
 
@@ -316,23 +300,19 @@ impl AmlContext {
         if let None = self.method_context {
             return Err(AmlError::NotExecutingControlMethod);
         }
-
-        match local {
-            0 => self.method_context.as_ref().unwrap().local_0.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
-            1 => self.method_context.as_ref().unwrap().local_1.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
-            2 => self.method_context.as_ref().unwrap().local_2.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
-            3 => self.method_context.as_ref().unwrap().local_3.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
-            4 => self.method_context.as_ref().unwrap().local_4.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
-            5 => self.method_context.as_ref().unwrap().local_5.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
-            6 => self.method_context.as_ref().unwrap().local_6.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
-            7 => self.method_context.as_ref().unwrap().local_7.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
-            _ => Err(AmlError::InvalidLocalAccess(local)),
+        if local > 7 {
+            return Err(AmlError::InvalidLocalAccess(local));
         }
+
+        self.method_context.as_ref().unwrap().locals[local as usize]
+            .as_ref()
+            .ok_or(AmlError::InvalidLocalAccess(local))
     }
 
-    /// Perform a store into a `Target`. This returns a value read out of the target, if neccessary, as values can
-    /// be altered during a store in some circumstances. If the target is a `Name`, this also performs required
-    /// implicit conversions. Stores to other targets are semantically equivalent to a `CopyObject`.
+    /// Perform a store into a `Target`, according to the rules specified by §19.3.5.8. This returns a value read
+    /// out of the target, if neccessary, as values can be altered during a store in some circumstances.  When
+    /// required, this also performs required implicit conversions, otherwise stores are semantically equivalent to
+    /// a `CopyObject`.
     pub(crate) fn store(&mut self, target: Target, value: AmlValue) -> Result<AmlValue, AmlError> {
         match target {
             Target::Name(ref path) => {
@@ -365,17 +345,13 @@ impl AmlContext {
                     return Err(AmlError::NotExecutingControlMethod);
                 }
 
-                // TODO: I don't think these semantics are correct? If the arg/local is a field unit or buffer
-                // field, don't we need to do special stuff?
-                match arg_num {
-                    1 => self.method_context.as_mut().unwrap().args.arg_1 = Some(value.clone()),
-                    2 => self.method_context.as_mut().unwrap().args.arg_2 = Some(value.clone()),
-                    3 => self.method_context.as_mut().unwrap().args.arg_3 = Some(value.clone()),
-                    4 => self.method_context.as_mut().unwrap().args.arg_4 = Some(value.clone()),
-                    5 => self.method_context.as_mut().unwrap().args.arg_5 = Some(value.clone()),
-                    6 => self.method_context.as_mut().unwrap().args.arg_6 = Some(value.clone()),
-                    _ => return Err(AmlError::InvalidArgAccess(arg_num)),
-                }
+                /*
+                 * Stores into `Arg` objects are simply copied with no conversion applied, unless the `Arg`
+                 * contains an Object Reference, in which case an automatic de-reference occurs and the object is
+                 * copied to the target of the Object Reference, instead of overwriting the `Arg.`
+                 */
+                // TODO: implement behaviour for object references
+                self.method_context.as_mut().unwrap().args.store_arg(arg_num, value.clone())?;
                 Ok(value)
             }
 
@@ -384,19 +360,11 @@ impl AmlContext {
                     return Err(AmlError::NotExecutingControlMethod);
                 }
 
-                // TODO: I don't think these semantics are correct? If the arg/local is a field unit or buffer
-                // field, don't we need to do special stuff?
-                match local_num {
-                    0 => self.method_context.as_mut().unwrap().local_0 = Some(value.clone()),
-                    1 => self.method_context.as_mut().unwrap().local_1 = Some(value.clone()),
-                    2 => self.method_context.as_mut().unwrap().local_2 = Some(value.clone()),
-                    3 => self.method_context.as_mut().unwrap().local_3 = Some(value.clone()),
-                    4 => self.method_context.as_mut().unwrap().local_4 = Some(value.clone()),
-                    5 => self.method_context.as_mut().unwrap().local_5 = Some(value.clone()),
-                    6 => self.method_context.as_mut().unwrap().local_6 = Some(value.clone()),
-                    7 => self.method_context.as_mut().unwrap().local_7 = Some(value.clone()),
-                    _ => return Err(AmlError::InvalidLocalAccess(local_num)),
-                }
+                /*
+                 * Stores into `Local` objects are always simply copied into the destination with no conversion
+                 * applied, even if it contains an Object Reference.
+                 */
+                self.method_context.as_mut().unwrap().locals[local_num as usize] = Some(value.clone());
                 Ok(value)
             }
 
@@ -764,6 +732,8 @@ pub enum AmlError {
     InvalidArgAccess(ArgNum),
     /// Produced when a method accesses a local that it has not stored into.
     InvalidLocalAccess(LocalNum),
+    /// Tried to invoke a method with too many arguments.
+    TooManyArgs,
 
     /*
      * Errors produced parsing the PCI routing tables (_PRT objects).

+ 2 - 1
aml/src/type2.rs

@@ -606,7 +606,8 @@ where
             .feed(|(path, num_args)| {
                 n_of(term_arg(), num_args.unwrap_or(0) as usize).map_with_context(move |arg_list, context| {
                     if num_args.is_some() {
-                        let result = context.invoke_method(&path, Args::from_list(arg_list));
+                        let args = try_with_context!(context, Args::from_list(arg_list));
+                        let result = context.invoke_method(&path, args);
                         (Ok(try_with_context!(context, result)), context)
                     } else {
                         (Ok(try_with_context!(context, context.namespace.get_by_path(&path)).clone()), context)

+ 27 - 36
aml/src/value.rs

@@ -519,47 +519,38 @@ impl AmlValue {
     }
 }
 
-/// A control method can take up to 7 arguments, each of which can be an `AmlValue`.
-#[derive(Clone, Debug, Default)]
-pub struct Args {
-    pub arg_0: Option<AmlValue>,
-    pub arg_1: Option<AmlValue>,
-    pub arg_2: Option<AmlValue>,
-    pub arg_3: Option<AmlValue>,
-    pub arg_4: Option<AmlValue>,
-    pub arg_5: Option<AmlValue>,
-    pub arg_6: Option<AmlValue>,
-}
+/// A control method can take up to 7 arguments, each of which is an `AmlValue`.
+#[derive(Clone, Default, Debug)]
+pub struct Args(pub [Option<AmlValue>; 7]);
 
 impl Args {
-    pub fn from_list(mut list: Vec<AmlValue>) -> Args {
-        assert!(list.len() <= 7);
-        list.reverse();
-        Args {
-            arg_0: list.pop(),
-            arg_1: list.pop(),
-            arg_2: list.pop(),
-            arg_3: list.pop(),
-            arg_4: list.pop(),
-            arg_5: list.pop(),
-            arg_6: list.pop(),
+    pub fn from_list(list: Vec<AmlValue>) -> Result<Args, AmlError> {
+        use core::convert::TryInto;
+
+        if list.len() > 7 {
+            return Err(AmlError::TooManyArgs);
         }
+
+        let mut args: Vec<Option<AmlValue>> = list.into_iter().map(Option::Some).collect();
+        args.extend(core::iter::repeat(None).take(7 - args.len()));
+        Ok(Args(args.try_into().unwrap()))
     }
-    /// Get an argument by its `ArgNum`.
-    ///
-    /// ### Panics
-    /// Panics if passed an invalid argument number (valid argument numbers are `0..=6`)
-    pub fn arg(&self, num: ArgNum) -> Result<&AmlValue, AmlError> {
-        match num {
-            0 => self.arg_0.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
-            1 => self.arg_1.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
-            2 => self.arg_2.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
-            3 => self.arg_3.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
-            4 => self.arg_4.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
-            5 => self.arg_5.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
-            6 => self.arg_6.as_ref().ok_or(AmlError::InvalidArgAccess(num)),
-            _ => Err(AmlError::InvalidArgAccess(num)),
+
+    pub fn arg(&self, arg: ArgNum) -> Result<&AmlValue, AmlError> {
+        if arg > 6 {
+            return Err(AmlError::InvalidArgAccess(arg));
         }
+
+        self.0[arg as usize].as_ref().ok_or(AmlError::InvalidArgAccess(arg))
+    }
+
+    pub fn store_arg(&mut self, arg: ArgNum, value: AmlValue) -> Result<(), AmlError> {
+        if arg > 6 {
+            return Err(AmlError::InvalidArgAccess(arg));
+        }
+
+        self.0[arg as usize] = Some(value);
+        Ok(())
     }
 }