acpi/aml/
devices.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Utilities for encoding devices into ACPI Machine Language (AML).
5
6use super::helpers::*;
7use super::objects::*;
8use super::ops::*;
9
10/// An AML Method
11pub struct Method {
12    pub name: [u8; 4],
13    pub sync_level: u8,
14    pub is_serialized: bool,
15    pub arg_count: u8,
16    operations: Vec<u8>,
17}
18
19impl Method {
20    /// Constructs a new [`Method`].
21    pub fn new(name: &[u8; 4]) -> Self {
22        let local_name: [u8; 4] = [name[0], name[1], name[2], name[3]];
23        Self {
24            name: local_name,
25            sync_level: 0,
26            is_serialized: false,
27            arg_count: 0,
28            operations: vec![],
29        }
30    }
31
32    /// Set the number of arguments the method accepts.
33    pub fn set_arg_count(&mut self, arg_count: u8) {
34        self.arg_count = arg_count;
35    }
36
37    /// Add an operation to the method body.
38    pub fn add_operation(&mut self, op: &impl OperationObject) {
39        op.append_to_vec(&mut self.operations);
40    }
41}
42
43impl AmlObject for Method {
44    fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
45        byte_stream.push(0x14);
46        byte_stream.extend_from_slice(&encode_package_len(5 + self.operations.len()));
47        byte_stream.extend_from_slice(&self.name);
48        byte_stream.push(
49            self.sync_level << 4 | if self.is_serialized { 1 << 3 } else { 0 } | self.arg_count,
50        );
51        byte_stream.extend_from_slice(&self.operations);
52    }
53}
54
55/// An AML Device
56pub struct Device {
57    name: Vec<u8>,
58    objects: Vec<u8>,
59}
60
61impl Device {
62    /// Construct a new [`Device`]
63    pub fn new(name: &[u8]) -> Self {
64        Self {
65            name: encode_name(name),
66            objects: vec![],
67        }
68    }
69
70    /// Add an object to the body of the device.
71    pub fn add_object(&mut self, obj: &impl AmlObject) {
72        obj.append_to_vec(&mut self.objects);
73    }
74}
75
76impl AmlObject for Device {
77    // A device object consists of the extended identifier (0x5b 0x82) followed by the length, the name and then the
78    // contained objects.
79    fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
80        byte_stream.push(0x5b);
81        byte_stream.push(0x82);
82        let length = self.name.len() + self.objects.len();
83        byte_stream.extend_from_slice(&encode_package_len(length));
84        byte_stream.extend_from_slice(&self.name);
85        byte_stream.extend_from_slice(&self.objects);
86    }
87}
88
89/// An EISA identifier for a device.
90pub struct EisaId(pub [u8; 7]);
91
92impl AmlObject for EisaId {
93    fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
94        let mut id: [u8; 4] = [0; 4];
95        id[0] = (self.0[0] - b'@') << 2 | (self.0[1] - b'@') >> 3;
96        id[1] = (self.0[1] & 7) << 5 | (self.0[2] - b'@');
97        id[2] = char_to_hex(self.0[3]) << 4 | char_to_hex(self.0[4]);
98        id[3] = char_to_hex(self.0[5]) << 4 | char_to_hex(self.0[6]);
99        byte_stream.append(&mut encode_integer(u32::from_le_bytes(id) as u64));
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106    use crate::aml::test_helpers::verify_expected_bytes;
107
108    #[test]
109    fn verify_eisaid() {
110        let eisa_id = EisaId(*b"PNP0003");
111        let bytes = eisa_id.to_bytes();
112        verify_expected_bytes(&bytes, &[0xc, 0x41, 0xd0, 0, 0x3]);
113    }
114
115    #[test]
116    fn verify_method() {
117        let op = AndOp {
118            operand1: vec![b'S', b'T', b'A', b'_'],
119            operand2: encode_integer(13),
120            target_name: vec![b'S', b'T', b'A', b'_'],
121        };
122        let mut method = Method::new(b"_DIS");
123        method.add_operation(&op);
124        let bytes = method.to_bytes();
125        verify_expected_bytes(
126            &bytes,
127            &[
128                0x14, 0x11, 0x5F, 0x44, 0x49, 0x53, 0x00, 0x7b, b'S', b'T', b'A', b'_', 0x0a, 0x0d,
129                b'S', b'T', b'A', b'_',
130            ],
131        );
132    }
133
134    #[test]
135    fn verify_device_object() {
136        let package = Package(vec![0]);
137        let nobj = NamedObject::new(b"FOO", &package);
138        let mut device = Device::new(b"DEV");
139        device.add_object(&nobj);
140        let bytes = device.to_bytes();
141        verify_expected_bytes(
142            &bytes,
143            &[
144                0x5b, 0x82, 14, b'D', b'E', b'V', b'_', 8, b'F', b'O', b'O', b'_', 0x12, 3, 1, 0,
145            ],
146        );
147    }
148}