1use super::objects::*;
5
6pub trait ResourceObject {
7 fn append_to_vec(&self, byte_stream: &mut Vec<u8>);
8
9 fn to_bytes(&self) -> Vec<u8> {
10 let mut byte_stream = Vec::new();
11 self.append_to_vec(&mut byte_stream);
12 byte_stream
13 }
14}
15
16pub struct Memory32Fixed {
17 is_writeable: bool,
18 base_address: u32,
19 length: u32,
20}
21
22impl Memory32Fixed {
23 pub fn new(base_address: u32, length: u32, is_writeable: bool) -> Self {
24 Self {
25 is_writeable,
26 base_address,
27 length,
28 }
29 }
30}
31
32impl ResourceObject for Memory32Fixed {
33 fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
34 byte_stream.extend_from_slice(&[0x86, 9, 0]);
35 byte_stream.push(if self.is_writeable { 1 } else { 0 });
36 byte_stream.extend_from_slice(&self.base_address.to_le_bytes());
37 byte_stream.extend_from_slice(&self.length.to_le_bytes());
38 }
39}
40
41#[repr(u8)]
42#[derive(Copy, Clone, Debug)]
43pub enum MemoryAttribute {
44 Memory = 0,
45 _Reserved = 8,
46 _Acpi = 0x10,
47 _Nvs = 0x18,
48}
49
50#[repr(u8)]
51#[derive(Copy, Clone, Debug)]
52pub enum MemoryCacheType {
53 _NonCacheable = 0,
54 Cacheable = 2,
55 _CacheableWriteCombining = 4,
56 _CacheableAndPrefetchable = 6,
57}
58
59pub struct DwordMemory {
60 pub length: u32,
61 pub translation_offset: u32,
62 pub address_max: u32,
63 pub address_min: u32,
64 pub granularity: u32,
65 pub attributes: MemoryAttribute,
66 pub cacheability: MemoryCacheType,
67 pub is_writeable: bool,
68 pub is_max_address_fixed: bool,
69 pub is_min_address_fixed: bool,
70 pub is_subtractive_decode: bool,
71}
72
73impl ResourceObject for DwordMemory {
74 fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
75 byte_stream.extend_from_slice(&[0x87, 0x17, 0, 0]);
76 byte_stream.push(
77 if self.is_subtractive_decode { 2 } else { 0 }
78 | if self.is_min_address_fixed { 4 } else { 0 }
79 | if self.is_max_address_fixed { 8 } else { 0 },
80 );
81 byte_stream.push(
82 if self.is_writeable { 1 } else { 0 } | self.cacheability as u8 | self.attributes as u8,
83 );
84 byte_stream.extend_from_slice(&self.granularity.to_le_bytes());
85 byte_stream.extend_from_slice(&self.address_min.to_le_bytes());
86 byte_stream.extend_from_slice(&self.address_max.to_le_bytes());
87 byte_stream.extend_from_slice(&self.translation_offset.to_le_bytes());
88 byte_stream.extend_from_slice(&self.length.to_le_bytes());
89 }
90}
91
92#[cfg(test)]
93impl DwordMemory {
94 pub fn new(address: u32, length: u32) -> Self {
95 assert!(address as u64 + length as u64 - 1 <= u32::MAX as u64);
96 Self {
97 length,
98 translation_offset: 0,
99 address_max: address + (length - 1),
100 address_min: address,
101 granularity: 0,
102 attributes: MemoryAttribute::Memory,
103 cacheability: MemoryCacheType::Cacheable,
104 is_writeable: true,
105 is_max_address_fixed: true,
106 is_min_address_fixed: true,
107 is_subtractive_decode: false,
108 }
109 }
110}
111
112pub struct QwordMemory {
113 pub is_io_backed: bool,
114 pub attributes: MemoryAttribute,
115 pub cacheability: MemoryCacheType,
116 pub is_writeable: bool,
117 pub min_address: u64,
118 pub max_address: u64,
119 pub length: u64,
120}
121
122impl QwordMemory {
123 pub fn new(address: u64, length: u64) -> Self {
124 assert!(address as u128 + length as u128 - 1 <= u64::MAX as u128);
125 Self {
126 is_io_backed: false,
127 attributes: MemoryAttribute::Memory,
128 cacheability: MemoryCacheType::Cacheable,
129 is_writeable: true,
130 min_address: address,
131 max_address: address + (length - 1),
132 length,
133 }
134 }
135}
136
137impl ResourceObject for QwordMemory {
138 fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
139 byte_stream.extend_from_slice(&[0x8a, 0x2b, 0, 0, 0xc]);
140 byte_stream.push(
141 if self.is_io_backed { 0x20 } else { 0 }
142 | self.attributes as u8
143 | self.cacheability as u8
144 | if self.is_writeable { 1 } else { 0 },
145 );
146 byte_stream.extend_from_slice(&(0_u64).to_le_bytes()); byte_stream.extend_from_slice(&self.min_address.to_le_bytes());
148 byte_stream.extend_from_slice(&self.max_address.to_le_bytes());
149 byte_stream.extend_from_slice(&(0_u64).to_le_bytes()); byte_stream.extend_from_slice(&self.length.to_le_bytes());
151 }
152}
153
154pub struct BusNumber {
156 pub attributes: MemoryAttribute,
157 pub min_address: u16,
158 pub max_address: u16,
159 pub length: u16,
160}
161
162impl BusNumber {
163 pub fn new(address: u16, length: u16) -> Self {
165 Self {
166 attributes: MemoryAttribute::Memory,
167 min_address: address,
168 max_address: address + (length - 1),
169 length,
170 }
171 }
172}
173
174impl ResourceObject for BusNumber {
175 fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
176 byte_stream.extend_from_slice(&[0x88, 0x0d, 0, 2, 0x0c]);
177 byte_stream.push(0);
178 byte_stream.extend_from_slice(&(0u16).to_le_bytes()); byte_stream.extend_from_slice(&self.min_address.to_le_bytes());
180 byte_stream.extend_from_slice(&self.max_address.to_le_bytes());
181 byte_stream.extend_from_slice(&(0u16).to_le_bytes()); byte_stream.extend_from_slice(&self.length.to_le_bytes());
183 }
184}
185
186pub struct Interrupt {
187 pub is_wake_capable: bool,
188 pub is_shared: bool,
189 pub is_low_polarity: bool,
190 pub is_edge_triggered: bool,
191 pub is_consumer: bool,
192 number: u32,
193}
194
195impl Interrupt {
196 pub fn new(number: u32) -> Self {
197 Self {
198 is_wake_capable: false,
199 is_shared: false,
200 is_low_polarity: false,
201 is_edge_triggered: false,
202 is_consumer: true,
203 number,
204 }
205 }
206}
207
208impl ResourceObject for Interrupt {
209 fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
210 byte_stream.extend_from_slice(&[0x89, 6, 0]);
211 byte_stream.push(
212 if self.is_wake_capable { 0x10 } else { 0 }
213 | if self.is_shared { 8 } else { 0 }
214 | if self.is_low_polarity { 4 } else { 0 }
215 | if self.is_edge_triggered { 2 } else { 0 }
216 | if self.is_consumer { 1 } else { 0 },
217 );
218 byte_stream.push(1);
219 byte_stream.extend_from_slice(&self.number.to_le_bytes());
220 }
221}
222
223pub struct IoPort {
224 pub is_16bit_aware: bool,
225 pub base_address: u16,
226 pub end_address: u16,
227 pub alignment: u8,
228 pub length: u8,
229}
230
231impl IoPort {
232 pub fn new(start: u16, end: u16, length: u8) -> Self {
233 Self {
234 is_16bit_aware: true,
235 base_address: start,
236 end_address: end,
237 alignment: 1,
238 length,
239 }
240 }
241}
242
243impl ResourceObject for IoPort {
244 fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
245 byte_stream.push(0x47);
246 byte_stream.push(if self.is_16bit_aware { 1 } else { 0 });
247 byte_stream.extend_from_slice(&self.base_address.to_le_bytes());
248 byte_stream.extend_from_slice(&self.end_address.to_le_bytes());
249 byte_stream.push(self.alignment);
250 byte_stream.push(self.length);
251 }
252}
253
254pub struct CurrentResourceSettings {
255 resources: Vec<u8>,
256}
257
258impl CurrentResourceSettings {
259 pub fn new() -> Self {
260 Self { resources: vec![] }
261 }
262
263 pub fn add_resource(&mut self, resource: &impl ResourceObject) {
264 resource.append_to_vec(&mut self.resources);
265 }
266}
267
268impl DsdtObject for CurrentResourceSettings {
269 fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
270 let mut resource_bytes = self.resources.clone();
271 resource_bytes.extend_from_slice(&[0x79, 0]);
273
274 let nobj = NamedObject::new(b"_CRS", &Buffer(resource_bytes));
276 nobj.append_to_vec(byte_stream);
277 }
278}
279
280#[cfg(test)]
281mod tests {
282 use super::*;
283 use crate::dsdt::tests::verify_expected_bytes;
284
285 #[test]
286 fn verify_memory_resource_object() {
287 let memory = Memory32Fixed::new(0xfee00000, 0x1000, true);
288 let mut crs = CurrentResourceSettings::new();
289 crs.add_resource(&memory);
290 let bytes = crs.to_bytes();
291 verify_expected_bytes(
292 &bytes,
293 &[
294 0x08, b'_', b'C', b'R', b'S', 0x11, 17, 0x0a, 14, 0x86, 0x09, 0, 1, 0, 0, 0xe0,
295 0xfe, 0, 0x10, 0, 0, 0x79, 0,
296 ],
297 );
298 }
299
300 #[test]
301 fn verify_dword_memory_resource_object() {
302 let memory = DwordMemory::new(0x10000000, 0x10000000);
303 let mut crs = CurrentResourceSettings::new();
304 crs.add_resource(&memory);
305 let bytes = crs.to_bytes();
306 verify_expected_bytes(
307 &bytes,
308 &[
309 0x08, b'_', b'C', b'R', b'S', 0x11, 0x1f, 0x0a, 0x1c, 0x87, 0x17, 0x00, 0x00, 0x0C,
310 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0x1F, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x79, 0x00,
312 ],
313 );
314 }
315
316 #[test]
317 fn verify_qword_memory_resource_object() {
318 let memory = QwordMemory::new(0x100000000, 0x100000000);
319 let mut crs = CurrentResourceSettings::new();
320 crs.add_resource(&memory);
321 let bytes = crs.to_bytes();
322 verify_expected_bytes(
323 &bytes,
324 &[
325 0x08, b'_', b'C', b'R', b'S', 0x11, 51, 0x0a, 48, 0x8A, 0x2B, 0x00, 0x00, 0x0C,
326 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
327 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x79,
329 0x00,
330 ],
331 );
332 }
333
334 #[test]
335 fn verify_ioport_resource_object() {
336 let mut crs = CurrentResourceSettings::new();
337 crs.add_resource(&IoPort::new(0x3f8, 0x3f8, 8));
338 let bytes = crs.to_bytes();
339 verify_expected_bytes(
340 &bytes,
341 &[
342 0x08, b'_', b'C', b'R', b'S', 0x11, 13, 0x0a, 10, 0x47, 0x01, 0xF8, 0x03, 0xF8,
343 0x03, 0x01, 0x08, 0x79, 0x00,
344 ],
345 );
346 }
347
348 #[test]
349 fn verify_interrupt_resource_object() {
350 let mut crs = CurrentResourceSettings::new();
351 let mut interrupt = Interrupt::new(4);
352 interrupt.is_edge_triggered = true;
353 crs.add_resource(&interrupt);
354 let bytes = crs.to_bytes();
355 verify_expected_bytes(
356 &bytes,
357 &[
358 0x08, b'_', b'C', b'R', b'S', 0x11, 14, 0x0a, 11, 0x89, 0x06, 0x00, 0x03, 0x01,
359 0x04, 0x00, 0x00, 0x00, 0x79, 0x00,
360 ],
361 );
362 }
363
364 #[test]
365 fn verify_resource_object_multi() {
366 let mut crs = CurrentResourceSettings::new();
367 crs.add_resource(&Memory32Fixed::new(0xfee00000, 0x1000, true));
368 crs.add_resource(&Memory32Fixed::new(0xfec00000, 0x1000, true));
369 let bytes = crs.to_bytes();
370 verify_expected_bytes(
371 &bytes,
372 &[
373 0x08, b'_', b'C', b'R', b'S', 0x11, 0x1d, 0x0a, 0x1a, 0x86, 0x09, 0x00, 0x01, 0x00,
374 0x00, 0xe0, 0xFE, 0x00, 0x10, 0x00, 0x00, 0x86, 0x09, 0x00, 0x01, 0x00, 0x00, 0xC0,
375 0xFE, 0x00, 0x10, 0x00, 0x00, 0x79, 0x00,
376 ],
377 );
378 }
379
380 #[test]
381 fn verify_resource_object_multi2() {
382 let mut crs = CurrentResourceSettings::new();
383 crs.add_resource(&IoPort::new(0x3f8, 0x3f8, 8));
384 let mut interrupt = Interrupt::new(4);
385 interrupt.is_edge_triggered = true;
386 crs.add_resource(&interrupt);
387 let bytes = crs.to_bytes();
388 verify_expected_bytes(
389 &bytes,
390 &[
391 0x08, 0x5F, 0x43, 0x52, 0x53, 0x11, 0x16, 0x0A, 0x13, 0x47, 0x01, 0xF8, 0x03, 0xF8,
392 0x03, 0x01, 0x08, 0x89, 0x06, 0x00, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00, 0x79, 0x00,
393 ],
394 );
395 }
396}