Browse Source

Handle writes from integers into buffer fields

Isaac Woods 3 years ago
parent
commit
14e966731c
4 changed files with 49 additions and 3 deletions
  1. 1 0
      aml/Cargo.toml
  2. 4 2
      aml/src/lib.rs
  3. 37 0
      aml/src/value.rs
  4. 7 1
      tests/buffer_fields.asl

+ 1 - 0
aml/Cargo.toml

@@ -13,4 +13,5 @@ edition = "2018"
 log = "0.4"
 bit_field = "0.10"
 byteorder = { version = "1", default-features = false }
+bitvec = { version = "0.22.3", default-features = false, features = ["alloc", "atomic"] }
 spinning_top = "0.2.4"

+ 4 - 2
aml/src/lib.rs

@@ -335,8 +335,9 @@ impl AmlContext {
                         field.read_field(self)
                     }
                     AmlType::BufferField => {
-                        log::info!("Trying to write to buffer field!");
-                        todo!()
+                        let mut buffer_field = self.namespace.get(handle).unwrap().clone();
+                        buffer_field.write_buffer_field(value.clone(), self)?;
+                        Ok(value)
                     }
                     typ => {
                         *self.namespace.get_mut(handle)? = value.as_type(typ, self)?;
@@ -789,6 +790,7 @@ pub enum AmlError {
     TypeCannotBeCompared(AmlType),
     /// Produced when the `Mid` operator is applied to a value of a type other than `Buffer` or `String`.
     TypeCannotBeSliced(AmlType),
+    TypeCannotBeWrittenToBufferField(AmlType),
 }
 
 #[cfg(test)]

+ 37 - 0
aml/src/value.rs

@@ -501,6 +501,43 @@ impl AmlValue {
         }
     }
 
+    pub fn write_buffer_field(&mut self, value: AmlValue, context: &mut AmlContext) -> Result<(), AmlError> {
+        use bitvec::view::BitView;
+
+        if let AmlValue::BufferField { buffer_data, offset, length } = self {
+            let offset = *offset as usize;
+            let length = *length as usize;
+            // TODO: check these against the size of the buffer to be written into
+            let mut inner_data = buffer_data.lock();
+            let bitslice = inner_data.view_bits_mut::<bitvec::order::Lsb0>();
+
+            match value {
+                AmlValue::Integer(value) => {
+                    /*
+                     * When an `Integer` is written into a `BufferField`, the entire contents are overwritten. If
+                     * it's smaller than the length of the buffer field, it's zero-extended. If it's larger, the
+                     * upper bits are truncated.
+                     */
+                    let bits_to_copy = cmp::min(*length, 64);
+                    bitslice[offset..(offset + length)]
+                        .copy_from_bitslice(&value.to_le_bytes().view_bits()[..(bits_to_copy as usize)]);
+                    Ok(())
+                }
+                AmlValue::Boolean(value) => {
+                    bitslice.set(offset, value);
+                    Ok(())
+                }
+                AmlValue::Buffer(value) => {
+                    // TODO
+                    todo!()
+                }
+                _ => Err(AmlError::TypeCannotBeWrittenToBufferField(value.type_of())),
+            }
+        } else {
+            Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::BufferField })
+        }
+    }
+
     /// Logically compare two `AmlValue`s, according to the rules that govern opcodes like `DefLEqual`, `DefLLess`,
     /// etc. The type of `self` dictates the type that `other` will be converted to, and the method by which the
     /// values will be compared:

+ 7 - 1
tests/buffer_fields.asl

@@ -1,5 +1,5 @@
 DefinitionBlock("buffer_fields.aml", "DSDT", 1, "RSACPI", "BUFFLD", 1) {
-	Name(X, Buffer (16) { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f })
+	Name(X, Buffer (16) { 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 })
 	CreateBitField(X, 3, BIT3)
 	CreateField(X, 0, 3, BITS)
 	CreateByteField(X, 1, BYTE)
@@ -7,5 +7,11 @@ DefinitionBlock("buffer_fields.aml", "DSDT", 1, "RSACPI", "BUFFLD", 1) {
 	CreateDWordField(X, 4, DWRD)
 	CreateQWordField(X, 8, QWRD)
 
+	// `X` should end up as [0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]
 	BIT3 = 1
+	BITS = 7
+	BYTE = 0x01
+	WORD = 0x0302
+	DWRD = 0x07060504
+	/* QWRD = Buffer() { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f } */
 }