Pārlūkot izejas kodu

Support native functions

Isaac Woods 4 gadi atpakaļ
vecāks
revīzija
d29abef14c
4 mainītis faili ar 61 papildinājumiem un 16 dzēšanām
  1. 24 10
      aml/src/lib.rs
  2. 5 2
      aml/src/term_object.rs
  3. 14 1
      aml/src/test_utils.rs
  4. 18 3
      aml/src/value.rs

+ 24 - 10
aml/src/lib.rs

@@ -172,7 +172,7 @@ impl AmlContext {
                 Err(err)
             }
             Err((_, _, other)) => {
-                error!("AML table evaluated to weird result: {:?}", other);
+                error!("AML table evaluated to unexpected result: {:?}", other);
                 Err(AmlError::MalformedStream)
             }
         }
@@ -180,6 +180,8 @@ impl AmlContext {
 
     // TODO: docs
     pub fn invoke_method(&mut self, path: &AmlName, args: Args) -> Result<AmlValue, AmlError> {
+        use value::MethodCode;
+
         match self.namespace.get_by_path(path)?.clone() {
             AmlValue::Method { flags, code } => {
                 /*
@@ -195,16 +197,28 @@ impl AmlContext {
                  */
                 self.namespace.add_level(path.clone(), LevelType::MethodLocals)?;
 
-                let return_value = match term_list(PkgLength::from_raw_length(&code, code.len() as u32).unwrap())
-                    .parse(&code, self)
-                {
-                    // If the method doesn't return a value, we implicitly return `0`
-                    Ok(_) => Ok(AmlValue::Integer(0)),
-                    Err((_, _, Propagate::Return(result))) => Ok(result),
-                    Err((_, _, Propagate::Err(err))) => {
-                        error!("Failed to execute control method: {:?}", err);
-                        Err(err)
+                let return_value = match code {
+                    MethodCode::Aml(ref code) => {
+                        match term_list(PkgLength::from_raw_length(code, code.len() as u32).unwrap())
+                            .parse(code, self)
+                        {
+                            // If the method doesn't return a value, we implicitly return `0`
+                            Ok(_) => Ok(AmlValue::Integer(0)),
+                            Err((_, _, Propagate::Return(result))) => Ok(result),
+                            Err((_, _, Propagate::Err(err))) => {
+                                error!("Failed to execute control method: {:?}", err);
+                                Err(err)
+                            }
+                        }
                     }
+
+                    MethodCode::Native(ref method) => match (method)(self) {
+                        Ok(result) => Ok(result),
+                        Err(err) => {
+                            error!("Failed to execute control method: {:?}", err);
+                            Err(err)
+                        }
+                    },
                 };
 
                 /*

+ 5 - 2
aml/src/term_object.rs

@@ -20,7 +20,7 @@ use crate::{
     pkg_length::{pkg_length, PkgLength},
     type1::type1_opcode,
     type2::{def_buffer, def_package, type2_opcode},
-    value::{AmlValue, FieldFlags, MethodFlags, RegionSpace},
+    value::{AmlValue, FieldFlags, MethodCode, MethodFlags, RegionSpace},
     AmlContext,
     AmlError,
     AmlHandle,
@@ -368,7 +368,10 @@ where
                         context.namespace.add_value_at_resolved_path(
                             name,
                             &context.current_scope,
-                            AmlValue::Method { flags: MethodFlags::new(flags), code: code.to_vec() },
+                            AmlValue::Method {
+                                flags: MethodFlags::new(flags),
+                                code: MethodCode::Aml(code.to_vec())
+                            },
                         )
                     );
                     (Ok(()), context)

+ 14 - 1
aml/src/test_utils.rs

@@ -116,6 +116,8 @@ pub(crate) macro check_ok_value($parse: expr, $expected: expr, $remains: expr) {
 /// to apply the AML value conversion rules to compare them correctly. This is therefore only useful for artificial
 /// testing scenarios.
 pub(crate) fn crudely_cmp_values(a: &AmlValue, b: &AmlValue) -> bool {
+    use crate::value::MethodCode;
+
     match a {
         AmlValue::Boolean(a) => match b {
             AmlValue::Boolean(b) => a == b,
@@ -147,7 +149,18 @@ pub(crate) fn crudely_cmp_values(a: &AmlValue, b: &AmlValue) -> bool {
             _ => false,
         },
         AmlValue::Method { flags, code } => match b {
-            AmlValue::Method { flags: b_flags, code: b_code } => flags == b_flags && code == b_code,
+            AmlValue::Method { flags: b_flags, code: b_code } => {
+                if flags != b_flags {
+                    return false;
+                }
+
+                match (code, b_code) {
+                    (MethodCode::Aml(a), MethodCode::Aml(b)) => a == b,
+                    (MethodCode::Aml(_), MethodCode::Native(_)) => false,
+                    (MethodCode::Native(_), MethodCode::Aml(_)) => false,
+                    (MethodCode::Native(_), MethodCode::Native(_)) => panic!("Can't compare two native methods"),
+                }
+            }
             _ => false,
         },
         AmlValue::Buffer(a) => match b {

+ 18 - 3
aml/src/value.rs

@@ -1,7 +1,7 @@
 use crate::{misc::ArgNum, AmlContext, AmlError, AmlHandle, AmlName};
-use alloc::{string::String, vec::Vec};
+use alloc::{rc::Rc, string::String, vec::Vec};
 use bit_field::BitField;
-use core::cmp;
+use core::{cmp, fmt, fmt::Debug};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum RegionSpace {
@@ -140,6 +140,21 @@ pub enum AmlType {
     ThermalZone,
 }
 
+#[derive(Clone)]
+pub enum MethodCode {
+    Aml(Vec<u8>),
+    Native(Rc<dyn Fn(&mut AmlContext) -> Result<AmlValue, AmlError>>),
+}
+
+impl fmt::Debug for MethodCode {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            MethodCode::Aml(ref code) => f.debug_struct("AML method").field("code", code).finish(),
+            MethodCode::Native(_) => f.debug_struct("Native method").finish(),
+        }
+    }
+}
+
 #[derive(Clone, Debug)]
 pub enum AmlValue {
     Boolean(bool),
@@ -163,7 +178,7 @@ pub enum AmlValue {
     },
     Method {
         flags: MethodFlags,
-        code: Vec<u8>,
+        code: MethodCode,
     },
     Buffer(Vec<u8>),
     Processor {