Skip to main content

aarch32_cpu/register/hyp/
hsr.rs

1//! Code for managing HSR (*Hyp Syndrome Register*)
2
3use crate::register::{SysReg, SysRegRead, SysRegWrite};
4
5use arbitrary_int::{u2, u25, u3, u4, u6};
6
7/// HSR (*Hyp Syndrome Register*)
8#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
9pub struct Hsr {
10    /// Exception Class.
11    ///
12    /// Indicates the reason for the exception that this register holds
13    /// information about.
14    #[bits(26..=31, rw)]
15    ec: Option<ExceptionClass>,
16    /// Instruction length bit.
17    ///
18    /// Indicates the size of the instruction that has been trapped to Hyp mode.
19    #[bit(25, rw)]
20    il: InstructionLength,
21    /// Instruction Specific Syndrome.
22    ///
23    /// Architecturally, this field can be defined independently for each
24    /// defined Exception class. However, in practice, some ISS encodings are
25    /// used for more than one Exception class.
26    #[bits(0..=24, rw)]
27    iss: u25,
28}
29
30impl Hsr {
31    /// Get the ISS value from the HSR
32    pub fn get_iss(&self) -> Option<Iss> {
33        if let Ok(ec) = self.ec() {
34            Some(ec.decode_iss(self.iss()))
35        } else {
36            None
37        }
38    }
39}
40
41#[bitbybit::bitenum(u6, exhaustive = false)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44#[derive(Debug, PartialEq, Eq)]
45/// Exception Class value from the HSR (*Hyp Syndrome Register*)
46pub enum ExceptionClass {
47    /// Unknown reason
48    Unknown = 0b00_0000,
49    /// Trapped WFI or WFE instruction execution
50    TrappedWfiWfe = 0b00_0001,
51    /// Trapped MCR or MRC access with (coproc==`0b1111`) that is not reported using EC value `0b000000``
52    TrappedCp15McrMrc = 0b00_0011,
53    /// Trapped MCRR or MRRC access with (coproc==`0b1111`) that is not reported using EC value `0b000000``
54    TrappedCp15McrrMrrc = 0b00_0100,
55    /// Trapped MCR or MRC access with (coproc==`0b1110``)
56    TrappedCp14McrMrc = 0b00_0101,
57    /// Trapped LDC or STC access
58    TrappedLdcStc = 0b00_0110,
59    /// Access to Advanced SIMD or floating-point functionality trapped by a `HCPTR.{TASE, TCP10}` control
60    TrappedFpu = 0b00_0111,
61    /// Trapped VMRS access, from ID group trap, that is not reported using EC value `0b000111`
62    TrappedVmrs = 0b00_1000,
63    /// Trapped MRRC access with (coproc==`0b1110`)
64    TrappedCp14McrrMrrc = 0b00_1100,
65    /// Illegal exception return to AArch32 state
66    IllegalAArch32Eret = 0b00_1110,
67    /// Exception on SVC instruction execution in AArch32 state routed to EL2
68    Svc = 0b01_0001,
69    /// HVC instruction execution in AArch32 state, when HVC is not disabled
70    Hvc = 0b01_0010,
71    /// Trapped execution of SMC instruction in AArch32 state
72    Smc = 0b01_0011,
73    /// Prefetch Abort from a lower Exception level
74    PrefetchAbortFromLower = 0b10_0000,
75    /// Prefetch Abort taken without a change in Exception level
76    PrefetchAbortFromCurrent = 0b10_0001,
77    /// PC alignment fault exception
78    PcAlignment = 0b10_0010,
79    /// Data Abort exception from a lower Exception level
80    DataAbortFromLower = 0b10_0100,
81    /// Data Abort exception taken without a change in Exception level
82    DataAbortFromCurrent = 0b10_0101,
83}
84
85/// A decoded ISS
86///
87/// ISS is a 25 bit field whose meaning varies depending on the value of the EC field.
88#[derive(Debug, Clone)]
89pub enum Iss {
90    /// ISS for [`ExceptionClass::Unknown`]
91    Unknown(IssUnknown),
92    /// ISS for [`ExceptionClass::TrappedWfiWfe`]
93    TrappedWfiWfe(IssTrappedWfiWfe),
94    /// ISS for [`ExceptionClass::TrappedCp15McrMrc`]
95    TrappedCp15McrMrc(IssTrappedMcrMrc),
96    /// ISS for [`ExceptionClass::TrappedCp15McrrMrrc`]
97    TrappedCp15McrrMrrc(IssTrappedMcrrMrrc),
98    /// ISS for [`ExceptionClass::TrappedCp14McrMrc`]
99    TrappedCp14McrMrc(IssTrappedMcrMrc),
100    /// ISS for [`ExceptionClass::TrappedLdcStc`]
101    TrappedLdcStc(IssTrappedLdcStc),
102    /// ISS for [`ExceptionClass::TrappedFpu`]
103    TrappedFpu(IssTrappedFpu),
104    /// ISS for [`ExceptionClass::TrappedVmrs`]
105    TrappedVmrs(IssTrappedVmrs),
106    /// ISS for [`ExceptionClass::TrappedCp14McrrMrrc`]
107    TrappedCp14McrrMrrc(IssTrappedMcrrMrrc),
108    /// ISS for [`ExceptionClass::IllegalAArch32Eret`]
109    IllegalAArch32Eret,
110    /// ISS for [`ExceptionClass::Svc`]
111    Svc(IssCall),
112    /// ISS for [`ExceptionClass::Hvc`]
113    Hvc(IssCall),
114    /// ISS for [`ExceptionClass::Smc`]
115    Smc(IssSmc),
116    /// ISS for [`ExceptionClass::PrefetchAbortFromLower`]
117    PrefetchAbortFromLower(IssPrefetchAbort),
118    /// ISS for [`ExceptionClass::PrefetchAbortFromCurrent`]
119    PrefetchAbortFromCurrent(IssPrefetchAbort),
120    /// ISS for [`ExceptionClass::PcAlignment`]
121    PcAlignment,
122    /// ISS for [`ExceptionClass::DataAbortFromLower`]
123    DataAbortFromLower(IssDataAbort),
124    /// ISS for [`ExceptionClass::DataAbortFromCurrent`]
125    DataAbortFromCurrent(IssDataAbort),
126}
127
128impl ExceptionClass {
129    /// Convert an ISS value based on the Exception Class
130    pub fn decode_iss(&self, iss: u25) -> Iss {
131        match self {
132            ExceptionClass::Unknown => Iss::Unknown(IssUnknown(iss.value())),
133            ExceptionClass::TrappedWfiWfe => {
134                Iss::TrappedWfiWfe(IssTrappedWfiWfe::new_with_raw_value(iss))
135            }
136            ExceptionClass::TrappedCp15McrMrc => {
137                Iss::TrappedCp15McrMrc(IssTrappedMcrMrc::new_with_raw_value(iss))
138            }
139            ExceptionClass::TrappedCp15McrrMrrc => {
140                Iss::TrappedCp15McrrMrrc(IssTrappedMcrrMrrc::new_with_raw_value(iss))
141            }
142            ExceptionClass::TrappedCp14McrMrc => {
143                Iss::TrappedCp14McrMrc(IssTrappedMcrMrc::new_with_raw_value(iss))
144            }
145            ExceptionClass::TrappedLdcStc => {
146                Iss::TrappedLdcStc(IssTrappedLdcStc::new_with_raw_value(iss))
147            }
148            ExceptionClass::TrappedFpu => Iss::TrappedFpu(IssTrappedFpu::new_with_raw_value(iss)),
149            ExceptionClass::TrappedVmrs => Iss::TrappedVmrs(IssTrappedVmrs(iss.value())),
150            ExceptionClass::TrappedCp14McrrMrrc => {
151                Iss::TrappedCp14McrrMrrc(IssTrappedMcrrMrrc::new_with_raw_value(iss))
152            }
153            ExceptionClass::IllegalAArch32Eret => Iss::IllegalAArch32Eret,
154            ExceptionClass::Svc => Iss::Svc(IssCall::new_with_raw_value(iss)),
155            ExceptionClass::Hvc => Iss::Hvc(IssCall::new_with_raw_value(iss)),
156            ExceptionClass::Smc => Iss::Smc(IssSmc(iss.value())),
157            ExceptionClass::PrefetchAbortFromLower => {
158                Iss::PrefetchAbortFromLower(IssPrefetchAbort::new_with_raw_value(iss))
159            }
160            ExceptionClass::PrefetchAbortFromCurrent => {
161                Iss::PrefetchAbortFromCurrent(IssPrefetchAbort::new_with_raw_value(iss))
162            }
163            ExceptionClass::PcAlignment => Iss::PcAlignment,
164            ExceptionClass::DataAbortFromLower => {
165                Iss::DataAbortFromLower(IssDataAbort::new_with_raw_value(iss))
166            }
167            ExceptionClass::DataAbortFromCurrent => {
168                Iss::DataAbortFromCurrent(IssDataAbort::new_with_raw_value(iss))
169            }
170        }
171    }
172}
173
174/// The ISS field when EC = ExceptionClass::Unknown
175///
176/// All bits are reserved
177#[derive(Debug, Copy, Clone, PartialEq, Eq)]
178pub struct IssUnknown(pub u32);
179
180/// The ISS field when EC = ExceptionClass::TrappedWfiWfe
181#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
182pub struct IssTrappedWfiWfe {
183    /// Condition code valid
184    #[bit(24, r)]
185    cv: bool,
186    /// Condition code
187    #[bits(20..=23, r)]
188    cc: u4,
189    /// Trapped Instruction is WFE
190    #[bit(0, r)]
191    ti: bool,
192}
193
194/// The ISS field when EC = ExceptionClass::TrappedCp15McrMrc or ExceptionClass::TrappedCp14McrMrc
195#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
196pub struct IssTrappedMcrMrc {
197    /// Condition code valid
198    #[bit(24, r)]
199    cv: bool,
200    /// Condition code
201    #[bits(20..=23, r)]
202    cc: u4,
203    /// OPC2 value from instruction
204    #[bits(17..=19, r)]
205    opc2: u3,
206    /// OPC1 value from instruction
207    #[bits(14..=16, r)]
208    opc1: u3,
209    /// CRn value from instruction
210    #[bits(10..=13, r)]
211    crn: u4,
212    /// Rt value from instruction
213    #[bits(5..=8, r)]
214    rt: u4,
215    /// CRm value from instruction
216    #[bits(1..=4, r)]
217    crm: u4,
218    /// Direction (true = read, false = write)
219    #[bit(0, r)]
220    is_read: bool,
221}
222
223/// The ISS field when EC = ExceptionClass::TrappedCp15McrrMrrc or ExceptionClass::TrappedCp14McrrMrrc
224#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
225pub struct IssTrappedMcrrMrrc {
226    /// Condition code valid
227    #[bit(24, r)]
228    cv: bool,
229    /// Condition code
230    #[bits(20..=23, r)]
231    cc: u4,
232    /// OPC2 value from instruction
233    #[bits(16..=19, r)]
234    opc2: u4,
235    /// Rt2 value from instruction
236    #[bits(10..=13, r)]
237    rt2: u4,
238    /// Rt value from instruction
239    #[bits(5..=8, r)]
240    rt: u4,
241    /// CRm value from instruction
242    #[bits(1..=4, r)]
243    crm: u4,
244    /// Direction (true = read, false = write)
245    #[bit(0, r)]
246    is_read: bool,
247}
248
249/// The ISS field when EC = ExceptionClass::TrappedLdcStc
250#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
251pub struct IssTrappedLdcStc {
252    /// Condition code valid
253    #[bit(24, r)]
254    cv: bool,
255    /// Condition code
256    #[bits(20..=23, r)]
257    cc: u4,
258    /// The immediate value from the instruction
259    #[bits(12..=19, r)]
260    imm8: u8,
261    /// Rn value from instruction
262    #[bits(5..=8, r)]
263    rn: u4,
264    /// Whether offset is added (true) or subtracted (false)
265    #[bit(4, r)]
266    offset: bool,
267    /// Addressing Mode
268    #[bits(1..=3, r)]
269    am: u3,
270    /// Direction (true = read, false = write)
271    #[bit(0, r)]
272    is_read: bool,
273}
274
275/// The ISS field when EC = ExceptionClass::TrappedFpu
276#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
277pub struct IssTrappedFpu {
278    /// Condition code valid
279    #[bit(24, r)]
280    cv: bool,
281    /// Condition code
282    #[bits(20..=23, r)]
283    cc: u4,
284    /// Trapped Advanced SIMD
285    #[bit(5, r)]
286    ta: bool,
287    /// CoProc Bits
288    #[bits(0..=3, r)]
289    coproc: u4,
290}
291
292/// The ISS field when EC = ExceptionClass::TrappedVmrs
293#[derive(Debug, Copy, Clone, PartialEq, Eq)]
294pub struct IssTrappedVmrs(pub u32);
295
296/// The ISS field when EC = ExceptionClass::Svc
297#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
298pub struct IssCall {
299    /// Immediate value from instruction
300    #[bits(0..=15, r)]
301    imm16: u16,
302}
303
304/// The ISS field when EC = ExceptionClass::Smc
305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
306pub struct IssSmc(pub u32);
307
308/// The ISS field when EC = ExceptionClass::PrefetchAbortFromLower or ExceptionClass::PrefetchAbortFromCurrent
309#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
310pub struct IssPrefetchAbort {
311    /// FAR not Valid, for a Synchronous External abort.
312    #[bit(10, r)]
313    fnv: bool,
314    /// External Abort Type.
315    ///
316    /// External = true, anything else = false
317    #[bit(9, r)]
318    ea: bool,
319    /// Instruction Fault Status Code
320    #[bits(0..=5, r)]
321    ifsc: u6,
322}
323
324/// The ISS field when EC = ExceptionClass::DataAbortFromLower or ExceptionClass::DataAbortFromCurrent
325#[bitbybit::bitfield(u25, debug, defmt_bitfields(feature = "defmt"))]
326pub struct IssDataAbort {
327    /// Instruction Syndrome Valid
328    #[bit(24, r)]
329    isv: bool,
330    /// Syndrome Access Size
331    #[bits(22..=23, r)]
332    sas: u2,
333    /// Syndrome Sign Extend
334    #[bit(21, r)]
335    sae: bool,
336    /// Syndrome Register transfer
337    #[bits(16..=19, r)]
338    srt: u4,
339    /// Acquire/Release
340    #[bit(14, r)]
341    ar: bool,
342    /// FAR not Valid
343    #[bit(10, r)]
344    fnv: bool,
345    /// External Abort Type.
346    ///
347    /// External = true, anything else = false
348    #[bit(9, r)]
349    ea: bool,
350    /// Cache maintenance
351    #[bit(8, r)]
352    cm: bool,
353    /// Write not Read
354    #[bit(6, r)]
355    wnr: bool,
356    /// Data Fault Status Code
357    #[bits(0..=5, r)]
358    dfsc: u6,
359}
360
361#[bitbybit::bitenum(u1, exhaustive = true)]
362#[cfg_attr(feature = "defmt", derive(defmt::Format))]
363#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
364#[derive(Debug, PartialEq, Eq)]
365/// The length of the instruction that trapped
366pub enum InstructionLength {
367    /// A 16-bit instruction
368    SixteenBit = 0b0,
369    /// A 32-bit instruction
370    ThirtyTwoBit = 0b1,
371}
372
373impl SysReg for Hsr {
374    const CP: u32 = 15;
375    const CRN: u32 = 5;
376    const OP1: u32 = 4;
377    const CRM: u32 = 2;
378    const OP2: u32 = 0;
379}
380
381impl crate::register::SysRegRead for Hsr {}
382
383impl Hsr {
384    #[inline]
385    /// Reads HSR (*Hyp Syndrome Register*)
386    pub fn read() -> Hsr {
387        Self::new_with_raw_value(<Self as SysRegRead>::read_raw())
388    }
389}
390
391impl crate::register::SysRegWrite for Hsr {}
392
393impl Hsr {
394    #[inline]
395    /// Writes HSR (*Hyp Syndrome Register*)
396    ///
397    /// # Safety
398    ///
399    /// Ensure that this value is appropriate for this register
400    pub unsafe fn write(value: Self) {
401        unsafe {
402            <Self as SysRegWrite>::write_raw(value.raw_value());
403        }
404    }
405}