Răsfoiți Sursa

Convert a FieldUnit to an Integer by reading it

Isaac Woods 4 ani în urmă
părinte
comite
2519d2eccd
2 a modificat fișierele cu 52 adăugiri și 0 ștergeri
  1. 3 0
      aml/src/lib.rs
  2. 49 0
      aml/src/value.rs

+ 3 - 0
aml/src/lib.rs

@@ -475,4 +475,7 @@ pub enum AmlError {
     InvalidStatusObject,
     InvalidShiftLeft,
     InvalidShiftRight,
+    FieldRegionIsNotOpRegion,
+    FieldInvalidAddress,
+    FieldInvalidAccessSize,
 }

+ 49 - 0
aml/src/value.rs

@@ -1,6 +1,7 @@
 use crate::{misc::ArgNum, AmlContext, AmlError, AmlHandle};
 use alloc::{string::String, vec::Vec};
 use bit_field::BitField;
+use core::convert::TryInto;
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum RegionSpace {
@@ -200,6 +201,12 @@ impl AmlValue {
                 }))
             }
 
+            /*
+             * Read from a field. This can return either a `Buffer` or an `Integer`, so we make sure to call
+             * `as_integer` on the result.
+             */
+            AmlValue::Field { .. } => self.read_field(context)?.as_integer(context),
+
             _ => Err(AmlError::IncompatibleValueConversion),
         }
     }
@@ -256,6 +263,48 @@ impl AmlValue {
             _ => Err(AmlError::IncompatibleValueConversion),
         }
     }
+
+    /// Reads from a field of an opregion, returning either a `AmlValue::Integer` or an `AmlValue::Buffer`,
+    /// depending on the size of the field.
+    pub fn read_field(&self, context: &AmlContext) -> Result<AmlValue, AmlError> {
+        if let AmlValue::Field { region, flags, offset, length } = self {
+            let (region_space, region_base, region_length) = {
+                if let AmlValue::OpRegion { region, offset, length } = context.namespace.get(*region)? {
+                    (region, offset, length)
+                } else {
+                    return Err(AmlError::FieldRegionIsNotOpRegion);
+                }
+            };
+
+            match region_space {
+                RegionSpace::SystemMemory => {
+                    let address = (region_base + offset).try_into().map_err(|_| AmlError::FieldInvalidAddress)?;
+                    match length {
+                        8 => Ok(AmlValue::Integer(context.handler.read_u8(address) as u64)),
+                        16 => Ok(AmlValue::Integer(context.handler.read_u16(address) as u64)),
+                        32 => Ok(AmlValue::Integer(context.handler.read_u32(address) as u64)),
+                        64 => Ok(AmlValue::Integer(context.handler.read_u64(address))),
+                        _ => Err(AmlError::FieldInvalidAccessSize),
+                    }
+                }
+
+                RegionSpace::SystemIo => {
+                    let port = (region_base + offset).try_into().map_err(|_| AmlError::FieldInvalidAddress)?;
+                    match length {
+                        8 => Ok(AmlValue::Integer(context.handler.read_io_u8(port) as u64)),
+                        16 => Ok(AmlValue::Integer(context.handler.read_io_u16(port) as u64)),
+                        32 => Ok(AmlValue::Integer(context.handler.read_io_u32(port) as u64)),
+                        _ => Err(AmlError::FieldInvalidAccessSize),
+                    }
+                }
+
+                // TODO
+                _ => unimplemented!(),
+            }
+        } else {
+            Err(AmlError::IncompatibleValueConversion)
+        }
+    }
 }
 
 /// A control method can take up to 7 arguments, each of which can be an `AmlValue`.