Browse Source

Add named fields to the namespace

Isaac Woods 6 years ago
parent
commit
68acfb0793
4 changed files with 53 additions and 23 deletions
  1. 1 0
      src/aml/mod.rs
  2. 42 21
      src/aml/parser.rs
  3. 7 1
      src/aml/value.rs
  4. 3 1
      src/sdt.rs

+ 1 - 0
src/aml/mod.rs

@@ -27,6 +27,7 @@ pub enum AmlError {
     IncompatibleValueConversion,
     InvalidPath(String),
     InvalidFieldFlags,
+    InvalidNameSeg([u8; 4]),
 }
 
 impl AmlTable {

+ 42 - 21
src/aml/parser.rs

@@ -6,10 +6,17 @@ use bit_field::BitField;
 use core::str;
 use {Acpi, AcpiHandler};
 
-/// This is used internally by the parser. Often, we're only interested in the end offset, so we
-/// know when to stop parsing the current explicit-length structure. However, various constants
-/// (e.g. the size of fields) are encoded as PkgLengths, and so sometimes we want to access the raw
-/// data as well.
+/// This is used internally by the parser to keep track of what we know about a field before we can
+/// add it to the namespace.
+struct FieldInfo {
+    pub name: String,
+    pub length: u64,
+}
+
+/// This is used internally by the parser. Often, we're only interested in offset of the end of the
+/// current explicit-length structure, so we know when to stop parsing it. However, various constants
+/// (e.g. the size of fields) are also encoded as PkgLengths, and so sometimes we want to access
+/// the raw data as well.
 struct PkgLength {
     pub raw_length: u32,
     pub end_offset: u32,
@@ -201,7 +208,7 @@ where
         info!("region len: {}", length);
 
         // Insert it into the namespace
-        let namespace_path = self.resolve_path(name)?;
+        let namespace_path = self.resolve_path(&name)?;
         self.acpi.namespace.insert(
             // self.resolve_path(name)?, TODO: I thought this would work with nll?
             namespace_path,
@@ -233,33 +240,40 @@ where
         trace!("end offset: {}", end_offset);
         let name = self.parse_name_string()?;
         trace!("name: {}", name);
-        let field_flags = FieldFlags::new(self.stream.next()?);
-        trace!("Field flags: {:?}", field_flags);
+        let flags = FieldFlags::new(self.stream.next()?);
+        trace!("Field flags: {:?}", flags);
 
         while self.stream.offset() < end_offset {
             // TODO: parse other field types
-            try_parse!(self, AmlParser::parse_named_field)?;
+            let info = try_parse!(self, AmlParser::parse_named_field)?;
+
+            // TODO: add field name to this (info.name)?
+            let namespace_path = self.resolve_path(&name)?;
+            self.acpi.namespace.insert(
+                namespace_path,
+                AmlValue::Field {
+                    flags,
+                    offset: 0, // TODO: calculate offset
+                    length: info.length,
+                },
+            );
         }
 
         Ok(())
     }
 
-    fn parse_named_field(&mut self) -> Result<(), AmlError> {
+    fn parse_named_field(&mut self) -> Result<FieldInfo, AmlError> {
         /*
          * NamedField := NameSeg PkgLength
          *
          * This encodes the size of the field using a PkgLength - it doesn't mark the length of an
          * explicit-length structure!
          */
-        let name_seg = self.parse_name_seg()?;
-        let size = self.parse_pkg_length()?.raw_length;
-        info!(
-            "Adding named field called {:?} with size {}",
-            name_seg, size
-        );
+        let name = String::from(name_seg_to_string(&self.parse_name_seg()?)?);
+        let length = self.parse_pkg_length()?.raw_length as u64;
+        info!("Adding named field called {:?} with size {}", name, length);
 
-        // TODO: add field to namespace
-        Ok(())
+        Ok(FieldInfo { name, length })
     }
 
     fn parse_def_buffer(&mut self) -> Result<AmlValue, AmlError> {
@@ -465,7 +479,7 @@ where
     }
 
     /// Resolve a given path and the current scope to an absolute path in the namespace.
-    fn resolve_path(&mut self, mut path: String) -> Result<String, AmlError> {
+    fn resolve_path(&mut self, mut path: &str) -> Result<String, AmlError> {
         /*
          * TODO: how should we handle '.' as they appear in paths?
          */
@@ -474,17 +488,17 @@ where
         // If the scope to resolve is from the root of the namespace, or the current scope is
         // nothing, just return the given scope
         if self.scope == "" || path.starts_with("\\") {
-            return Ok(path);
+            return Ok(String::from(path));
         }
 
         // "^"s at the start of a path specify to go up one level from the current scope, to its
         // parent object
         let mut namespace_object = self.scope.clone();
         while path.starts_with("^") {
-            path = path[1..].to_string();
+            path = &path[1..];
 
             if namespace_object.pop() == None {
-                return Err(AmlError::InvalidPath(original_path));
+                return Err(AmlError::InvalidPath(String::from(original_path)));
             }
         }
 
@@ -507,3 +521,10 @@ fn is_digit_char(byte: u8) -> bool {
 fn is_name_char(byte: u8) -> bool {
     is_lead_name_char(byte) || is_digit_char(byte)
 }
+
+fn name_seg_to_string<'a>(seg: &'a [u8; 4]) -> Result<&'a str, AmlError> {
+    match str::from_utf8(seg) {
+        Ok(seg_str) => Ok(seg_str),
+        Err(_) => Err(AmlError::InvalidNameSeg(*seg)),
+    }
+}

+ 7 - 1
src/aml/value.rs

@@ -32,7 +32,7 @@ pub enum FieldUpdateRule {
     WriteAsZeros,
 }
 
-#[derive(Debug)] // TODO: custom debug / get rid of completely
+#[derive(Clone, Copy, Debug)] // TODO: custom debug / get rid of completely
 pub struct FieldFlags(u8);
 
 impl FieldFlags {
@@ -75,6 +75,12 @@ pub enum AmlValue {
         offset: u64,
         length: u64,
     },
+
+    Field {
+        flags: FieldFlags,
+        offset: u64,
+        length: u64,
+    },
 }
 
 impl AmlValue {

+ 3 - 1
src/sdt.rs

@@ -184,7 +184,9 @@ where
         }
 
         "HPET" => {
-            let hpet_mapping = acpi.handler.map_physical_region::<Hpet>(physical_address);
+            let hpet_mapping = acpi
+                .handler
+                .map_physical_region::<Hpet>(physical_address, mem::size_of::<Hpet>());
             ::hpet::parse_hpet(&hpet_mapping)?;
             acpi.handler.unmap_physical_region(hpet_mapping);
         }