Procházet zdrojové kódy

Implement DefConcat

Isaac Woods před 3 roky
rodič
revize
6f92f675a4
3 změnil soubory, kde provedl 82 přidání a 2 odebrání
  1. 1 0
      aml/src/opcode.rs
  2. 48 1
      aml/src/type2.rs
  3. 33 1
      aml/src/value.rs

+ 1 - 0
aml/src/opcode.rs

@@ -49,6 +49,7 @@ pub const DEF_BREAKPOINT_OP: u8 = 0xcc;
  */
 pub const DEF_STORE_OP: u8 = 0x70;
 pub const DEF_ADD_OP: u8 = 0x72;
+pub const DEF_CONCAT_OP: u8 = 0x73;
 pub const DEF_SHIFT_LEFT: u8 = 0x79;
 pub const DEF_SHIFT_RIGHT: u8 = 0x7a;
 pub const DEF_AND_OP: u8 = 0x7b;

+ 48 - 1
aml/src/type2.rs

@@ -19,7 +19,7 @@ use crate::{
     DebugVerbosity,
 };
 use alloc::{vec, vec::Vec};
-use core::{cmp::Ordering, convert::TryInto};
+use core::{cmp::Ordering, convert::TryInto, mem};
 
 /// Type 2 opcodes return a value and so can be used in expressions.
 pub fn type2_opcode<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
@@ -44,6 +44,7 @@ where
             def_add(),
             def_and(),
             def_buffer(),
+            def_concat(),
             def_l_equal(),
             def_l_greater(),
             def_l_greater_equal(),
@@ -147,6 +148,52 @@ where
         .map(|((), buffer)| Ok(AmlValue::Buffer(buffer)))
 }
 
+pub fn def_concat<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
+where
+    'c: 'a,
+{
+    /*
+     * DefConcat := 0x73 Data Data Target
+     * Data := TermArg => ComputationalData
+     */
+    opcode(opcode::DEF_CONCAT_OP)
+        .then(comment_scope(
+            DebugVerbosity::AllScopes,
+            "DefConcat",
+            term_arg().then(term_arg()).then(target()).map_with_context(|((left, right), target), context| {
+                let result = match left.as_concat_type() {
+                    AmlValue::Integer(left) => {
+                        let right = try_with_context!(context, right.as_integer(context));
+
+                        let mut buffer = Vec::with_capacity(mem::size_of::<u64>() * 2);
+                        buffer.extend_from_slice(&left.to_le_bytes());
+                        buffer.extend_from_slice(&right.to_le_bytes());
+
+                        AmlValue::Buffer(buffer)
+                    }
+                    AmlValue::Buffer(mut left) => {
+                        left.extend(try_with_context!(context, right.as_buffer(context)));
+                        AmlValue::Buffer(left)
+                    }
+                    AmlValue::String(left) => {
+                        let right = match right.as_concat_type() {
+                            AmlValue::String(right) => right,
+                            AmlValue::Integer(_) => try_with_context!(context, right.as_string(context)),
+                            AmlValue::Buffer(_) => try_with_context!(context, right.as_string(context)),
+                            _ => panic!("Invalid type returned from `as_concat_type`"),
+                        };
+                        AmlValue::String(left + &right)
+                    }
+                    _ => panic!("Invalid type returned from `as_concat_type`"),
+                };
+
+                try_with_context!(context, context.store(target, result.clone()));
+                (Ok(result), context)
+            }),
+        ))
+        .map(|((), result)| Ok(result))
+}
+
 fn def_l_or<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
 where
     'c: 'a,

+ 33 - 1
aml/src/value.rs

@@ -1,5 +1,9 @@
 use crate::{misc::ArgNum, AmlContext, AmlError, AmlHandle, AmlName};
-use alloc::{string::String, sync::Arc, vec::Vec};
+use alloc::{
+    string::{String, ToString},
+    sync::Arc,
+    vec::Vec,
+};
 use bit_field::BitField;
 use core::{cmp, fmt, fmt::Debug};
 
@@ -307,6 +311,34 @@ impl AmlValue {
         }
     }
 
+    /// Converts an `AmlValue` to the representation that should be used when concatenating it with other values,
+    /// primarily by the `DefConcat` opcode. This will always produce a `AmlValue::Integer`, `AmlValue::String`, or
+    /// `AmlValue::Buffer`, with other types being converted to strings containing the name of their type.
+    pub fn as_concat_type(&self) -> AmlValue {
+        match self.type_of() {
+            AmlType::Integer => self.clone(),
+            AmlType::String => self.clone(),
+            AmlType::Buffer => self.clone(),
+
+            AmlType::Uninitialized => AmlValue::String("[Uninitialized]".to_string()),
+            AmlType::BufferField => AmlValue::String("[Buffer Field]".to_string()),
+            AmlType::DdbHandle => AmlValue::String("[Ddb Handle]".to_string()),
+            AmlType::DebugObject => AmlValue::String("[Debug Object]".to_string()),
+            AmlType::Event => AmlValue::String("[Event]".to_string()),
+            AmlType::FieldUnit => AmlValue::String("[Field]".to_string()),
+            AmlType::Device => AmlValue::String("[Device]".to_string()),
+            AmlType::Method => AmlValue::String("[Control Method]".to_string()),
+            AmlType::Mutex => AmlValue::String("[Mutex]".to_string()),
+            AmlType::ObjReference => AmlValue::String("[Obj Reference]".to_string()),
+            AmlType::OpRegion => AmlValue::String("[Operation Region]".to_string()),
+            AmlType::Package => AmlValue::String("[Package]".to_string()),
+            AmlType::Processor => AmlValue::String("[Processor]".to_string()),
+            AmlType::PowerResource => AmlValue::String("[Power Resource]".to_string()),
+            AmlType::RawDataBuffer => AmlValue::String("[Raw Data Buffer]".to_string()),
+            AmlType::ThermalZone => AmlValue::String("[Thermal Zone]".to_string()),
+        }
+    }
+
     /// Turns an `AmlValue` returned from a `_STA` method into a `StatusObject`. Should only be called for values
     /// returned from `_STA`. If you need a `StatusObject`, but the device does not have a `_STA` method, use
     /// `StatusObject::default()`.