diff options
-rw-r--r-- | Cargo.lock | 8 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | acpi_tables/Cargo.toml | 8 | ||||
-rw-r--r-- | acpi_tables/src/lib.rs | 10 | ||||
-rw-r--r-- | acpi_tables/src/rsdp.rs | 67 | ||||
-rw-r--r-- | acpi_tables/src/sdt.rs | 107 |
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); + } +} |