acpi/aml/
ops.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Utilities for encoding procedural operations into ACPI
5//! Machine Language (AML).
6
7use super::helpers::encode_package_len;
8
9/// An AML operation.
10pub trait OperationObject {
11    fn append_to_vec(&self, byte_stream: &mut Vec<u8>);
12
13    fn to_bytes(&self) -> Vec<u8> {
14        let mut byte_stream = Vec::new();
15        self.append_to_vec(&mut byte_stream);
16        byte_stream
17    }
18}
19
20/// A bitwise AND AML operation.
21pub struct AndOp {
22    pub operand1: Vec<u8>,
23    pub operand2: Vec<u8>,
24    pub target_name: Vec<u8>,
25}
26
27impl OperationObject for AndOp {
28    fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
29        byte_stream.push(0x7b);
30        byte_stream.extend_from_slice(&self.operand1);
31        byte_stream.extend_from_slice(&self.operand2);
32        byte_stream.extend_from_slice(&self.target_name);
33    }
34}
35
36/// A bitwise OR AML operation.
37pub struct OrOp {
38    pub operand1: Vec<u8>,
39    pub operand2: Vec<u8>,
40    pub target_name: Vec<u8>,
41}
42
43impl OperationObject for OrOp {
44    fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
45        byte_stream.push(0x7d);
46        byte_stream.extend_from_slice(&self.operand1);
47        byte_stream.extend_from_slice(&self.operand2);
48        byte_stream.extend_from_slice(&self.target_name);
49    }
50}
51
52/// An AML If conditional operation.
53pub struct IfOp {
54    /// Pre-serialized predicate expression.
55    pub predicate: Vec<u8>,
56    /// Pre-serialized body operations.
57    pub body: Vec<u8>,
58}
59
60impl OperationObject for IfOp {
61    fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
62        byte_stream.push(0xa0); // IfOp
63        let inner_len = self.predicate.len() + self.body.len();
64        byte_stream.extend_from_slice(&encode_package_len(inner_len));
65        byte_stream.extend_from_slice(&self.predicate);
66        byte_stream.extend_from_slice(&self.body);
67    }
68}
69
70/// An AML Else operation (must follow an IfOp).
71pub struct ElseOp {
72    /// Pre-serialized body operations.
73    pub body: Vec<u8>,
74}
75
76impl OperationObject for ElseOp {
77    fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
78        byte_stream.push(0xa1); // ElseOp
79        byte_stream.extend_from_slice(&encode_package_len(self.body.len()));
80        byte_stream.extend_from_slice(&self.body);
81    }
82}
83
84/// An AML Store operation (Store source to destination).
85pub struct StoreOp {
86    /// Pre-serialized source operand.
87    pub source: Vec<u8>,
88    /// Pre-serialized destination (must be a SuperName — name, local, arg, etc.).
89    pub destination: Vec<u8>,
90}
91
92impl OperationObject for StoreOp {
93    fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
94        byte_stream.push(0x70); // StoreOp
95        byte_stream.extend_from_slice(&self.source);
96        byte_stream.extend_from_slice(&self.destination);
97    }
98}
99
100/// An AML LEqual comparison.
101pub struct LEqualOp {
102    /// Pre-serialized left operand.
103    pub left: Vec<u8>,
104    /// Pre-serialized right operand.
105    pub right: Vec<u8>,
106}
107
108impl OperationObject for LEqualOp {
109    fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
110        byte_stream.push(0x93); // LEqualOp
111        byte_stream.extend_from_slice(&self.left);
112        byte_stream.extend_from_slice(&self.right);
113    }
114}
115
116/// An AML CreateDWordField operation.
117pub struct CreateDWordFieldOp {
118    /// Pre-serialized source buffer.
119    pub source_buffer: Vec<u8>,
120    /// Pre-serialized byte index.
121    pub byte_index: Vec<u8>,
122    /// 4-byte field name.
123    pub field_name: [u8; 4],
124}
125
126impl OperationObject for CreateDWordFieldOp {
127    fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
128        byte_stream.push(0x8a); // CreateDWordFieldOp
129        byte_stream.extend_from_slice(&self.source_buffer);
130        byte_stream.extend_from_slice(&self.byte_index);
131        byte_stream.extend_from_slice(&self.field_name);
132    }
133}
134
135/// An AML operation to return from a procedure.
136pub struct ReturnOp {
137    pub result: Vec<u8>,
138}
139
140impl OperationObject for ReturnOp {
141    fn append_to_vec(&self, byte_stream: &mut Vec<u8>) {
142        byte_stream.push(0xa4);
143        byte_stream.extend_from_slice(&self.result);
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150    use crate::aml::encode_integer;
151    use crate::aml::test_helpers::verify_expected_bytes;
152
153    #[test]
154    fn verify_and_operation() {
155        let op = AndOp {
156            operand1: vec![b'S', b'T', b'A', b'_'],
157            operand2: encode_integer(13),
158            target_name: vec![b'S', b'T', b'A', b'_'],
159        };
160        let bytes = op.to_bytes();
161        verify_expected_bytes(
162            &bytes,
163            &[
164                0x7b, b'S', b'T', b'A', b'_', 0x0a, 0x0d, b'S', b'T', b'A', b'_',
165            ],
166        );
167    }
168
169    #[test]
170    fn verify_or_operation() {
171        let op = OrOp {
172            operand1: vec![b'S', b'T', b'A', b'_'],
173            operand2: encode_integer(13),
174            target_name: vec![b'S', b'T', b'A', b'_'],
175        };
176        let bytes = op.to_bytes();
177        verify_expected_bytes(
178            &bytes,
179            &[
180                0x7d, b'S', b'T', b'A', b'_', 0x0a, 0x0d, b'S', b'T', b'A', b'_',
181            ],
182        );
183    }
184
185    #[test]
186    fn verify_return_operation() {
187        let op = ReturnOp {
188            result: vec![b'S', b'T', b'A', b'_'],
189        };
190        let bytes = op.to_bytes();
191        verify_expected_bytes(&bytes, &[0xa4, b'S', b'T', b'A', b'_']);
192    }
193
194    #[test]
195    fn verify_if_operation() {
196        // If with a simple predicate (byte 0x01 = One) and empty body
197        let op = IfOp {
198            predicate: vec![0x01],
199            body: vec![],
200        };
201        let bytes = op.to_bytes();
202        // 0xa0 = IfOp, 0x02 = PkgLen (1 byte predicate + 0 body + 1 len byte), 0x01 = predicate
203        verify_expected_bytes(&bytes, &[0xa0, 0x02, 0x01]);
204    }
205
206    #[test]
207    fn verify_else_operation() {
208        // Else with a Return(One) body
209        let body = ReturnOp { result: vec![0x01] }.to_bytes();
210        let op = ElseOp { body };
211        let bytes = op.to_bytes();
212        // 0xa1 = ElseOp, 0x03 = PkgLen, 0xa4 = Return, 0x01 = One
213        verify_expected_bytes(&bytes, &[0xa1, 0x03, 0xa4, 0x01]);
214    }
215
216    #[test]
217    fn verify_store_operation() {
218        let op = StoreOp {
219            source: encode_integer(0),
220            destination: vec![b'S', b'T', b'S', b'0'],
221        };
222        let bytes = op.to_bytes();
223        // 0x70 = StoreOp, 0x00 = Zero, STS0 = destination
224        verify_expected_bytes(&bytes, &[0x70, 0x00, b'S', b'T', b'S', b'0']);
225    }
226
227    #[test]
228    fn verify_lequal_operation() {
229        let op = LEqualOp {
230            left: vec![0x68],  // Arg0
231            right: vec![0x01], // One
232        };
233        let bytes = op.to_bytes();
234        // 0x93 = LEqualOp, 0x68 = Arg0, 0x01 = One
235        verify_expected_bytes(&bytes, &[0x93, 0x68, 0x01]);
236    }
237
238    #[test]
239    fn verify_create_dword_field_operation() {
240        let op = CreateDWordFieldOp {
241            source_buffer: vec![0x6b], // Arg3
242            byte_index: encode_integer(0),
243            field_name: *b"STS0",
244        };
245        let bytes = op.to_bytes();
246        // 0x8a = CreateDWordFieldOp, 0x6b = Arg3, 0x00 = Zero (index), STS0 = name
247        verify_expected_bytes(&bytes, &[0x8a, 0x6b, 0x00, b'S', b'T', b'S', b'0']);
248    }
249}