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