Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/acpi_tables/src/sdt.rs
5394 views
1
// Copyright 2020 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::fs::File;
6
use std::io::ErrorKind;
7
use std::io::Read;
8
use std::io::Result;
9
use std::path::Path;
10
11
use zerocopy::FromBytes;
12
use zerocopy::Immutable;
13
use zerocopy::IntoBytes;
14
15
/// SDT represents for System Description Table. The structure SDT is a
16
/// generic format for creating various ACPI tables like DSDT/FADT/MADT.
17
#[derive(Clone)]
18
pub struct SDT {
19
data: Vec<u8>,
20
}
21
22
pub const HEADER_LEN: u32 = 36;
23
const LENGTH_OFFSET: usize = 4;
24
const CHECKSUM_OFFSET: usize = 9;
25
26
#[allow(clippy::len_without_is_empty)]
27
impl SDT {
28
/// Set up the ACPI table header at the front of the SDT.
29
/// The arguments correspond to the elements in the ACPI
30
/// table headers.
31
pub fn new(
32
signature: [u8; 4],
33
length: u32,
34
revision: u8,
35
oem_id: [u8; 6],
36
oem_table: [u8; 8],
37
oem_revision: u32,
38
) -> Self {
39
// The length represents for the length of the entire table
40
// which includes this header. And the header is 36 bytes, so
41
// lenght should be >= 36. For the case who gives a number less
42
// than the header len, use the header len directly.
43
let len: u32 = if length < HEADER_LEN {
44
HEADER_LEN
45
} else {
46
length
47
};
48
let mut data = Vec::with_capacity(length as usize);
49
data.extend_from_slice(&signature);
50
data.extend_from_slice(&len.to_le_bytes());
51
data.push(revision);
52
data.push(0); // checksum
53
data.extend_from_slice(&oem_id);
54
data.extend_from_slice(&oem_table);
55
data.extend_from_slice(&oem_revision.to_le_bytes());
56
data.extend_from_slice(b"CROS");
57
data.extend_from_slice(&0u32.to_le_bytes());
58
59
data.resize(length as usize, 0);
60
let mut sdt = SDT { data };
61
62
sdt.update_checksum();
63
sdt
64
}
65
66
/// Set up the ACPI table from file content. Verify file checksum.
67
pub fn from_file(path: &Path) -> Result<Self> {
68
let mut file = File::open(path)?;
69
let mut data = Vec::new();
70
file.read_to_end(&mut data)?;
71
let checksum = super::generate_checksum(data.as_slice());
72
if checksum == 0 {
73
Ok(SDT { data })
74
} else {
75
Err(ErrorKind::InvalidData.into())
76
}
77
}
78
79
pub fn is_signature(&self, signature: &[u8; 4]) -> bool {
80
self.data[0..4] == *signature
81
}
82
83
fn update_checksum(&mut self) {
84
self.data[CHECKSUM_OFFSET] = 0;
85
let checksum = super::generate_checksum(self.data.as_slice());
86
self.data[CHECKSUM_OFFSET] = checksum;
87
}
88
89
pub fn as_slice(&self) -> &[u8] {
90
self.data.as_slice()
91
}
92
93
pub fn append<T: IntoBytes + Immutable>(&mut self, value: T) {
94
self.data.extend_from_slice(value.as_bytes());
95
self.write(LENGTH_OFFSET, self.data.len() as u32);
96
}
97
98
pub fn append_slice(&mut self, value: &[u8]) {
99
self.data.extend_from_slice(value);
100
self.write(LENGTH_OFFSET, self.data.len() as u32);
101
}
102
103
/// Read a value at the given offset
104
pub fn read<T: FromBytes + Default>(&self, offset: usize) -> T {
105
self.as_slice()
106
.get(offset..)
107
.and_then(|bytes| {
108
let (val, _) = T::read_from_prefix(bytes).ok()?;
109
Some(val)
110
})
111
.unwrap_or_default()
112
}
113
114
/// Write a value at the given offset
115
pub fn write<T: IntoBytes + Immutable>(&mut self, offset: usize, value: T) {
116
let value_len = std::mem::size_of::<T>();
117
if (offset + value_len) > self.data.len() {
118
return;
119
}
120
self.data[offset..offset + value_len].copy_from_slice(value.as_bytes());
121
self.update_checksum();
122
}
123
124
pub fn len(&self) -> usize {
125
self.data.len()
126
}
127
}
128
129
#[cfg(test)]
130
mod tests {
131
use std::io::Write;
132
133
use tempfile::NamedTempFile;
134
135
use super::SDT;
136
137
#[test]
138
fn test_sdt() {
139
let mut sdt = SDT::new(*b"TEST", 40, 1, *b"CROSVM", *b"TESTTEST", 1);
140
let sum: u8 = sdt
141
.as_slice()
142
.iter()
143
.fold(0u8, |acc, x| acc.wrapping_add(*x));
144
assert_eq!(sum, 0);
145
sdt.write(36, 0x12345678_u32);
146
let sum: u8 = sdt
147
.as_slice()
148
.iter()
149
.fold(0u8, |acc, x| acc.wrapping_add(*x));
150
assert_eq!(sum, 0);
151
}
152
153
#[test]
154
fn test_sdt_read_write() -> Result<(), std::io::Error> {
155
let temp_file = NamedTempFile::new()?;
156
let expected_sdt = SDT::new(*b"TEST", 40, 1, *b"CROSVM", *b"TESTTEST", 1);
157
158
// Write SDT to file.
159
{
160
let mut writer = temp_file.as_file();
161
writer.write_all(expected_sdt.as_slice())?;
162
}
163
164
// Read it back and verify.
165
let actual_sdt = SDT::from_file(temp_file.path())?;
166
assert!(actual_sdt.is_signature(b"TEST"));
167
assert_eq!(actual_sdt.as_slice(), expected_sdt.as_slice());
168
Ok(())
169
}
170
}
171
172