acpi/dsdt/
helpers.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4pub fn encode_name(name: &[u8]) -> Vec<u8> {
5    let mut encoded_name: Vec<u8> = Vec::new();
6    let mut segments: Vec<[u8; 4]> = Vec::new();
7    let mut i = 0;
8    if name[0] == b'\\' {
9        encoded_name.push(b'\\');
10        i = 1;
11    }
12    loop {
13        if i == name.len() {
14            break;
15        }
16
17        if name[i] == b'^' {
18            assert!(
19                (encoded_name.is_empty() || encoded_name[encoded_name.len() - 1] == b'^')
20                    && segments.is_empty()
21            );
22            encoded_name.push(b'^');
23            i += 1;
24            continue;
25        }
26
27        assert!((name[i] == b'_') || (name[i] >= b'A' && name[i] <= b'Z'));
28        let mut seg: [u8; 4] = [b'_'; 4];
29        let mut seg_i = 0;
30        loop {
31            let off = i + seg_i;
32            if off == name.len() || name[off] == b'.' {
33                break;
34            }
35
36            assert!(seg_i < 4);
37            assert!(
38                (name[off] == b'_')
39                    || (name[off] >= b'A' && name[off] <= b'Z')
40                    || (name[off] >= b'0' && name[off] <= b'9')
41            );
42            seg[seg_i] = name[off];
43            seg_i += 1
44        }
45        assert!(seg_i > 0);
46        segments.push(seg);
47        // advance past the last segment
48        i += seg_i;
49        if i < name.len() {
50            // advance past the segment divider '.'
51            i += 1;
52        }
53    }
54    if segments.len() > 2 {
55        encoded_name.push(0x2f);
56        encoded_name.push(u8::try_from(segments.len()).unwrap());
57    } else if segments.len() > 1 {
58        encoded_name.push(0x2e);
59    }
60    for seg in segments {
61        encoded_name.extend_from_slice(&seg);
62    }
63    encoded_name
64}
65
66pub fn encode_package_len(len: usize) -> Vec<u8> {
67    assert!(len < (1 << 28) - 1);
68    let mut result: Vec<u8> = Vec::new();
69    if len < 63 {
70        result.push(u8::try_from(len).unwrap() + 1);
71    } else {
72        // To store larger values, the length is stored in little-endian format, with the first byte encoding the
73        // number of additional bytes as well as the least-significant nibble. With a maximum of three additional
74        // bytes plus the extra nibble, the length can be up to 28 bits.
75        let len_bytes = if len < 1 << 12 {
76            2
77        } else if len < 1 << 20 {
78            3
79        } else {
80            4
81        };
82
83        let mut encoded_len: [u8; 4] = [0; 4];
84        let mut rem = len + len_bytes;
85        // byte count is in bits 6 and 7 and low nibble is in bits 0-3.
86        encoded_len[0] =
87            u8::try_from((len_bytes - 1) << 6).unwrap() | u8::try_from(rem & 0xf).unwrap();
88        rem >>= 4;
89        for e in encoded_len.iter_mut().take(len_bytes).skip(1) {
90            *e = u8::try_from(rem & 0xff).unwrap();
91            rem >>= 8;
92        }
93
94        result.extend_from_slice(&encoded_len[..len_bytes]);
95    }
96    result
97}
98
99pub fn encode_integer(value: u64) -> Vec<u8> {
100    let mut byte_stream: Vec<u8> = Vec::new();
101    let end;
102    if value == 0 {
103        // 0 has its own op
104        return vec![0];
105    } else if value == 1 {
106        // 1 has its own op
107        return vec![1];
108    } else if value <= 0xff {
109        byte_stream.push(0xa);
110        end = 1;
111    } else if value <= 0xffff {
112        byte_stream.push(0xb);
113        end = 2;
114    } else if value <= 0xffffffff {
115        byte_stream.push(0xc);
116        end = 4;
117    } else {
118        byte_stream.push(0xe);
119        end = 8;
120    }
121
122    let bytes = value.to_le_bytes();
123    byte_stream.extend_from_slice(&bytes[..end]);
124    byte_stream
125}
126
127pub fn encode_dword(value: u32) -> Vec<u8> {
128    let mut byte_stream = vec![0xcu8];
129    byte_stream.extend_from_slice(&value.to_le_bytes());
130    while byte_stream.len() < 5 {
131        byte_stream.push(0);
132    }
133    byte_stream
134}
135
136pub fn encode_string(value: &[u8]) -> Vec<u8> {
137    let mut byte_stream: Vec<u8> = Vec::new();
138    byte_stream.push(0xd);
139    byte_stream.extend_from_slice(value);
140    byte_stream.push(0);
141    byte_stream
142}
143
144pub fn char_to_hex(value: u8) -> u8 {
145    match value {
146        b'0'..=b'9' => value - b'0',
147        b'a'..=b'f' => 10 + value - b'a',
148        b'A'..=b'F' => 10 + value - b'A',
149        _ => panic!("Unsupported hex char {}", value),
150    }
151}
152
153#[cfg(test)]
154mod tests {
155    use super::*;
156    use crate::dsdt::tests::verify_expected_bytes;
157
158    #[test]
159    fn verify_simple_name() {
160        let bytes = encode_name(b"FOO");
161        verify_expected_bytes(&bytes, b"FOO_");
162    }
163
164    #[test]
165    fn verify_simple_name_with_root() {
166        let bytes = encode_name(b"\\FOO");
167        verify_expected_bytes(&bytes, b"\\FOO_");
168    }
169
170    #[test]
171    fn verify_simple_name_with_prefix() {
172        let bytes = encode_name(b"^FOO");
173        verify_expected_bytes(&bytes, b"^FOO_");
174    }
175
176    #[test]
177    fn verify_dual_name() {
178        let bytes = encode_name(b"FOO.BAR");
179        verify_expected_bytes(&bytes, b"\x2eFOO_BAR_");
180    }
181
182    #[test]
183    fn verify_dual_name_with_root() {
184        let bytes = encode_name(b"\\_SB.FOO");
185        verify_expected_bytes(&bytes, b"\\\x2e_SB_FOO_");
186    }
187
188    #[test]
189    fn verify_multi_name() {
190        let bytes = encode_name(b"FOO.BAR.BAZ.BLAM");
191        verify_expected_bytes(&bytes, b"\x2f\x04FOO_BAR_BAZ_BLAM");
192    }
193}