Browse Source

Don't complain if a method isn't actually a method

To make life easier for callers, we no longer error if you try an invoke
a method, and it turns out it's not a method, instead simply returning the
value as if it's the return value of the method.
Isaac Woods 4 years ago
parent
commit
a0971776da
1 changed files with 46 additions and 40 deletions
  1. 46 40
      aml/src/lib.rs

+ 46 - 40
aml/src/lib.rs

@@ -194,49 +194,55 @@ impl AmlContext {
     }
 
     pub fn invoke_method(&mut self, path: &AmlName, args: Args) -> Result<AmlValue, AmlError> {
-        if let AmlValue::Method { flags, code } = self.namespace.get_by_path(path)?.clone() {
-            /*
-             * First, set up the state we expect to enter the method with, but clearing local
-             * variables to "null" and setting the arguments. Save the current method state and scope, so if we're
-             * already executing another control method, we resume into it correctly.
-             */
-            let old_context = mem::replace(&mut self.method_context, Some(MethodContext::new(args)));
-            let old_scope = mem::replace(&mut self.current_scope, path.clone());
-
-            /*
-             * Create a namespace level to store local objects created by the invocation.
-             */
-            self.namespace.add_level(path.clone(), LevelType::MethodLocals)?;
-
-            log::trace!("Invoking method({}) with {} arguments, code: {:x?}", path, flags.arg_count(), code);
-            let return_value =
-                match term_list(PkgLength::from_raw_length(&code, code.len() as u32)).parse(&code, self) {
-                    // If the method doesn't return a value, we implicitly return `0`
-                    Ok(_) => Ok(AmlValue::Integer(0)),
-                    Err((_, _, AmlError::Return(result))) => Ok(result),
-                    Err((_, _, err)) => {
-                        error!("Failed to execute control method: {:?}", err);
-                        Err(err)
-                    }
-                };
-
-            /*
-             * Locally-created objects should be destroyed on method exit (see §5.5.2.3 of the ACPI spec). We do
-             * this by simply removing the method's local object layer.
-             */
-            // TODO: this should also remove objects created by the method outside the method's scope, if they
-            // weren't statically created. This is harder.
-            self.namespace.remove_level(path.clone())?;
+        match self.namespace.get_by_path(path)?.clone() {
+            AmlValue::Method { flags, code } => {
+                /*
+                 * First, set up the state we expect to enter the method with, but clearing local
+                 * variables to "null" and setting the arguments. Save the current method state and scope, so if we're
+                 * already executing another control method, we resume into it correctly.
+                 */
+                let old_context = mem::replace(&mut self.method_context, Some(MethodContext::new(args)));
+                let old_scope = mem::replace(&mut self.current_scope, path.clone());
+
+                /*
+                 * Create a namespace level to store local objects created by the invocation.
+                 */
+                self.namespace.add_level(path.clone(), LevelType::MethodLocals)?;
+
+                let return_value =
+                    match term_list(PkgLength::from_raw_length(&code, code.len() as u32)).parse(&code, self) {
+                        // If the method doesn't return a value, we implicitly return `0`
+                        Ok(_) => Ok(AmlValue::Integer(0)),
+                        Err((_, _, AmlError::Return(result))) => Ok(result),
+                        Err((_, _, err)) => {
+                            error!("Failed to execute control method: {:?}", err);
+                            Err(err)
+                        }
+                    };
+
+                /*
+                 * Locally-created objects should be destroyed on method exit (see §5.5.2.3 of the ACPI spec). We do
+                 * this by simply removing the method's local object layer.
+                 */
+                // TODO: this should also remove objects created by the method outside the method's scope, if they
+                // weren't statically created. This is harder.
+                self.namespace.remove_level(path.clone())?;
+
+                /*
+                 * Restore the old state.
+                 */
+                self.method_context = old_context;
+                self.current_scope = old_scope;
+
+                return_value
+            }
 
             /*
-             * Restore the old state.
+             * AML can encode methods that don't require any computation simply as the value that would otherwise be
+             * returned (e.g. a `_STA` object simply being an `AmlValue::Integer`, instead of a method that just
+             * returns an integer).
              */
-            self.method_context = old_context;
-            self.current_scope = old_scope;
-
-            return_value
-        } else {
-            Err(AmlError::IncompatibleValueConversion)
+            value => Ok(value),
         }
     }