1pub use crate::aml::*;
5use memory_range::MemoryRange;
6use zerocopy::FromBytes;
7use zerocopy::Immutable;
8use zerocopy::IntoBytes;
9use zerocopy::KnownLayout;
10
11#[repr(C, packed)]
12#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
13pub struct DescriptionHeader {
14 pub signature: u32,
15 _length: u32, pub revision: u8,
17 _checksum: u8, pub oem_id: [u8; 6],
19 pub oem_table_id: u64,
20 pub oem_revision: u32,
21 pub creator_id: u32,
22 pub creator_rev: u32,
23}
24
25fn encode_pcie_name(mut pcie_index: u32) -> Vec<u8> {
26 assert!(pcie_index < 1000);
27 let mut temp = "PCI0".as_bytes().to_vec();
28 let mut i = temp.len() - 1;
29 while pcie_index > 0 {
30 temp[i] = b'0' + (pcie_index % 10) as u8;
31 pcie_index /= 10;
32 i -= 1;
33 }
34 temp
35}
36
37pub struct Ssdt {
38 description_header: DescriptionHeader,
39 objects: Vec<u8>,
40 pcie_ecam_ranges: Vec<MemoryRange>,
41}
42
43impl Ssdt {
44 pub fn new() -> Self {
45 Self {
46 description_header: DescriptionHeader {
47 signature: u32::from_le_bytes(*b"SSDT"),
48 _length: 0,
49 revision: 2,
50 _checksum: 0,
51 oem_id: *b"MSFTVM",
52 oem_table_id: 0x313054445353, oem_revision: 1,
54 creator_id: u32::from_le_bytes(*b"MSFT"),
55 creator_rev: 0x01000000,
56 },
57 objects: vec![],
58 pcie_ecam_ranges: vec![],
59 }
60 }
61
62 pub fn to_bytes(&self) -> Vec<u8> {
63 let mut byte_stream = Vec::new();
64 byte_stream.extend_from_slice(self.description_header.as_bytes());
65 byte_stream.extend_from_slice(&self.objects);
66
67 if !self.pcie_ecam_ranges.is_empty() {
70 let mut vmod = Device::new(b"VMOD");
71 vmod.add_object(&NamedObject::new(b"_HID", &EisaId(*b"PNP0C02")));
72
73 let mut crs = CurrentResourceSettings::new();
74 for ecam_range in &self.pcie_ecam_ranges {
75 crs.add_resource(&QwordMemory::new(
76 ecam_range.start(),
77 ecam_range.end() - ecam_range.start(),
78 ));
79 }
80 vmod.add_object(&crs);
81 vmod.append_to_vec(&mut byte_stream);
82 }
83
84 let length = byte_stream.len();
85 byte_stream[4..8].copy_from_slice(&u32::try_from(length).unwrap().to_le_bytes());
86 let mut checksum: u8 = 0;
87 for byte in &byte_stream {
88 checksum = checksum.wrapping_add(*byte);
89 }
90
91 byte_stream[9] = (!checksum).wrapping_add(1);
92 byte_stream
93 }
94
95 pub fn add_object(&mut self, obj: &impl AmlObject) {
96 obj.append_to_vec(&mut self.objects);
97 }
98
99 pub fn add_pcie(
118 &mut self,
119 index: u32,
120 segment: u16,
121 start_bus: u8,
122 end_bus: u8,
123 ecam_range: MemoryRange,
124 low_mmio: MemoryRange,
125 high_mmio: MemoryRange,
126 ) {
127 let mut pcie = Device::new(encode_pcie_name(index).as_slice());
128 pcie.add_object(&NamedObject::new(b"_HID", &EisaId(*b"PNP0A08")));
129 pcie.add_object(&NamedObject::new(b"_CID", &EisaId(*b"PNP0A03")));
130 pcie.add_object(&NamedInteger::new(b"_UID", index.into()));
131 pcie.add_object(&NamedInteger::new(b"_SEG", segment.into()));
132 pcie.add_object(&NamedInteger::new(b"_BBN", start_bus.into()));
133
134 let mut osc_method = Method::new(b"_OSC");
158 osc_method.set_arg_count(4);
159
160 osc_method.add_operation(&CreateDWordFieldOp {
162 source_buffer: encode_arg(3),
163 byte_index: encode_integer(0),
164 field_name: *b"STS0",
165 });
166
167 let pcie_osc_uuid = guid::guid!("33DB4D5B-1FF7-401C-9657-7441C03DD766");
169 let uuid_buffer = Buffer(pcie_osc_uuid.as_bytes()).to_bytes();
170 let lequal = LEqualOp {
171 left: encode_arg(0),
172 right: uuid_buffer,
173 };
174
175 let or_op = OrOp {
177 operand1: b"STS0".to_vec(),
178 operand2: encode_integer(0x04),
179 target_name: b"STS0".to_vec(),
180 };
181 let else_body = ElseOp {
182 body: or_op.to_bytes(),
183 };
184
185 let store_zero = StoreOp {
187 source: encode_integer(0),
188 destination: b"STS0".to_vec(),
189 };
190 let if_op = IfOp {
191 predicate: lequal.to_bytes(),
192 body: store_zero.to_bytes(),
193 };
194 osc_method.add_operation(&if_op);
195 osc_method.add_operation(&else_body);
196
197 osc_method.add_operation(&ReturnOp {
199 result: encode_arg(3),
200 });
201
202 pcie.add_object(&osc_method);
203
204 let mut crs = CurrentResourceSettings::new();
205 crs.add_resource(&BusNumber::new(
206 start_bus.into(),
207 (end_bus as u16) - (start_bus as u16) + 1,
208 ));
209 crs.add_resource(&QwordMemory::new(
210 low_mmio.start(),
211 low_mmio.end() - low_mmio.start(),
212 ));
213 crs.add_resource(&QwordMemory::new(
214 high_mmio.start(),
215 high_mmio.end() - high_mmio.start(),
216 ));
217 pcie.add_object(&crs);
218
219 self.add_object(&pcie);
220 self.pcie_ecam_ranges.push(ecam_range);
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227 use crate::aml::test_helpers::verify_expected_bytes;
228
229 pub fn verify_header(bytes: &[u8]) {
230 assert!(bytes.len() >= 36);
231
232 assert_eq!(bytes[0], b'S');
234 assert_eq!(bytes[1], b'S');
235 assert_eq!(bytes[2], b'D');
236 assert_eq!(bytes[3], b'T');
237
238 let ssdt_len = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
240 assert_eq!(ssdt_len as usize, bytes.len());
241
242 assert_eq!(bytes[8], 2);
244
245 let mut checksum: u8 = 0;
247 for byte in bytes.iter() {
248 checksum = checksum.wrapping_add(*byte);
249 }
250 assert_eq!(checksum, 0);
251
252 assert_eq!(bytes[10], b'M');
254 assert_eq!(bytes[11], b'S');
255 assert_eq!(bytes[12], b'F');
256 assert_eq!(bytes[13], b'T');
257 assert_eq!(bytes[14], b'V');
258 assert_eq!(bytes[15], b'M');
259
260 assert_eq!(bytes[16], b'S');
262 assert_eq!(bytes[17], b'S');
263 assert_eq!(bytes[18], b'D');
264 assert_eq!(bytes[19], b'T');
265 assert_eq!(bytes[20], b'0');
266 assert_eq!(bytes[21], b'1');
267 assert_eq!(bytes[22], 0);
268 assert_eq!(bytes[23], 0);
269
270 let oem_revision = u32::from_le_bytes(bytes[24..28].try_into().unwrap());
272 assert_eq!(oem_revision, 1);
273
274 assert_eq!(bytes[28], b'M');
276 assert_eq!(bytes[29], b'S');
277 assert_eq!(bytes[30], b'F');
278 assert_eq!(bytes[31], b'T');
279
280 let creator_rev = u32::from_le_bytes(bytes[32..36].try_into().unwrap());
282 assert_eq!(creator_rev, 0x01000000);
283 }
284
285 #[test]
286 pub fn verify_pcie_name_encoding() {
287 assert_eq!(encode_pcie_name(0), b"PCI0".to_vec());
288 assert_eq!(encode_pcie_name(1), b"PCI1".to_vec());
289 assert_eq!(encode_pcie_name(2), b"PCI2".to_vec());
290 assert_eq!(encode_pcie_name(54), b"PC54".to_vec());
291 assert_eq!(encode_pcie_name(294), b"P294".to_vec());
292 }
293
294 #[test]
295 fn verify_simple_table() {
296 let mut ssdt = Ssdt::new();
297 let nobj = NamedObject::new(b"_S0", &Package(vec![0, 0]));
298 ssdt.add_object(&nobj);
299 let bytes = ssdt.to_bytes();
300 verify_header(&bytes);
301 verify_expected_bytes(&bytes[36..], &[8, b'_', b'S', b'0', b'_', 0x12, 4, 2, 0, 0]);
302 }
303}