/src/MigTD/deps/td-shim/td-shim-interface/src/acpi.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2021 Intel Corporation |
2 | | // Copyright (c) 2022 Alibaba Cloud |
3 | | // |
4 | | // SPDX-License-Identifier: BSD-2-Clause-Patent |
5 | | use core::mem::size_of; |
6 | | use zerocopy::{AsBytes, FromBytes, FromZeroes}; |
7 | | |
8 | | pub const ACPI_TABLES_MAX_NUM: usize = 20; |
9 | | pub const ACPI_RSDP_REVISION: u8 = 2; |
10 | | |
11 | | #[derive(Debug, PartialEq, Eq)] |
12 | | pub enum Error { |
13 | | InvalidParameter, |
14 | | TooManyAcpiTables, |
15 | | } |
16 | | |
17 | | pub fn calculate_checksum(data: &[u8]) -> u8 { |
18 | 0 | (255 - data.iter().fold(0u8, |acc, x| acc.wrapping_add(*x))).wrapping_add(1) |
19 | | } |
20 | | |
21 | | #[repr(packed)] |
22 | | #[derive(Default, AsBytes, FromBytes, FromZeroes)] |
23 | | pub struct Rsdp { |
24 | | pub signature: [u8; 8], |
25 | | pub checksum: u8, |
26 | | pub oem_id: [u8; 6], |
27 | | pub revision: u8, |
28 | | pub _rsdt_addr: u32, |
29 | | pub length: u32, |
30 | | pub xsdt_addr: u64, |
31 | | pub extended_checksum: u8, |
32 | | pub _reserved: [u8; 3], |
33 | | } |
34 | | |
35 | | impl Rsdp { |
36 | | pub fn new(xsdt_addr: u64) -> Rsdp { |
37 | | let mut rsdp = Rsdp { |
38 | | signature: *b"RSD PTR ", |
39 | | checksum: 0, |
40 | | oem_id: *b"INTEL ", |
41 | | revision: ACPI_RSDP_REVISION, |
42 | | length: size_of::<Rsdp>() as u32, |
43 | | xsdt_addr, |
44 | | ..Default::default() |
45 | | }; |
46 | | rsdp.checksum(); |
47 | | rsdp |
48 | | } |
49 | | |
50 | | pub fn set_xsdt(&mut self, xsdt: u64) { |
51 | | self.xsdt_addr = xsdt; |
52 | | self.checksum(); |
53 | | } |
54 | | |
55 | | fn checksum(&mut self) { |
56 | | self.checksum = 0; |
57 | | self.extended_checksum = 0; |
58 | | self.checksum = calculate_checksum(&self.as_bytes()[0..20]); |
59 | | self.extended_checksum = calculate_checksum(self.as_bytes()); |
60 | | } |
61 | | } |
62 | | |
63 | | #[repr(C, packed)] |
64 | | #[derive(Default, AsBytes, FromBytes, FromZeroes)] |
65 | | pub struct GenericSdtHeader { |
66 | | pub signature: [u8; 4], |
67 | | pub length: u32, |
68 | | pub revision: u8, |
69 | | pub checksum: u8, |
70 | | pub oem_id: [u8; 6], |
71 | | pub oem_table_id: u64, |
72 | | pub oem_revision: u32, |
73 | | pub creator_id: u32, |
74 | | pub creator_revision: u32, |
75 | | } |
76 | | |
77 | | impl GenericSdtHeader { |
78 | | pub fn new(signature: &[u8; 4], length: u32, revision: u8) -> Self { |
79 | | GenericSdtHeader { |
80 | | signature: *signature, |
81 | | length, |
82 | | revision, |
83 | | checksum: 0, |
84 | | oem_id: *b"INTEL ", |
85 | | oem_table_id: u64::from_le_bytes(*b"SHIM "), |
86 | | oem_revision: 1, |
87 | | creator_id: u32::from_le_bytes(*b"SHIM"), |
88 | | creator_revision: 1, |
89 | | } |
90 | | } |
91 | | |
92 | | pub fn set_checksum(&mut self, checksum: u8) { |
93 | | self.checksum = checksum; |
94 | | } |
95 | | } |
96 | | |
97 | | #[repr(C, packed)] |
98 | | #[derive(Default, AsBytes, FromBytes, FromZeroes)] |
99 | | pub struct Xsdt { |
100 | | pub header: GenericSdtHeader, |
101 | | pub tables: [u64; ACPI_TABLES_MAX_NUM], |
102 | | } |
103 | | |
104 | | impl Xsdt { |
105 | | pub fn new() -> Self { |
106 | | Xsdt { |
107 | | header: GenericSdtHeader::new(b"XSDT", size_of::<GenericSdtHeader>() as u32, 1), |
108 | | tables: [0; ACPI_TABLES_MAX_NUM], |
109 | | } |
110 | | } |
111 | | |
112 | | pub fn add_table(&mut self, addr: u64) -> Result<(), Error> { |
113 | | if self.header.length < size_of::<GenericSdtHeader>() as u32 { |
114 | | Err(Error::InvalidParameter) |
115 | | } else { |
116 | | let table_num = |
117 | | (self.header.length as usize - size_of::<GenericSdtHeader>()) / size_of::<u64>(); |
118 | | if table_num < ACPI_TABLES_MAX_NUM { |
119 | | self.tables[table_num] = addr; |
120 | | self.header.length += size_of::<u64>() as u32; |
121 | | Ok(()) |
122 | | } else { |
123 | | Err(Error::TooManyAcpiTables) |
124 | | } |
125 | | } |
126 | | } |
127 | | |
128 | | pub fn checksum(&mut self) { |
129 | | self.header.set_checksum(0); |
130 | | self.header.set_checksum(calculate_checksum( |
131 | | &self.as_bytes()[..self.header.length as usize], |
132 | | )); |
133 | | } |
134 | | } |
135 | | |
136 | | #[repr(C, packed)] |
137 | | #[derive(Default, AsBytes, FromBytes, FromZeroes)] |
138 | | pub struct Ccel { |
139 | | pub header: GenericSdtHeader, |
140 | | pub cc_type: u8, |
141 | | pub cc_subtype: u8, |
142 | | pub reserved: u16, |
143 | | pub laml: u64, |
144 | | pub lasa: u64, |
145 | | } |
146 | | |
147 | | impl Ccel { |
148 | | pub fn new(cc_type: u8, cc_subtype: u8, laml: u64, lasa: u64) -> Ccel { |
149 | | let mut ccel = Ccel { |
150 | | header: GenericSdtHeader::new(b"CCEL", size_of::<Ccel>() as u32, 1), |
151 | | cc_type, |
152 | | cc_subtype, |
153 | | reserved: 0, |
154 | | laml, |
155 | | lasa, |
156 | | }; |
157 | | ccel.checksum(); |
158 | | ccel |
159 | | } |
160 | | |
161 | | pub fn checksum(&mut self) { |
162 | | self.header.checksum = 0; |
163 | | self.header |
164 | | .set_checksum(calculate_checksum(self.as_bytes())); |
165 | | } |
166 | | } |
167 | | |
168 | | #[cfg(test)] |
169 | | mod tests { |
170 | | use super::*; |
171 | | |
172 | | #[test] |
173 | | fn test_calculate_checksum() { |
174 | | let mut buf = [0xac; 8]; |
175 | | buf[7] = 0; |
176 | | buf[7] = calculate_checksum(&buf); |
177 | | let sum = buf.iter().fold(0u8, |s, v| s.wrapping_add(*v)); |
178 | | assert_eq!(sum, 0); |
179 | | |
180 | | buf[3] = 0xcd; |
181 | | buf[6] = 0x1c; |
182 | | buf[4] = 0; |
183 | | buf[4] = calculate_checksum(&buf); |
184 | | let sum = buf.iter().fold(0u8, |s, v| s.wrapping_add(*v)); |
185 | | assert_eq!(sum, 0); |
186 | | } |
187 | | |
188 | | #[test] |
189 | | fn test_rsdp() { |
190 | | let mut rsdp = Rsdp::new(0xabcd1234); |
191 | | let sum = rsdp.as_bytes()[0..20] |
192 | | .iter() |
193 | | .fold(0u8, |s, v| s.wrapping_add(*v)); |
194 | | assert_eq!(sum, 0); |
195 | | let sum = rsdp.as_bytes().iter().fold(0u8, |s, v| s.wrapping_add(*v)); |
196 | | assert_eq!(sum, 0); |
197 | | |
198 | | rsdp.set_xsdt(0xdeadbeaf); |
199 | | let sum = rsdp.as_bytes()[0..20] |
200 | | .iter() |
201 | | .fold(0u8, |s, v| s.wrapping_add(*v)); |
202 | | assert_eq!(sum, 0); |
203 | | let sum = rsdp.as_bytes().iter().fold(0u8, |s, v| s.wrapping_add(*v)); |
204 | | assert_eq!(sum, 0); |
205 | | } |
206 | | |
207 | | #[test] |
208 | | fn test_xsdt() { |
209 | | const CHECK_SUM: u8 = 186; |
210 | | let mut xsdt = Xsdt::new(); |
211 | | assert_eq!(xsdt.header.length as usize, size_of::<GenericSdtHeader>()); |
212 | | for idx in 0..ACPI_TABLES_MAX_NUM { |
213 | | assert!(!xsdt.add_table(idx as u64).is_err()); |
214 | | assert_eq!( |
215 | | xsdt.header.length as usize, |
216 | | size_of::<GenericSdtHeader>() + (idx + 1) * 8 |
217 | | ); |
218 | | } |
219 | | |
220 | | assert!(xsdt |
221 | | .add_table(100) |
222 | | .is_err_and(|e| e == Error::TooManyAcpiTables)); |
223 | | assert_eq!( |
224 | | xsdt.header.length as usize, |
225 | | size_of::<GenericSdtHeader>() + ACPI_TABLES_MAX_NUM * 8 |
226 | | ); |
227 | | assert!(xsdt |
228 | | .add_table(101) |
229 | | .is_err_and(|e| e == Error::TooManyAcpiTables)); |
230 | | assert_eq!( |
231 | | xsdt.header.length as usize, |
232 | | size_of::<GenericSdtHeader>() + ACPI_TABLES_MAX_NUM * 8 |
233 | | ); |
234 | | |
235 | | xsdt.checksum(); |
236 | | assert_eq!(xsdt.header.checksum, CHECK_SUM); |
237 | | } |
238 | | |
239 | | #[test] |
240 | | fn test_ccel() { |
241 | | let ccel = Ccel::new(2, 0, 0x100, 0); |
242 | | |
243 | | assert_eq!(&ccel.header.signature, b"CCEL"); |
244 | | assert_eq!(ccel.header.checksum, 45); |
245 | | } |
246 | | } |