summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock8
-rw-r--r--Cargo.toml1
-rw-r--r--acpi_tables/Cargo.toml8
-rw-r--r--acpi_tables/src/lib.rs10
-rw-r--r--acpi_tables/src/rsdp.rs67
-rw-r--r--acpi_tables/src/sdt.rs107
6 files changed, 201 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f63785c..80d5b5e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -19,6 +19,13 @@ dependencies = [
 ]
 
 [[package]]
+name = "acpi_tables"
+version = "0.1.0"
+dependencies = [
+ "data_model 0.1.0",
+]
+
+[[package]]
 name = "arch"
 version = "0.1.0"
 dependencies = [
@@ -100,6 +107,7 @@ name = "crosvm"
 version = "0.1.0"
 dependencies = [
  "aarch64 0.1.0",
+ "acpi_tables 0.1.0",
  "arch 0.1.0",
  "assertions 0.1.0",
  "audio_streams 0.1.0",
diff --git a/Cargo.toml b/Cargo.toml
index 7eb7215..66a616a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -72,6 +72,7 @@ sync = { path = "sync" }
 sys_util = "*"
 vhost = { path = "vhost" }
 vm_control = { path = "vm_control" }
+acpi_tables = { path = "acpi_tables" }
 
 [target.'cfg(target_arch = "x86_64")'.dependencies]
 x86_64 = { path = "x86_64" }
diff --git a/acpi_tables/Cargo.toml b/acpi_tables/Cargo.toml
new file mode 100644
index 0000000..80518bb
--- /dev/null
+++ b/acpi_tables/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "acpi_tables"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+
+[dependencies]
+data_model = { path = "../data_model" }
diff --git a/acpi_tables/src/lib.rs b/acpi_tables/src/lib.rs
new file mode 100644
index 0000000..73dd9e8
--- /dev/null
+++ b/acpi_tables/src/lib.rs
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+pub mod rsdp;
+pub mod sdt;
+
+fn generate_checksum(data: &[u8]) -> u8 {
+    (255 - data.iter().fold(0u8, |acc, x| acc.wrapping_add(*x))).wrapping_add(1)
+}
diff --git a/acpi_tables/src/rsdp.rs b/acpi_tables/src/rsdp.rs
new file mode 100644
index 0000000..4bf64c9
--- /dev/null
+++ b/acpi_tables/src/rsdp.rs
@@ -0,0 +1,67 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use data_model::DataInit;
+
+#[repr(packed)]
+#[derive(Clone, Copy, Default)]
+pub struct RSDP {
+    pub signature: [u8; 8],
+    pub checksum: u8,
+    pub oem_id: [u8; 6],
+    pub revision: u8,
+    _rsdt_addr: u32,
+    pub length: u32,
+    pub xsdt_addr: u64,
+    pub extended_checksum: u8,
+    _reserved: [u8; 3],
+}
+
+// Safe as RSDP structure only contains raw data
+unsafe impl DataInit for RSDP {}
+
+impl RSDP {
+    pub fn new(oem_id: [u8; 6], xsdt_addr: u64) -> Self {
+        let mut rsdp = RSDP {
+            signature: *b"RSD PTR ",
+            checksum: 0,
+            oem_id,
+            revision: 2,
+            _rsdt_addr: 0,
+            length: std::mem::size_of::<RSDP>() as u32,
+            xsdt_addr,
+            extended_checksum: 0,
+            _reserved: [0; 3],
+        };
+
+        rsdp.checksum = super::generate_checksum(&rsdp.as_slice()[0..19]);
+        rsdp.extended_checksum = super::generate_checksum(&rsdp.as_slice());
+        rsdp
+    }
+
+    pub fn len() -> usize {
+        std::mem::size_of::<RSDP>()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::RSDP;
+    use data_model::DataInit;
+
+    #[test]
+    fn test_rsdp() {
+        let rsdp = RSDP::new(*b"CHYPER", 0xdead_beef);
+        let sum = rsdp
+            .as_slice()
+            .iter()
+            .fold(0u8, |acc, x| acc.wrapping_add(*x));
+        assert_eq!(sum, 0);
+        let sum: u8 = rsdp
+            .as_slice()
+            .iter()
+            .fold(0u8, |acc, x| acc.wrapping_add(*x));
+        assert_eq!(sum, 0);
+    }
+}
diff --git a/acpi_tables/src/sdt.rs b/acpi_tables/src/sdt.rs
new file mode 100644
index 0000000..ca1133c
--- /dev/null
+++ b/acpi_tables/src/sdt.rs
@@ -0,0 +1,107 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use data_model::DataInit;
+
+/// SDT represents for System Description Table. The structure SDT is a
+/// generic format for creating various ACPI tables like DSDT/FADT/MADT.
+pub struct SDT {
+    data: Vec<u8>,
+}
+
+const HEADER_LEN: u32 = 36;
+const LENGTH_OFFSET: usize = 4;
+const CHECKSUM_OFFSET: usize = 9;
+
+#[allow(clippy::len_without_is_empty)]
+impl SDT {
+    /// Set up the ACPI table header at the front of the SDT.
+    /// The arguments correspond to the elements in the ACPI
+    /// table headers.
+    pub fn new(
+        signature: [u8; 4],
+        length: u32,
+        revision: u8,
+        oem_id: [u8; 6],
+        oem_table: [u8; 8],
+        oem_revision: u32,
+    ) -> Self {
+        // The length represents for the length of the entire table
+        // which includes this header. And the header is 36 bytes, so
+        // lenght should be >= 36. For the case who gives a number less
+        // than the header len, use the header len directly.
+        let len: u32 = if length < HEADER_LEN {
+            HEADER_LEN
+        } else {
+            length
+        };
+        let mut data = Vec::with_capacity(length as usize);
+        data.extend_from_slice(&signature);
+        data.extend_from_slice(&len.to_le_bytes());
+        data.push(revision);
+        data.push(0); // checksum
+        data.extend_from_slice(&oem_id);
+        data.extend_from_slice(&oem_table);
+        data.extend_from_slice(&oem_revision.to_le_bytes());
+        data.extend_from_slice(b"CROS");
+        data.extend_from_slice(&0u32.to_le_bytes());
+
+        data.resize(length as usize, 0);
+        let mut sdt = SDT { data };
+
+        sdt.update_checksum();
+        sdt
+    }
+
+    fn update_checksum(&mut self) {
+        self.data[CHECKSUM_OFFSET] = 0;
+        let checksum = super::generate_checksum(self.data.as_slice());
+        self.data[CHECKSUM_OFFSET] = checksum;
+    }
+
+    pub fn as_slice(&self) -> &[u8] {
+        &self.data.as_slice()
+    }
+
+    pub fn append<T: DataInit>(&mut self, value: T) {
+        self.data.extend_from_slice(value.as_slice());
+        self.write(LENGTH_OFFSET, self.data.len() as u32);
+    }
+
+    /// Write a value at the given offset
+    pub fn write<T: DataInit>(&mut self, offset: usize, value: T) {
+        let value_len = std::mem::size_of::<T>();
+        if (offset + value_len) > self.data.len() {
+            return;
+        }
+
+        self.data[offset..offset + value_len].copy_from_slice(&value.as_slice());
+        self.update_checksum();
+    }
+
+    pub fn len(&self) -> usize {
+        self.data.len()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::SDT;
+
+    #[test]
+    fn test_sdt() {
+        let mut sdt = SDT::new(*b"TEST", 40, 1, *b"CROSVM", *b"TESTTEST", 1);
+        let sum: u8 = sdt
+            .as_slice()
+            .iter()
+            .fold(0u8, |acc, x| acc.wrapping_add(*x));
+        assert_eq!(sum, 0);
+        sdt.write(36, 0x12345678 as u32);
+        let sum: u8 = sdt
+            .as_slice()
+            .iter()
+            .fold(0u8, |acc, x| acc.wrapping_add(*x));
+        assert_eq!(sum, 0);
+    }
+}