Skip to main content

device_driver_mir/
runtime.rs

1//! The runtime assumes all objects passed here have gone through all of the MIR passes
2
3use std::fmt::Display;
4
5use device_driver_common::{
6    interner::Istr,
7    specifiers::{BaseType, ByteOrder, Integer, RepeatSource},
8};
9
10use crate::model::{Enum, Field, FieldSet, Manifest, Object};
11
12#[derive(Debug)]
13pub struct DecodedFieldset {
14    pub fields: Vec<DecodedField>,
15}
16
17#[derive(Debug)]
18pub struct DecodedField {
19    pub name: Istr,
20    pub index_name: Option<String>,
21    pub base_value: FieldBaseValue,
22    pub converted_value: Option<String>,
23}
24
25#[derive(Debug)]
26pub enum FieldBaseValue {
27    Integer(i128),
28    Bool(bool),
29}
30
31impl Display for FieldBaseValue {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        match self {
34            FieldBaseValue::Integer(val) => write!(f, "{val}"),
35            FieldBaseValue::Bool(val) => write!(f, "{val}"),
36        }
37    }
38}
39
40impl FieldBaseValue {
41    pub fn as_integer(&self) -> Option<i128> {
42        if let Self::Integer(v) = self {
43            Some(*v)
44        } else {
45            None
46        }
47    }
48}
49
50pub fn decode_fieldset(
51    manifest: &Manifest,
52    fieldset_model: &FieldSet,
53    bytes: &[u8],
54) -> Result<DecodedFieldset, DecodeError> {
55    if bytes.len() != fieldset_model.size_bytes.value as usize {
56        return Err(DecodeError::SizeBytesMismatch);
57    }
58
59    let mut fields = Vec::new();
60
61    for field_id in fieldset_model.fields.iter() {
62        let field = manifest.fields.get(*field_id).unwrap();
63
64        let offsets = field
65            .repeat
66            .as_ref()
67            .map(|repeat| match &repeat.source.value {
68                RepeatSource::Count(non_zero) => (0..non_zero.get())
69                    .map(|index| (index as i128 * repeat.stride.value, Some(index.to_string())))
70                    .collect(),
71                RepeatSource::Enum(identifier_ref) => {
72                    let enum_model = manifest
73                        .search_object(identifier_ref)
74                        .unwrap()
75                        .as_enum()
76                        .unwrap();
77                    enum_model
78                        .iter_variants_with_discriminant(&manifest.enum_variants)
79                        .map(|(index, variant_id)| {
80                            (
81                                index * repeat.stride.value,
82                                Some(
83                                    manifest
84                                        .enum_variants
85                                        .get(variant_id)
86                                        .unwrap()
87                                        .name
88                                        .original()
89                                        .to_string(),
90                                ),
91                            )
92                        })
93                        .collect()
94                }
95            })
96            .unwrap_or_else(|| vec![(0, None)]);
97
98        for (offset, index_name) in offsets {
99            let start =
100                (field.field_address.start as usize).strict_add_signed(offset.try_into().unwrap());
101            let end =
102                (field.field_address.end as usize).strict_add_signed(offset.try_into().unwrap());
103
104            let value = match field.base_type.value {
105                BaseType::Bool => FieldBaseValue::Bool(
106                    load_integer(
107                        bytes,
108                        fieldset_model.byte_order.unwrap(),
109                        Integer::U8,
110                        start,
111                        end,
112                    ) != 0,
113                ),
114                BaseType::FixedSize(integer) => FieldBaseValue::Integer(load_integer(
115                    bytes,
116                    fieldset_model.byte_order.unwrap(),
117                    integer,
118                    start,
119                    end,
120                )),
121                BaseType::Unspecified | BaseType::Uint | BaseType::Int => unreachable!(),
122            };
123
124            fields.push(decode_field(manifest, field, index_name, value));
125        }
126    }
127
128    Ok(DecodedFieldset { fields })
129}
130
131pub fn decode_field(
132    manifest: &Manifest,
133    field_model: &Field,
134    index_name: Option<String>,
135    value: FieldBaseValue,
136) -> DecodedField {
137    let converted_value = if let Some(conversion) = &field_model.field_conversion {
138        let target_type = manifest.search_type(&conversion.type_ref.value).unwrap();
139        match target_type {
140            Object::Enum(e) => match decode_enum(manifest, e, value.as_integer().unwrap()) {
141                Ok(active_variant) => Some(format!("{}::{active_variant}", e.name.original())),
142                Err(e) => Some(format!("<{e}>")),
143            },
144            Object::Extern(_) => Some("<extern>".into()),
145            _ => unreachable!(),
146        }
147    } else {
148        None
149    };
150
151    DecodedField {
152        name: field_model.name.original(),
153        index_name,
154        base_value: value,
155        converted_value,
156    }
157}
158
159pub fn decode_enum(
160    manifest: &Manifest,
161    enum_model: &Enum,
162    value: i128,
163) -> Result<Istr, DecodeError> {
164    let mut fallback_variant = None;
165
166    for (variant_value, variant_id) in
167        enum_model.iter_variants_with_discriminant(&manifest.enum_variants)
168    {
169        let variant = manifest.enum_variants.get(variant_id).unwrap();
170
171        if variant_value == value {
172            return Ok(variant.name.original());
173        }
174
175        if variant.value.is_catch_all() {
176            // Catch-all trumps default
177            fallback_variant = Some(variant.name.original());
178        }
179        if variant.value.is_default() && fallback_variant.is_none() {
180            // Only take default if not already set
181            fallback_variant = Some(variant.name.original());
182        }
183    }
184
185    if let Some(fallback) = fallback_variant {
186        return Ok(fallback);
187    }
188
189    Err(DecodeError::InvalidValue)
190}
191
192pub enum DecodeError {
193    InvalidValue,
194    SizeBytesMismatch,
195}
196
197impl Display for DecodeError {
198    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199        match self {
200            DecodeError::InvalidValue => write!(f, "invalid value"),
201            DecodeError::SizeBytesMismatch => write!(f, "size-bytes mismatch"),
202        }
203    }
204}
205
206pub fn load_integer(
207    bytes: &[u8],
208    byte_order: ByteOrder,
209    base_type: Integer,
210    start: usize,
211    end: usize,
212) -> i128 {
213    let mut val = 0;
214
215    for index in start..=end {
216        let byte_index = match byte_order {
217            ByteOrder::LE => index / 8,
218            ByteOrder::BE => bytes.len() - (index / 8) - 1,
219        };
220        let bit_index = index % 8;
221
222        let byte = bytes[byte_index];
223        let bit = byte & (1 << bit_index);
224
225        if bit > 0 {
226            let val_bit_index = index - start;
227            val |= 1 << val_bit_index;
228        }
229    }
230
231    if base_type.is_signed() {
232        // Sign extend if required
233        let sign_bit_index = end - start;
234        if val & (1 << sign_bit_index) > 0 {
235            val |= !0i128 << sign_bit_index;
236        }
237    }
238
239    val
240}
241
242#[cfg(test)]
243mod tests {
244    use super::*;
245
246    #[test]
247    fn load_unsigned_integer() {
248        assert_eq!(
249            load_integer(&0b1101u16.to_le_bytes(), ByteOrder::LE, Integer::U8, 0, 3),
250            0b1101
251        );
252        assert_eq!(
253            load_integer(&0b1101u16.to_le_bytes(), ByteOrder::LE, Integer::U8, 1, 3),
254            0b110
255        );
256        assert_eq!(
257            load_integer(&0b1101u16.to_le_bytes(), ByteOrder::LE, Integer::U8, 0, 2),
258            0b101
259        );
260
261        assert_eq!(
262            load_integer(&0b1101u16.to_be_bytes(), ByteOrder::BE, Integer::U8, 0, 3),
263            0b1101
264        );
265        assert_eq!(
266            load_integer(&0b1101u16.to_be_bytes(), ByteOrder::BE, Integer::U8, 1, 3),
267            0b110
268        );
269        assert_eq!(
270            load_integer(&0b1101u16.to_be_bytes(), ByteOrder::BE, Integer::U8, 0, 2),
271            0b101
272        );
273    }
274
275    #[test]
276    fn load_signed_integer() {
277        assert_eq!(
278            load_integer(&(-5i16).to_le_bytes(), ByteOrder::LE, Integer::I8, 0, 3),
279            -5
280        );
281        assert_eq!(
282            load_integer(&(-5i16).to_be_bytes(), ByteOrder::BE, Integer::I8, 0, 3),
283            -5
284        );
285    }
286}