Skip to main content

libarch/arm64/
system.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use bitrs::{bitfield_repr, layout, multilayout};
6use regio::arm64::{SysReg, spec};
7
8use super::PhysicalAddressSize;
9
10/// [arm/sysreg]/currentel: CurrentEL, Current Exception Level
11pub const CURRENT_EL: SysReg<spec::CurrentEL, CurrentEl> = SysReg::new();
12
13layout!({
14    /// The layout of [`CURRENT_EL`].
15    pub struct CurrentEl(u64);
16    {
17        let __ @ 63..4;
18        let el @ 3..2;
19        let __ @ 1..0;
20    }
21});
22
23/// [arm/sysreg]/mpidr_el1: Multiprocessor Affinity Register (EL1)
24pub const MPIDR_EL1: SysReg<spec::MPIDR_EL1, MultiprocessorAffinityRegister> = SysReg::new();
25
26layout!({
27    /// The layout of [`MPIDR_EL1`] and `VMPIDR_EL2`.
28    pub struct MultiprocessorAffinityRegister(u64);
29    {
30        let __ @ 63..40;
31        let aff3 @ 39..32; // Affinity level 3
32        let __ @ 31 = 1;
33        let u @ 30; // Uniprocessor system
34        let __ @ 29..25;
35        let mt @ 24; // Multithreading
36        let aff2 @ 23..16; // Affinity level 2
37        let aff1 @ 15..8; // Affinity level 1
38        let aff0 @ 7..0; // Affinity level 0
39    }
40});
41
42impl MultiprocessorAffinityRegister {
43    const AFFINITY_MASK: u64 = MultiprocessorAffinityRegister::AFF3_MASK
44        | MultiprocessorAffinityRegister::AFF2_MASK
45        | MultiprocessorAffinityRegister::AFF1_MASK
46        | MultiprocessorAffinityRegister::AFF0_MASK;
47
48    /// Returns the full affinity value (bits [39:32], [23:16], [15:8], and [7:0]).
49    pub fn affinity(&self) -> u64 {
50        self.bits() & Self::AFFINITY_MASK
51    }
52}
53
54/// [arm/sysreg]/sctlr_el1: System Control Register (EL1)
55pub const SCTLR_EL1: SysReg<spec::SCTLR_EL1, SystemControlRegisterEl1> = SysReg::new();
56
57/// [arm/sysreg]/sctlr_el2: System Control Register (EL2)
58pub const SCTLR_EL2: SysReg<spec::SCTLR_EL2, SystemControlRegisterEl2> = SysReg::new();
59
60/// [arm/sysreg]/sctlr_el3: System Control Register (EL3)
61pub const SCTLR_EL3: SysReg<spec::SCTLR_EL3, SystemControlRegisterEl3> = SysReg::new();
62
63#[bitfield_repr(u8)]
64#[derive(Clone, Copy)]
65pub enum TagCheckFault {
66    None = 0b00,            // Faults have no effect.
67    Synchronous = 0b01,     // All faults cause a synchronous exception.
68    Asynchronous = 0b10,    // All faults accumulate asynchronously.
69    SynchronousRead = 0b11, // Synchronous for read, asynchronous for write.
70}
71
72multilayout!({
73    /// The layout of [`SCTLR_EL1`].
74    #[bitrs(el1)]
75    pub struct SystemControlRegisterEl1(u64);
76
77    /// The layout of [`SCTLR_EL2`].
78    #[bitrs(el2)]
79    pub struct SystemControlRegisterEl2(u64);
80
81    /// The layout of [`SCTLR_EL3`].
82    #[bitrs(el3)]
83    pub struct SystemControlRegisterEl3(u64);
84
85    // EL1, EL2, EL3
86    {
87        let spintmask @ 62;
88        let nmi @ 61;
89        let tsco @ 59;
90        let tme @ 53;
91        let tmt @ 51;
92        let dsbss @ 44;
93        let ata @ 43;
94        let tcf @ 41..40: TagCheckFault;
95        let itfsb @ 37;
96        let bt @ 36;
97        let __ @ 34;
98        let enia @ 31;
99        let enib @ 30;
100        let enda @ 27;
101        let ee @ 25;
102        let eis @ 22;
103        let iesb @ 21;
104        let wxn @ 19;
105        let __ @ 17;
106        let dze @ 14;
107        let endb @ 13;
108        let i @ 12;
109        let eos @ 11;
110        let naa @ 6;
111        let sa @ 3;
112        let c @ 2;
113        let a @ 1;
114        let m @ 0;
115    }
116
117    // EL1, EL2
118    #[any(el1, el2)]
119    {
120        let tidcp @ 63;
121        let entp2 @ 60;
122        let tsco0 @ 58;
123        let epan @ 57;
124        let enals @ 56;
125        let enas0 @ 55;
126        let enasr @ 54;
127        let tme0 @ 52;
128        let tmt0 @ 50;
129        let mscen @ 33;
130        let cmow @ 32;
131    }
132
133    // EL1
134    #[el1]
135    {
136        let twedel @ 49..46;
137        let tweden @ 45;
138        let ata0 @ 42;
139        let tcf0 @ 39..38: TagCheckFault;
140        let bt0 @ 35;
141        let lsmaoe @ 29;
142        let ntlsmd @ 28;
143        let uci @ 26;
144        let e0e @ 24;
145        let span @ 23;
146        let tscxt @ 20;
147        let ntwe @ 18;
148        let ntwi @ 16;
149        let uct @ 15;
150        let enrctx @ 10;
151        let uma @ 9;
152        let sed @ 8;
153        let itd @ 7;
154        let cp15ben @ 5;
155        let sa0 @ 4;
156    }
157});
158
159impl SystemControlRegisterEl1 {
160    /// Returns the minimum delay in cycles if TWEDEn is enabled.
161    pub fn twedel_cycles(&self) -> Option<u64> {
162        if self.tweden() { Some(1u64 << self.twedel() << 8) } else { None }
163    }
164}
165
166/// [arm/sysreg]/sctlr2_el1: System Control Register 2 (EL1)
167pub const SCTLR2_EL1: SysReg<spec::SCTLR2_EL1, SystemControlRegister2El1> = SysReg::new();
168
169/// [arm/sysreg]/sctlr2_el2: System Control Register 2 (EL2)
170pub const SCTLR2_EL2: SysReg<spec::SCTLR2_EL2, SystemControlRegister2El2> = SysReg::new();
171
172/// [arm/sysreg]/sctlr2_el3: System Control Register 2 (EL3)
173pub const SCTLR2_EL3: SysReg<spec::SCTLR2_EL3, SystemControlRegister2El3> = SysReg::new();
174
175multilayout!({
176    /// The layout of [`SCTLR2_EL1`].
177    #[bitrs(el1)]
178    pub struct SystemControlRegister2El1(u64);
179
180    /// The layout of [`SCTLR2_EL2`].
181    #[bitrs(el2)]
182    pub struct SystemControlRegister2El2(u64);
183
184    /// The layout of [`SCTLR2_EL3`].
185    #[bitrs(el3)]
186    pub struct SystemControlRegister2El3(u64);
187
188    // EL1, EL2, EL3
189    {
190        let __ @ 63..7;
191        let enanerr @ 4;
192        let enaderr @ 3;
193        let __ @ 0;
194    }
195
196    // EL1, EL2
197    #[any(el1, el2)]
198    {
199        let enidcp128 @ 6;
200        let ease @ 5;
201        let nmea @ 2;
202    }
203
204    // EL2, EL3
205    #[any(el2, el3)]
206    {
207        let emec @ 1;
208    }
209});
210
211/// [arm/sysreg]/scr_el3: Secure Configuration Register
212pub const SCR_EL3: SysReg<spec::SCR_EL3, SecureConfigurationRegister> = SysReg::new();
213
214layout!({
215    /// The layout of [`SCR_EL3`].
216    pub struct SecureConfigurationRegister(u64);
217    {
218        let __ @ 63..39;
219        let hxen @ 38;
220        let aden @ 37;
221        let enas0 @ 36;
222        let amvoffen @ 35;
223        let __ @ 34;
224        let twedel @ 33..30;
225        let tweden @ 29;
226        let ecven @ 28;
227        let fgten @ 27;
228        let ata @ 26;
229        let enscxt @ 25;
230        let __ @ 24..22;
231        let fien @ 21;
232        let nmea @ 20;
233        let ease @ 19;
234        let eel2 @ 18;
235        let api @ 17;
236        let apk @ 16;
237        let terr @ 15;
238        let tlor @ 14;
239        let twe @ 13;
240        let twi @ 12;
241        let st @ 11;
242        let rw @ 10;
243        let sif @ 9;
244        let hce @ 8;
245        let smd @ 7;
246        let __ @ 6;
247        let __ @ 5..4 = 0b11;
248        let ea @ 3;
249        let fiq @ 2;
250        let irq @ 1;
251        let ns @ 0;
252    }
253});
254
255/// The cache shareability attribute for memory regions, as defined by the
256/// TCR_ELx.SHn fields.
257///
258/// [arm/v8]: D13.2.120 TCR_EL1, Translation Control Register (EL1)
259/// [arm/v8]: D13.2.121 TCR_EL2, Translation Control Register (EL2)
260#[bitfield_repr(u8)]
261#[derive(Clone, Copy)]
262pub enum ShareabilityAttribute {
263    None = 0b00,
264    // 0b01 is reserved.
265    Outer = 0b10,
266    Inner = 0b11,
267}
268
269/// The cacheability attribute of a normal memory regions, as defined by the
270/// TCR_ELx.IRGNn and TCR_ELx.ORGNn fields.
271///
272/// [arm/v8]: D13.2.120 TCR_EL1, Translation Control Register (EL1)
273/// [arm/v8]: D13.2.121 TCR_EL2, Translation Control Register (EL2)
274#[bitfield_repr(u8)]
275#[derive(Clone, Copy)]
276pub enum CacheabilityAttribute {
277    NonCacheable = 0b00,
278    WriteBackReadWriteAllocate = 0b01,
279    WriteThroughReadAllocate = 0b10,
280    WriteBackReadAllocate = 0b11,
281}
282
283/// Granule size values for the TCR_EL1 and TCR_EL2 fields.
284///
285/// WARNING: The encodings for the TG0 field and TG1 field are different.
286///
287/// [arm/v8]: D13.2.120 TCR_EL1, Translation Control Register (EL1)
288#[bitfield_repr(u8)]
289#[derive(Clone, Copy)]
290pub enum TcrTg0Value {
291    Tg4KiB = 0b00,
292    Tg16KiB = 0b10,
293    Tg64KiB = 0b01,
294}
295
296/// Granule size values for the TCR_EL1.TG1 field.
297///
298/// WARNING: The encodings for the TG0 field and TG1 field are different.
299///
300/// [arm/v8]: D13.2.120 TCR_EL1, Translation Control Register (EL1)
301#[bitfield_repr(u8)]
302#[derive(Clone, Copy)]
303pub enum TcrTg1Value {
304    Tg16KiB = 0b01,
305    Tg4KiB = 0b10,
306    Tg64KiB = 0b11,
307}
308
309/// [arm/v8]: D13.2.120 TCR_EL1, Translation Control Register (EL1)
310pub const TCR_EL1: SysReg<spec::TCR_EL1, TranslationControlRegisterEl1> = SysReg::new();
311
312/// [arm/v8]: D13.2.121 TCR_EL2, Translation Control Register (EL2)
313pub const TCR_EL2: SysReg<spec::TCR_EL2, TranslationControlRegisterEl2> = SysReg::new();
314
315multilayout!({
316    /// The layout of [`TCR_EL1`].
317    #[bitrs(el1)]
318    pub struct TranslationControlRegisterEl1(u64);
319
320    /// The layout of [`TCR_EL2`].
321    #[bitrs(el2)]
322    pub struct TranslationControlRegisterEl2(u64);
323
324    // EL1, EL2.
325    {
326        let __ @ 63..62;
327        let tg0 @ 15..14: TcrTg0Value;
328        let sh0 @ 13..12: ShareabilityAttribute;
329        let orgn0 @ 11..10: CacheabilityAttribute;
330        let irgn0 @ 9..8: CacheabilityAttribute;
331        let t0sz @ 5..0;
332    }
333
334    #[el1]
335    {
336        let mtx1 @ 61;
337        let mtx0 @ 60;
338        let ds @ 59;
339        let tcma1 @ 58;
340        let tcma0 @ 57;
341        let e0pd1 @ 56;
342        let e0pd0 @ 55;
343        let nfd1 @ 54;
344        let nfd0 @ 53;
345        let tbid1 @ 52;
346        let tbid0 @ 51;
347        let hwu162 @ 50;
348        let hwu161 @ 49;
349        let hwu160 @ 48;
350        let hwu159 @ 47;
351        let hwu062 @ 46;
352        let hwu061 @ 45;
353        let hwu060 @ 44;
354        let hwu059 @ 43;
355        let hpd1 @ 42;
356        let hpd0 @ 41;
357        let hd @ 40;
358        let ha @ 39;
359        let tbi1 @ 38;
360        let tbi0 @ 37;
361        let asid_size @ 36; // `as` is reserved
362        let __ @ 35;
363        let ips @ 34..32: PhysicalAddressSize;
364        let tg1 @ 31..30: TcrTg1Value;
365        let sh1 @ 29..28: ShareabilityAttribute;
366        let orgn1 @ 27..26: CacheabilityAttribute;
367        let irgn1 @ 25..24: CacheabilityAttribute;
368        let epd1 @ 23;
369        let a1 @ 22;
370        let t1sz @ 21..16;
371        let epd0 @ 7;
372        let __ @ 6;
373    }
374
375    #[el2]
376    {
377        let mtx @ 33;
378        let ds @ 32;
379        let __ @ 31 = 1;
380        let tcma @ 30;
381        let tbid @ 29;
382        let hwu62 @ 28;
383        let hwu61 @ 27;
384        let hwu60 @ 26;
385        let hwu59 @ 25;
386        let hpd @ 24;
387        let __ @ 23 = 1;
388        let hd @ 22;
389        let ha @ 21;
390        let tbi @ 20;
391        let ps @ 18..16: PhysicalAddressSize;
392        let __ @ 7..6;
393    }
394});
395
396/// [arm/v8]: VTCR_EL2, Virtualization Translation Control Register
397pub const VTCR_EL2: SysReg<spec::VTCR_EL2, VirtualizationTranslationControlRegister> =
398    SysReg::new();
399
400layout!({
401    /// The layout of [`VTCR_EL2`].
402    pub struct VirtualizationTranslationControlRegister(u64);
403    {
404        let __ @ 63..46;
405        let hdbss @ 45;
406        let haft @ 44;
407        let __ @ 43..42;
408        let tl0 @ 41;
409        let gcsh @ 40;
410        let __ @ 39;
411        let d128 @ 38;
412        let s2poe @ 37;
413        let s2pie @ 36;
414        let tl1 @ 35;
415        let assured_only @ 34;
416        let sl2 @ 33;
417        let ds @ 32;
418        let __ @ 31 = 1;
419        let nsa @ 30;
420        let nsw @ 29;
421        let hwu62 @ 28;
422        let hwu61 @ 27;
423        let hwu60 @ 26;
424        let hwu59 @ 25;
425        let __ @ 24;
426        let __ @ 23 = 1;
427        let hd @ 22;
428        let ha @ 21;
429        let __ @ 20;
430        let vs @ 19;
431        let ps @ 18..16: PhysicalAddressSize;
432        let tg0 @ 15..14: TcrTg0Value;
433        let sh0 @ 13..12: ShareabilityAttribute;
434        let orgn0 @ 11..10: CacheabilityAttribute;
435        let irgn0 @ 9..8: CacheabilityAttribute;
436        let sl0 @ 7..6;
437        let t0sz @ 5..0;
438    }
439});
440
441/// [arm/v9]: D23.2.172 TCR2_EL1, Translation Control Register (EL1)
442pub const TCR2_EL1: SysReg<spec::TCR2_EL1, ExtendedTranslationControlRegister> = SysReg::new();
443
444layout!({
445    /// The layout of [`TCR2_EL1`].
446    pub struct ExtendedTranslationControlRegister(u64);
447    {
448        let __ @ 63..22;
449        let fngna1 @ 21; // Force non-global for unassured using TTBR1. (FEAT_THE)
450        let fngna0 @ 20; // Force non-global for unassured using TTBR0. (FEAT_THE)
451        let __ @ 19;
452        let fng1 @ 18; // Force non-global translations for TTBR1. (FEAT_ASID2)
453        let fng0 @ 17; // Force non-global translations for TTBR0. (FEAT_ASID2)
454        let a2 @ 16; // Enable use of two ASIDs. (FEAT_ASID2)
455        let disch1 @ 15; // Disable contiguous bit for start table for TTBR1. (FEAT_D128)
456        let disch0 @ 14; // Disable contiguous bit for start table for TTBR0. (FEAT_D128)
457        let __ @ 13..12;
458        let haft @ 11; // Hardware managed access flag for table descriptors. (FEAT_HAFT)
459        let pttwi @ 10; // Permit translation table walk incoherence. (FEAT_THE)
460        let __ @ 9..6;
461        let d128 @ 5; // Enable 128 bit translation tables. (FEAT_D128)
462        let aie @ 4; // Enable attribute indexing extension. (FEAT_AIE)
463        let poe @ 3; // Enable permission overlays for privileged accesses. (FEAT_S1POE)
464        let e0poe @ 2; // Enable permission overlays for unprivileged accesses. (FEAT_S1POE)
465        let pie @ 1; // Enable indirect permission scheme. (FEAT_S1PIE)
466        let pnch @ 0; // Enable protected attribute enable. (FEAT_THE)
467    }
468});
469
470/// [arm/v8]: D13.2.132 TTBR0_EL1, Translation Table Base Register 0 (EL1)
471pub const TTBR0_EL1: SysReg<spec::TTBR0_EL1, TranslationTableBaseRegister> = SysReg::new();
472
473/// [arm/v8]: D13.2.133 TTBR0_EL2, Translation Table Base Register 0 (EL2)
474pub const TTBR0_EL2: SysReg<spec::TTBR0_EL2, TranslationTableBaseRegister> = SysReg::new();
475
476/// [arm/v8]: D13.2.134 TTBR0_EL3, Translation Table Base Register 0 (EL3)
477pub const TTBR0_EL3: SysReg<spec::TTBR0_EL3, TranslationTableBaseRegister> = SysReg::new();
478
479/// [arm/v8]: D13.2.135 TTBR1_EL1, Translation Table Base Register 1 (EL1)
480pub const TTBR1_EL1: SysReg<spec::TTBR1_EL1, TranslationTableBaseRegister> = SysReg::new();
481
482/// [arm/v8]: D13.2.136 TTBR1_EL2, Translation Table Base Register 1 (EL2)
483pub const TTBR1_EL2: SysReg<spec::TTBR1_EL2, TranslationTableBaseRegister> = SysReg::new();
484
485/// [arm/v8]: VTTBR_EL2, Virtualization Translation Table Base Register (EL2)
486pub const VTTBR_EL2: SysReg<spec::VTTBR_EL2, TranslationTableBaseRegister> = SysReg::new();
487
488layout!({
489    /// The layout of [`TTBR0_EL1`], [`TTBR0_EL2`], [`TTBR0_EL3`],
490    /// [`TTBR1_EL1`], [`TTBR1_EL2`], [`TTBR1_EL3`], and [`VTTBR_EL2`].
491    pub struct TranslationTableBaseRegister(u64);
492    {
493        let asid @ 63..48;
494        #[unshifted]
495        let addr @ 47..1; // Bits [47:1] of the root table physical address.
496        let cnp @ 0; // Common not private.
497    }
498});
499
500impl TranslationTableBaseRegister {
501    /// VMID field (same bit position as ASID when used for VTTBR_EL2).
502    ///
503    /// The layout is the same as TTBR0_ELx, but the ASID field is called VMID.
504    pub fn vmid(&self) -> u16 {
505        self.asid()
506    }
507
508    /// Sets VMID field.
509    pub fn set_vmid(&mut self, vmid: u16) -> &mut Self {
510        self.set_asid(vmid)
511    }
512}
513
514/// [arm/sysreg]/currentel: DAIF, Interrupt Mask Bits
515pub const DAIF: SysReg<spec::DAIF, Daif> = SysReg::new();
516
517layout!({
518    /// The layout of [`DAIF`].
519    pub struct Daif(u64);
520    {
521        let __ @ 63..10;
522        let d @ 9;
523        let a @ 8;
524        let i @ 7;
525        let f @ 6;
526        let __ @ 5..0;
527    }
528});
529
530/// [arm/sysreg]/vbar_el1: Vector Base Address Register (EL1)
531pub const VBAR_EL1: SysReg<spec::VBAR_EL1, VectorBaseAddressRegister> = SysReg::new();
532
533/// [arm/sysreg]/vbar_el2: Vector Base Address Register (EL2)
534pub const VBAR_EL2: SysReg<spec::VBAR_EL2, VectorBaseAddressRegister> = SysReg::new();
535
536/// [arm/sysreg]/vbar_el3: Vector Base Address Register (EL3)
537pub const VBAR_EL3: SysReg<spec::VBAR_EL3, VectorBaseAddressRegister> = SysReg::new();
538
539layout!({
540    /// The layout of [`VBAR_EL1`], [`VBAR_EL2`], and [`VBAR_EL3`].
541    pub struct VectorBaseAddressRegister(u64);
542    {
543        #[unshifted]
544        let addr @ 63..11;
545        let __ @ 10..0;
546    }
547});
548
549/// [arm/sysreg]/elr_el1: Exception Link Register (EL1)
550pub const ELR_EL1: SysReg<spec::ELR_EL1, ExceptionLinkRegister> = SysReg::new();
551
552/// [arm/sysreg]/elr_el2: Exception Link Register (EL2)
553pub const ELR_EL2: SysReg<spec::ELR_EL2, ExceptionLinkRegister> = SysReg::new();
554
555/// [arm/sysreg]/elr_el3: Exception Link Register (EL3)
556pub const ELR_EL3: SysReg<spec::ELR_EL3, ExceptionLinkRegister> = SysReg::new();
557
558layout!({
559    /// The layout of [`ELR_EL1`], [`ELR_EL2`], and [`ELR_EL3`].
560    pub struct ExceptionLinkRegister(u64);
561    {
562        let pc @ 63..0;
563    }
564});
565
566/// [arm/sysreg]/sp_el0: Stack Pointer (EL0)
567pub const SP_EL0: SysReg<spec::SP_EL0, StackPointerRegister> = SysReg::new();
568
569/// [arm/sysreg]/sp_el1: Stack Pointer (EL1)
570pub const SP_EL1: SysReg<spec::SP_EL1, StackPointerRegister> = SysReg::new();
571
572/// [arm/sysreg]/sp_el2: Stack Pointer (EL2)
573pub const SP_EL2: SysReg<spec::SP_EL2, StackPointerRegister> = SysReg::new();
574
575layout!({
576    /// The layout of [`SP_EL1`], [`SP_EL2`], and [`SP_EL3`].
577    pub struct StackPointerRegister(u64);
578    {
579        let sp @ 63..0;
580    }
581});
582
583/// [arm/sysreg]/spsr_el1: Saved Program Status Register (El1)
584pub const SPSR_EL1: SysReg<spec::SPSR_EL1, SavedProgramStatusRegister> = SysReg::new();
585
586/// [arm/sysreg]/spsr_el2: Saved Program Status Register (El2)
587pub const SPSR_EL2: SysReg<spec::SPSR_EL2, SavedProgramStatusRegister> = SysReg::new();
588
589/// [arm/sysreg]/spsr_el3: Saved Program Status Register (El3)
590pub const SPSR_EL3: SysReg<spec::SPSR_EL3, SavedProgramStatusRegister> = SysReg::new();
591
592#[bitfield_repr(u8)]
593#[derive(Clone, Copy)]
594pub enum SpsrExceptionLevel {
595    El0t = 0b0000, // EL0 using SP_EL0
596    El1t = 0b0100, // EL1 using SP_EL0
597    El1h = 0b0101, // EL1 using SP_EL1
598    El2t = 0b1000, // EL2 using SP_EL0
599    El2h = 0b1001, // EL2 using SP_EL2
600    El3t = 0b1100, // EL3 using SP_EL0
601    El3h = 0b1101, // EL3 using SP_EL3
602}
603
604layout!({
605    /// The layout of [`SPSR_EL1`], [`SPSR_EL2`], and [`SPSR_EL3`].
606    ///
607    /// These are the assignments when an exception is taken from AArch64 state.
608    pub struct SavedProgramStatusRegister(u64);
609    {
610        let __ @ 63..32;
611        let n @ 31;
612        let z @ 30;
613        let c @ 29;
614        let v @ 28;
615        let __ @ 27..26;
616        let tco @ 25;
617        let dit @ 24;
618        let uao @ 23;
619        let pan @ 22;
620        let ss @ 21;
621        let il @ 20;
622        let __ @ 19..13;
623        let ssbs @ 12;
624        let btype @ 11..10;
625        let d @ 9;
626        let a @ 8;
627        let i @ 7;
628        let f @ 6;
629        let __ @ 5;
630        let a32 @ 4; // Always zero in this format.
631        let m @ 3..0: SpsrExceptionLevel;
632    }
633});
634
635impl SavedProgramStatusRegister {
636    /// EL this exception was taken from.
637    pub fn el(self) -> CurrentEl {
638        CurrentEl::from((self.m() as u64) & CurrentEl::EL_MASK)
639    }
640
641    /// SPSel state at the exception (true if it used SP_ELx).
642    pub fn spsel(self) -> bool {
643        (self.m() as u8) & 1 != 0
644    }
645}
646
647/// [arm/sysreg]/nzcv: Condition Flags
648pub const NZCV: SysReg<spec::NZCV, Nzcv> = SysReg::new();
649
650layout!({
651    /// The layout of [`NZCV`].
652    ///
653    /// This is a subset of SPSR_ELx that is accessible R/W to everyone.
654    pub struct Nzcv(u64);
655    {
656        let __ @ 63..32;
657        let n @ 31;
658        let z @ 30;
659        let c @ 29;
660        let v @ 28;
661        let __ @ 27..0;
662    }
663});
664
665/// [arm/sysreg]/esr_el1: Exception Syndrome Register (El1)
666pub const ESR_EL1: SysReg<spec::ESR_EL1, ExceptionSyndromeRegister> = SysReg::new();
667
668/// [arm/sysreg]/esr_el2: Exception Syndrome Register (El2)
669pub const ESR_EL2: SysReg<spec::ESR_EL2, ExceptionSyndromeRegister> = SysReg::new();
670
671/// [arm/sysreg]/esr_el3: Exception Syndrome Register (El3)
672pub const ESR_EL3: SysReg<spec::ESR_EL3, ExceptionSyndromeRegister> = SysReg::new();
673
674/// Some values are only possible in ESR_EL2 and/or ESR_EL3.
675#[bitfield_repr(u8)]
676#[derive(Clone, Copy)]
677pub enum ExceptionClass {
678    Unknown = 0b000000,
679    Wf = 0b000001,         // WF
680    Mcr = 0b000011,        // MCR or MRC
681    Mcrr = 0b000100,       // MCRR or MRRC
682    McrCoproc = 0b000101,  // MCR or MRC (coproc=0b1110)
683    Ldc = 0b000110,        // LDC or STC
684    Fp = 0b000111,         // SVE or SIMD
685    Ld64b = 0b001010,      // LD64B, ST64B, ST64BV, or ST64BVO
686    McrrCoproc = 0b001100, // MRRC (coproc==0b1110)
687    Bti = 0b001101,        // Branch target exception
688    IllegalExecution = 0b001110,
689    Svc32 = 0b010001,
690    Hvc32 = 0b010010, // EL2, EL3
691    Smc32 = 0b010011, // EL2, EL3
692    TrappedSysreg128 = 0b010100,
693    Svc64 = 0b010101,
694    Hvc64 = 0b010110, // EL2, EL3
695    Smc64 = 0b010111, // EL2, EL3
696    Msr = 0b011000,   // MSR, MRS, or System Instruction
697    Sve = 0b011001,
698    Eret = 0b011010, // EL2, EL3
699    Tstart = 0b011011,
700    Pac = 0b011100,
701    Sme = 0b011101,
702    ImplementationDefined = 0b011111, // EL3
703    InstructionAbortLowerEl = 0b100000,
704    InstructionAbortSameEl = 0b100001,
705    PcAlignment = 0b100010,
706    DataAbortLowerEl = 0b100100,
707    DataAbortSameEl = 0b100101,
708    SpAlignment = 0b100110,
709    Mops = 0b100111,
710    Fpe32 = 0b101000,
711    Fpe64 = 0b101100,
712    Gcs = 0b101101,
713    Serror = 0b101111,
714    BreakpointLowerEl = 0b110000,
715    BreakpointSameEl = 0b110001,
716    StepLowerEl = 0b110010,
717    StepSameEl = 0b110011,
718    WatchpointLowerEl = 0b110100,
719    WatchpointSameEl = 0b110101,
720    Bkpt = 0b111000,        // AArch32 BKPT #<n>
721    VectorCatch = 0b111010, // EL2, EL3
722    Brk = 0b111100,         // AArch64 BRK #<n>
723    Profiling = 0b111101,
724}
725
726layout!({
727    /// The layout of [`ESR_EL1`], [`ESR_EL2`], and [`ESR_EL3`].
728    ///
729    /// These are the assignments when an exception is taken from AArch64 state.
730    pub struct ExceptionSyndromeRegister(u64);
731    {
732        let __ @ 63..56;
733        let iss2 @ 55..32;
734        let ec @ 31..26: ExceptionClass;
735        let il @ 25;
736        let iss @ 24..0;
737    }
738});
739
740/// [arm/sysreg]/cptr_el2: Architectural Feature Trap Register (EL2) when `HCR_EL2.E2H == 0`
741pub const CPTR_EL2_NO_VHE: SysReg<spec::CPTR_EL2, ArchitecturalFeatureTrapRegisterNoVhe> =
742    SysReg::new();
743
744/// [arm/sysreg]/cptr_el2: Architectural Feature Trap Register (EL2) when `HCR_EL2.E2H == 1` (FEAT_VHE)
745pub const CPTR_EL2_VHE: SysReg<spec::CPTR_EL2, ArchitecturalFeatureTrapRegisterVhe> = SysReg::new();
746
747/// [arm/sysreg]/cptr_el3: Architectural Feature Trap Register (EL3) when `HCR_EL2.E2H == 0`
748pub const CPTR_EL3_NO_VHE: SysReg<spec::CPTR_EL3, ArchitecturalFeatureTrapRegisterNoVhe> =
749    SysReg::new();
750
751/// [arm/sysreg]/cptr_el3: Architectural Feature Trap Register (EL3) when `HCR_EL2.E2H == 1` (FEAT_VHE)
752pub const CPTR_EL3_VHE: SysReg<spec::CPTR_EL3, ArchitecturalFeatureTrapRegisterVhe> = SysReg::new();
753
754multilayout!({
755    /// The layout of [`CPTR_EL2`] and [`CPTR_EL3`] when `HCR_EL2.E2H == 0`.
756    #[bitrs(no_e2h)]
757    pub struct ArchitecturalFeatureTrapRegisterNoVhe(u64);
758
759    /// The layout of [`CPTR_EL2`] and [`CPTR_EL3`] when `HCR_EL2.E2H == 1` (FEAT_VHE).
760    #[bitrs(e2h)]
761    pub struct ArchitecturalFeatureTrapRegisterVhe(u64);
762
763    {
764        let __ @ 63..32;
765        let tcpac @ 31;
766        let tam @ 30;
767        let __ @ 29;
768        let __ @ 27..26;
769        let __ @ 23..22;
770        let __ @ 19..18;
771    }
772
773    #[e2h]
774    {
775        let tta @ 28;
776        let smen @ 25..24;
777        let fpen @ 21..20;
778        let zen @ 17..16;
779        let __ @ 15..0;
780    }
781
782    #[no_e2h]
783    {
784        let __ @ 28;
785        let __ @ 25..24;
786        let __ @ 21;
787        let tta @ 20;
788        let __ @ 17..14;
789        let __ @ 13 = 1;
790        let tsm @ 12;
791        let __ @ 11;
792        let tfp @ 10;
793        let __ @ 9 = 1;
794        let tz @ 8;
795        let __ @ 7..0;
796    }
797});
798
799/// [arm/sysreg]/hcr_el2: Hypervisor Configuration register (EL2)
800pub const HCR_EL2: SysReg<spec::HCR_EL2, HypervisorConfigurationRegister> = SysReg::new();
801
802layout!({
803    /// The layout of [`HCR_EL2`].
804    pub struct HypervisorConfigurationRegister(u64);
805    {
806        let twedel @ 63..60;
807        let tweden @ 59;
808        let tid5 @ 58;
809        let dct @ 57;
810        let ata @ 56;
811        let ttlbos @ 55;
812        let ttlbis @ 54;
813        let enscxt @ 53;
814        let tocu @ 52;
815        let amvoffen @ 51;
816        let ticab @ 50;
817        let tid4 @ 49;
818        let gpf @ 48;
819        let fien @ 47;
820        let fwb @ 46;
821        let nv2 @ 45;
822        let at @ 44;
823        let nv1 @ 43;
824        let nv @ 42;
825        let api @ 41;
826        let apk @ 40;
827        let tme @ 39;
828        let miocnce @ 38;
829        let tea @ 37;
830        let terr @ 36;
831        let tlor @ 35;
832        let e2h @ 34;
833        let id @ 33;
834        let cd @ 32;
835        let rw @ 31;
836        let trvm @ 30;
837        let hcd @ 29;
838        let tdz @ 28;
839        let tge @ 27;
840        let tvm @ 26;
841        let ttlb @ 25;
842        let tpu @ 24;
843        let tcpc @ 23;
844        let tsw @ 22;
845        let tacr @ 21;
846        let tidcp @ 20;
847        let tsc @ 19;
848        let tid3 @ 18;
849        let tid2 @ 17;
850        let tid1 @ 16;
851        let tid0 @ 15;
852        let twe @ 14;
853        let twi @ 13;
854        let dc @ 12;
855        let bsu @ 11..10;
856        let fb @ 9;
857        let vse @ 8;
858        let vi @ 7;
859        let vf @ 6;
860        let amo @ 5;
861        let imo @ 4;
862        let fmo @ 3;
863        let ptw @ 2;
864        let swio @ 1;
865        let vm @ 0;
866    }
867});
868
869/// [arm/sysreg]/hcrx_el2: Extended Hypervisor Configuration register (EL2)
870pub const HCRX_EL2: SysReg<spec::HCRX_EL2, ExtendedHypervisorConfigurationRegister> = SysReg::new();
871
872layout!({
873    /// The layout of [`HCRX_EL2`].
874    pub struct ExtendedHypervisorConfigurationRegister(u64);
875    {
876        let __ @ 63..27; // Safe "pass-through" value for no-op EL2.
877        let srmasken @ 26; // if FEAT_SRMASK
878        let __ @ 25;
879        let pacmen @ 24; // if FEAT_PAuth_LR
880        let enfpm @ 23; // if FEAT_FPMR
881        let gcsen @ 22; // if FEAT_GCS
882        let enidcp128 @ 21; // if FEAT_SYSREG128
883        let ensderr @ 20; // if FEAT_ADERR
884        let tmea @ 19; // if FEAT_DoubleFault2
885        let ensnerr @ 18; // if FEAT_ANERR
886        let d128en @ 17; // if FEAT_D128
887        let pttwi @ 16; // if FEAT_THE
888        let sctlr2en @ 15; // if FEAT_SCTLR2
889        let tcr2en @ 14; // if FEAT_TCR2
890        let __ @ 13..12;
891        let mscen @ 11; // if FEAT_MOPS
892        let mce2 @ 10; // if FEAT_MOPS
893        let cmow @ 9; // if CEAT_CMOW
894        let vfnmi @ 8; // if FEAT_NMI
895        let vinmi @ 7; // if FEAT_NMI
896        let tallint @ 6; // if FEAT_NMI
897        let smpme @ 5; // if FEAT_SME
898        let fgtnxs @ 4; // if FEAT_XS
899        let fnxs @ 3; // if FEAT_XS
900        let enasr @ 2; // if FEAT_LS64_V
901        let enals @ 1; // if FEAT_LS64
902        let enas0 @ 0; // if FEAT_LS64_ACCDATA
903    }
904});
905
906/// [arm/sysreg]/cnthctl_el2: Counter-timer Hypervisor Control register (EL2) when `HCR_EL2.E2H == 0`
907pub const CNTHCTL_EL2_NO_VHE: SysReg<
908    spec::CNTHCTL_EL2,
909    CounterTimerHypervisorControlRegisterNoVhe,
910> = SysReg::new();
911
912/// [arm/sysreg]/cnthctl_el2: Counter-timer Hypervisor Control register (EL2) when `HCR_EL2.E2H == 1` (FEAT_VHE)
913pub const CNTHCTL_EL2_VHE: SysReg<spec::CNTHCTL_EL2, CounterTimerHypervisorControlRegisterVhe> =
914    SysReg::new();
915
916multilayout!({
917    /// The layout of [`CNTHCTL_EL2`] when `HCR_EL2.E2H == 0`.
918    #[bitrs(no_e2h)]
919    pub struct CounterTimerHypervisorControlRegisterNoVhe(u64);
920
921    /// The layout of [`CNTHCTL_EL2`] when `HCR_EL2.E2H == 1` (FEAT_VHE).
922    #[bitrs(e2h)]
923    pub struct CounterTimerHypervisorControlRegisterVhe(u64);
924
925    {
926        let __ @ 63..20;
927        let cntpmask @ 19;
928        let cntvmask @ 18;
929        let evntis @ 17;
930        let el1nvvct @ 16;
931        let el1nvpct @ 15;
932        let el1tvct @ 14;
933        let el1tvt @ 13;
934        let ecv @ 12;
935        let evnti @ 7..4;
936        let evntdir @ 3;
937        let evnten @ 2;
938    }
939
940    #[e2h]
941    {
942        let el1pten @ 11;
943        let el1pcten @ 10;
944        let el0pten @ 9;
945        let el0vten @ 8;
946        let el0vcten @ 1;
947        let el0pcten @ 0;
948    }
949
950    #[no_e2h]
951    {
952        let __ @ 11..8;
953        let el1pcen @ 1;
954        let el1pcten @ 0;
955    }
956});
957
958/// [arm/sysreg]/icc_sre_el1: Interrupt Controller System Register Enable Register (EL1)
959pub const ICC_SRE_EL1: SysReg<spec::ICC_SRE_EL1, InterruptControllerSystemRegisterEnableRegister> =
960    SysReg::new();
961
962/// [arm/sysreg]/icc_sre_el2: Interrupt Controller System Register Enable Register (EL2)
963pub const ICC_SRE_EL2: SysReg<spec::ICC_SRE_EL2, InterruptControllerSystemRegisterEnableRegister> =
964    SysReg::new();
965
966/// [arm/sysreg]/icc_sre_el3: Interrupt Controller System Register Enable Register (EL3)
967pub const ICC_SRE_EL3: SysReg<spec::ICC_SRE_EL3, InterruptControllerSystemRegisterEnableRegister> =
968    SysReg::new();
969
970layout!({
971    /// The layout of [`ICC_SRE_EL1`], [`ICC_SRE_EL2`], and [`ICC_SRE_EL3`].
972    pub struct InterruptControllerSystemRegisterEnableRegister(u64);
973    {
974        let __ @ 63..4;
975        let enable @ 3;
976        let dib @ 2;
977        let dfb @ 1;
978        let sre @ 0;
979    }
980});
981
982#[cfg(test)]
983mod tests {
984    use super::*;
985
986    #[test]
987    fn multiprocessor_affinity() {
988        let mpidr =
989            *MultiprocessorAffinityRegister::new().set_aff0(1).set_aff1(2).set_aff2(3).set_aff3(4);
990        assert_eq!(mpidr.affinity(), 0x04_0003_0201);
991    }
992}