Coverage Report

Created: 2025-07-14 07:05

/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
}