acpi/dsdt/
resources.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use 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()); // granularity
147        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()); // translation offset
150        byte_stream.extend_from_slice(&self.length.to_le_bytes());
151    }
152}
153
154/// An ACPI bus number.
155pub 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    /// Constructs a new bus number.
164    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()); // granularity
179        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()); // translation offset
182        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        // Add end of resource marker
272        resource_bytes.extend_from_slice(&[0x79, 0]);
273
274        // Generate _CRS buffer
275        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}