aarch64_esr_decoder/
lib.rs

1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Library for decoding aarch64 Exception Syndrome Register and Main ID Register values.
16
17mod esr;
18mod midr;
19mod smccc;
20
21use bit_field::BitField;
22pub use esr::decode;
23pub use midr::decode_midr;
24pub use smccc::decode_smccc;
25use std::fmt::{self, Debug, Display, Formatter};
26use std::num::ParseIntError;
27use thiserror::Error;
28
29/// Information about a particular field.
30#[derive(Clone, Debug, Eq, PartialEq)]
31pub struct FieldInfo {
32    /// The short name of the field, e.g. "ISS".
33    pub name: &'static str,
34    /// The long name of the field, e.g. "Instruction Specific Syndrome".
35    pub long_name: Option<&'static str>,
36    /// The index of the lowest bit of the field.
37    pub start: usize,
38    /// The number of bits in the field.
39    pub width: usize,
40    /// The value of the field.
41    pub value: u64,
42    /// A description explaining the field value, if available.
43    pub description: Option<String>,
44    /// Any sub-fields.
45    pub subfields: Vec<FieldInfo>,
46}
47
48impl FieldInfo {
49    fn get(
50        register: u64,
51        name: &'static str,
52        long_name: Option<&'static str>,
53        start: usize,
54        end: usize,
55    ) -> Self {
56        let value = register.get_bits(start..end);
57        Self {
58            name,
59            long_name,
60            start,
61            width: end - start,
62            value,
63            description: None,
64            subfields: vec![],
65        }
66    }
67
68    fn get_bit(
69        register: u64,
70        name: &'static str,
71        long_name: Option<&'static str>,
72        bit: usize,
73    ) -> Self {
74        Self::get(register, name, long_name, bit, bit + 1)
75    }
76
77    fn with_description(self, description: String) -> Self {
78        Self {
79            description: Some(description),
80            ..self
81        }
82    }
83
84    fn as_bit(&self) -> bool {
85        assert!(self.width == 1);
86        self.value == 1
87    }
88
89    /// Assuming this field has a width of exactly 1, describe it with the given function.
90    ///
91    /// Panics if `self.width != 1`.
92    fn describe_bit<F>(self, describer: F) -> Self
93    where
94        F: FnOnce(bool) -> &'static str,
95    {
96        let bit = self.as_bit();
97        let description = describer(bit).to_string();
98        self.with_description(description)
99    }
100
101    fn describe<F>(self, describer: F) -> Result<Self, DecodeError>
102    where
103        F: FnOnce(u64) -> Result<&'static str, DecodeError>,
104    {
105        let description = describer(self.value)?.to_string();
106        Ok(self.with_description(description))
107    }
108
109    fn check_res0(self) -> Result<Self, DecodeError> {
110        if self.value != 0 {
111            Err(DecodeError::InvalidRes0 { res0: self.value })
112        } else {
113            Ok(self)
114        }
115    }
116
117    /// Returns the value as a hexadecimal string, or "true" or "false" if it is a single bit.
118    pub fn value_string(&self) -> String {
119        if self.width == 1 {
120            if self.value == 1 { "true" } else { "false" }.to_string()
121        } else {
122            format!("{:#01$x}", self.value, self.width.div_ceil(4) + 2,)
123        }
124    }
125
126    /// Returns the value as a binary strings.
127    pub fn value_binary_string(&self) -> String {
128        format!("{:#01$b}", self.value, self.width + 2)
129    }
130}
131
132impl Display for FieldInfo {
133    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
134        if self.width == 1 {
135            write!(
136                f,
137                "{}: {}",
138                self.name,
139                if self.value == 1 { "true" } else { "false" }
140            )
141        } else {
142            write!(
143                f,
144                "{}: {} {}",
145                self.name,
146                self.value_string(),
147                self.value_binary_string(),
148            )
149        }
150    }
151}
152
153/// An error decoding a register value.
154#[derive(Debug, Error)]
155pub enum DecodeError {
156    /// A RES0 field was not 0.
157    #[error("Invalid ESR, res0 is {res0:#x}")]
158    InvalidRes0 { res0: u64 },
159    /// The EC field had an invalid value.
160    #[error("Invalid EC {ec:#x}")]
161    InvalidEc { ec: u64 },
162    /// The DFSC or IFSC field had an invalid value.
163    #[error("Invalid DFSC or IFSC {fsc:#x}")]
164    InvalidFsc { fsc: u64 },
165    /// The SET field had an invalid value.
166    #[error("Invalid SET {set:#x}")]
167    InvalidSet { set: u64 },
168    /// The AET field had an invalid value.
169    #[error("Invalid AET {aet:#x}")]
170    InvalidAet { aet: u64 },
171    /// The AM field had an invalid value.
172    #[error("Invalid AM {am:#x}")]
173    InvalidAm { am: u64 },
174    /// The ISS field has an invalid value for a trapped LD64B or ST64B* exception.
175    #[error("Invalid ISS {iss:#x} for trapped LD64B or ST64B*")]
176    InvalidLd64bIss { iss: u64 },
177}
178
179/// Parses a decimal or hexadecimal number from a string.
180///
181/// If the string starts with `"0x"` then it will be parsed as hexadecimal, otherwise it will be
182/// assumed to be decimal.
183pub fn parse_number(s: &str) -> Result<u64, ParseIntError> {
184    if let Some(hex) = s.strip_prefix("0x") {
185        u64::from_str_radix(hex, 16)
186    } else {
187        s.parse()
188    }
189}
190
191#[cfg(test)]
192mod tests {
193    use super::*;
194
195    #[test]
196    fn parse_decimal() {
197        assert_eq!(parse_number("12345"), Ok(12345));
198    }
199
200    #[test]
201    fn parse_hex() {
202        assert_eq!(parse_number("0x123abc"), Ok(0x123abc));
203    }
204
205    #[test]
206    fn parse_invalid() {
207        assert!(parse_number("123abc").is_err());
208    }
209}