2
0
Эх сурвалжийг харах

Parse DefOpRegion and DefField

Isaac Woods 5 жил өмнө
parent
commit
e6ed62ba79

+ 1 - 0
aml_parser/src/lib.rs

@@ -32,6 +32,7 @@ pub enum AmlError {
     UnexpectedEndOfStream,
     UnexpectedByte(u8),
     InvalidNameSeg([u8; 4]),
+    InvalidFieldFlags,
 }
 
 pub struct AmlNamespace {

+ 5 - 0
aml_parser/src/opcode.rs

@@ -6,6 +6,11 @@ pub const MULTI_NAME_PREFIX: u8 = 0x2F;
 pub const ROOT_CHAR: u8 = b'\\';
 pub const PREFIX_CHAR: u8 = b'^';
 
+pub const RESERVED_FIELD: u8 = 0x00;
+pub const ACCESS_FIELD: u8 = 0x01;
+pub const CONNECT_FIELD: u8 = 0x02;
+pub const EXTENDED_ACCESS_FIELD: u8 = 0x03;
+
 pub const ZERO_OP: u8 = 0x00;
 pub const ONE_OP: u8 = 0x01;
 pub const ONES_OP: u8 = 0xff;

+ 128 - 6
aml_parser/src/term_object.rs

@@ -1,11 +1,12 @@
 use crate::{
-    name_object::name_string,
-    opcode::{opcode, SCOPE_OP},
-    parser::{choice, comment, comment_scope, take_n, ParseResult, Parser},
+    name_object::{name_seg, name_string},
+    opcode::{self, ext_opcode, opcode},
+    parser::{choice, comment_scope, take, take_u16, take_u32, take_u64, ParseResult, Parser},
     pkg_length::{pkg_length, PkgLength},
     value::{AmlValue, FieldFlags},
-    AmlNamespace,
+    AmlError,
 };
+use alloc::string::String;
 use log::{debug, trace};
 
 /// `TermList`s are usually found within explicit-length objects (so they have a `PkgLength`
@@ -30,14 +31,14 @@ pub fn term_object<'a>() -> impl Parser<'a, ()> {
      * TermObj := NamespaceModifierObj | NamedObj | Type1Opcode | Type2Opcode
      * NamespaceModifierObj := DefAlias | DefName | DefScope
      */
-    comment_scope("TermObj", choice!(def_scope()))
+    comment_scope("TermObj", choice!(def_scope(), def_op_region(), def_field()))
 }
 
 pub fn def_scope<'a>() -> impl Parser<'a, ()> {
     /*
      * DefScope := 0x10 PkgLength NameString TermList
      */
-    opcode(SCOPE_OP)
+    opcode(opcode::SCOPE_OP)
         .then(comment_scope(
             "DefScope",
             pkg_length().then(name_string()).feed(move |(pkg_length, name)| {
@@ -47,6 +48,127 @@ pub fn def_scope<'a>() -> impl Parser<'a, ()> {
         ))
         .discard_result()
 }
+
+pub fn def_op_region<'a>() -> impl Parser<'a, ()> {
+    /*
+     * DefOpRegion := ExtOpPrefix 0x80 NameString RegionSpace RegionOffset RegionLen
+     * RegionSpace := ByteData (where 0x00      = SystemMemory
+     *                                0x01      = SystemIO
+     *                                0x02      = PciConfig
+     *                                0x03      = EmbeddedControl
+     *                                0x04      = SMBus
+     *                                0x05      = SystemCMOS
+     *                                0x06      = PciBarTarget
+     *                                0x07      = IPMI
+     *                                0x08      = GeneralPurposeIO
+     *                                0x09      = GenericSerialBus
+     *                                0x80-0xff = OEM Defined)
+     * ByteData := 0x00 - 0xff
+     * RegionOffset := TermArg => Integer
+     * RegionLen := TermArg => Integer
+     */
+    ext_opcode(opcode::EXT_OP_REGION_OP)
+        .then(comment_scope(
+            "DefOpRegion",
+            name_string().then(take()).then(term_arg()).then(term_arg()).map(
+                |(((name, space), offset), region_len)| {
+                    trace!("Op region: {}, {}, {:?}, {:?}", name, space, offset, region_len);
+                    ()
+                },
+            ),
+        ))
+        .discard_result()
+}
+
+pub fn def_field<'a>() -> impl Parser<'a, ()> {
+    /*
+     * DefField = ExtOpPrefix 0x81 PkgLength NameString FieldFlags FieldList
+     * FieldFlags := ByteData
+     */
+    ext_opcode(opcode::EXT_FIELD_OP)
+        .then(comment_scope(
+            "DefField",
+            pkg_length().then(name_string()).then(take()).feed(
+                |((list_length, region_name), flags)| {
+                    move |mut input: &'a [u8]| -> ParseResult<'a, ()> {
+                        /*
+                         * FieldList := Nothing | <FieldElement FieldList>
+                         */
+                        // TODO: can this pattern be expressed as a combinator
+                        while list_length.still_parsing(input) {
+                            let (new_input, ()) =
+                                field_element(&region_name, FieldFlags::new(flags)).parse(input)?;
+                            input = new_input;
+                        }
+
+                        Ok((input, ()))
+                    }
+                },
+            ),
+        ))
+        .discard_result()
+}
+
+pub fn field_element<'a>(region_name: &String, flags: FieldFlags) -> impl Parser<'a, ()> {
+    /*
+     * FieldElement := NamedField | ReservedField | AccessField | ExtendedAccessField |
+     *                 ConnectField
+     * NamedField := NameSeg PkgLength
+     * ReservedField := 0x00 PkgLength
+     * AccessField := 0x01 AccessType AccessAttrib
+     * ConnectField := <0x02 NameString> | <0x02 BufferData>
+     * ExtendedAccessField := 0x03 AccessType ExtendedAccessAttrib AccessLength
+     *
+     * AccessType := ByteData
+     * AccessAttrib := ByteData
+     *
+     * XXX: The spec says a ConnectField can be <0x02 BufferData>, but BufferData isn't an AML
+     * object (it seems to be defined in ASL). We treat BufferData as if it was encoded like
+     * DefBuffer, and this seems to work so far.
+     */
+    // TODO: replace these maps with `with_context` and register the fields in the namespace
+    // TODO: parse ConnectField and ExtendedAccessField
+    let reserved_field =
+        opcode(opcode::RESERVED_FIELD).then(pkg_length()).map(|((), pkg_length)| {
+            trace!("Adding reserved field with length: {}", pkg_length.raw_length);
+        });
+
+    let access_field = opcode(opcode::ACCESS_FIELD).then(take()).then(take()).map(
+        |(((), access_type), access_attrib)| {
+            trace!(
+                "Adding access field with access_type: {}, access_attrib: {}",
+                access_type,
+                access_attrib
+            );
+        },
+    );
+
+    let named_field = name_seg().then(pkg_length()).map(|(name, length)| {
+        trace!("Named field with name {} and length {}", name.as_str(), length.raw_length);
+    });
+
+    choice!(reserved_field, access_field, named_field)
+}
+
+pub fn term_arg<'a>() -> impl Parser<'a, AmlValue> {
+    /*
+     * TermArg := Type2Opcode | DataObject | ArgObj | LocalObj
+     */
+    // TODO: this doesn't yet parse Term2Opcode, ArgObj, or LocalObj
+    comment_scope("TermArg", choice!(data_object()))
+}
+
+pub fn data_object<'a>() -> impl Parser<'a, AmlValue> {
+    /*
+     * DataObject := DefPackage | DefVarPackage | ComputationalData
+     *
+     * The order of the parsers are important here, as DefPackage and DefVarPackage can be
+     * accidently parsed as ComputationalDatas.
+     */
+    // TODO: this doesn't yet parse DefPackage or DefVarPackage
+    comment_scope("DataObject", choice!(computational_data()))
+}
+
 pub fn computational_data<'a>() -> impl Parser<'a, AmlValue> {
     /*
      * ComputationalData := ByteConst | WordConst | DWordConst | QWordConst | String |

+ 71 - 0
aml_parser/src/value.rs

@@ -1,4 +1,75 @@
+use crate::AmlError;
+use bit_field::BitField;
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum RegionSpace {
+    SystemMemory,
+    SystemIo,
+    PciConfig,
+    EmbeddedControl,
+    SMBus,
+    SystemCmos,
+    PciBarTarget,
+    IPMI,
+    GeneralPurposeIo,
+    GenericSerialBus,
+    OemDefined(u8),
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum FieldAccessType {
+    Any,
+    Byte,
+    Word,
+    DWord,
+    QWord,
+    Buffer,
+    Reserved,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum FieldUpdateRule {
+    Preserve,
+    WriteAsOnes,
+    WriteAsZeros,
+}
+
+// TODO: custom debug impl
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub struct FieldFlags(u8);
+
+impl FieldFlags {
+    pub fn new(value: u8) -> FieldFlags {
+        FieldFlags(value)
+    }
+
+    pub fn access_type(&self) -> Result<FieldAccessType, AmlError> {
+        match self.0.get_bits(0..4) {
+            0 => Ok(FieldAccessType::Any),
+            1 => Ok(FieldAccessType::Byte),
+            2 => Ok(FieldAccessType::Word),
+            3 => Ok(FieldAccessType::DWord),
+            4 => Ok(FieldAccessType::QWord),
+            5 => Ok(FieldAccessType::Buffer),
+            _ => Err(AmlError::InvalidFieldFlags),
+        }
+    }
+
+    pub fn lock_rule(&self) -> bool {
+        self.0.get_bit(4)
+    }
+
+    pub fn field_update_rule(&self) -> Result<FieldUpdateRule, AmlError> {
+        match self.0.get_bits(5..7) {
+            0 => Ok(FieldUpdateRule::Preserve),
+            1 => Ok(FieldUpdateRule::WriteAsOnes),
+            2 => Ok(FieldUpdateRule::WriteAsZeros),
+            _ => Err(AmlError::InvalidFieldFlags),
+        }
+    }
+}
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub enum AmlValue {
     Integer(u64),
+    Field { flags: FieldFlags, offset: u64, length: u64 },
 }