diff options
author | Chuanxiao Dong <chuanxiao.dong@intel.corp-partner.google.com> | 2019-11-01 15:18:13 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-02-27 05:07:01 +0000 |
commit | 91e8403ddf1dd5abf5611127fa07c578568be752 (patch) | |
tree | aec5a308d689ed4d99a09f3cde0583646985d6b0 /acpi_tables/src/sdt.rs | |
parent | ec8aacb1343108c399e423f430864ee84cff8515 (diff) | |
download | crosvm-91e8403ddf1dd5abf5611127fa07c578568be752.tar crosvm-91e8403ddf1dd5abf5611127fa07c578568be752.tar.gz crosvm-91e8403ddf1dd5abf5611127fa07c578568be752.tar.bz2 crosvm-91e8403ddf1dd5abf5611127fa07c578568be752.tar.lz crosvm-91e8403ddf1dd5abf5611127fa07c578568be752.tar.xz crosvm-91e8403ddf1dd5abf5611127fa07c578568be752.tar.zst crosvm-91e8403ddf1dd5abf5611127fa07c578568be752.zip |
acpi_tables: Add initial ACPI tables support
The basic ACPI table support for creating XSDT. It refers to the implementation of the Cloud-hypervisor's ACPI commit: - Cloud-hypervisor: acpi_tables: Add initial ACPI tables support BUG=chromium:1018674 TEST=cargo test -p acpi_tables Change-Id: Ia3b597936fef214fcb92fce28c91152dfa03bec9 Signed-off-by: Chuanxiao Dong <chuanxiao.dong@intel.corp-partner.google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2035350 Reviewed-by: Tomasz Jeznach <tjeznach@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com>
Diffstat (limited to 'acpi_tables/src/sdt.rs')
-rw-r--r-- | acpi_tables/src/sdt.rs | 107 |
1 files changed, 107 insertions, 0 deletions
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); + } +} |