xref: /cloud-hypervisor/hypervisor/src/arch/aarch64/regs.rs (revision 38380198e1660348e54cc69a6355bcd1f92e8cae)
1 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
2 //
3 // Copyright © 2025, Microsoft Corporation
4 //
5 
6 use bitfield_struct::bitfield;
7 use open_enum::open_enum;
8 use zerocopy::{FromBytes, IntoBytes};
9 
10 /// ESR_EL2, exception syndrome register.
11 #[bitfield(u64)]
12 #[derive(IntoBytes, FromBytes)]
13 pub struct EsrEl2 {
14     #[bits(25)]
15     pub iss: u32,
16     pub il: bool,
17     #[bits(6)]
18     pub ec: u8,
19     #[bits(5)]
20     pub iss2: u8,
21     #[bits(27)]
22     _rsvd: u32,
23 }
24 
25 #[open_enum]
26 #[derive(Debug)]
27 #[repr(u8)]
28 pub enum FaultStatusCode {
29     ADDRESS_SIZE_FAULT_LEVEL0 = 0b000000,
30     ADDRESS_SIZE_FAULT_LEVEL1 = 0b000001,
31     ADDRESS_SIZE_FAULT_LEVEL2 = 0b000010,
32     ADDRESS_SIZE_FAULT_LEVEL3 = 0b000011,
33     TRANSLATION_FAULT_LEVEL0 = 0b000100,
34     TRANSLATION_FAULT_LEVEL1 = 0b000101,
35     TRANSLATION_FAULT_LEVEL2 = 0b000110,
36     TRANSLATION_FAULT_LEVEL3 = 0b000111,
37     ACCESS_FLAG_FAULT_LEVEL0 = 0b001000,
38     ACCESS_FLAG_FAULT_LEVEL1 = 0b001001,
39     ACCESS_FLAG_FAULT_LEVEL2 = 0b001010,
40     ACCESS_FLAG_FAULT_LEVEL3 = 0b001011,
41     PERMISSION_FAULT_LEVEL0 = 0b001100,
42     PERMISSION_FAULT_LEVEL1 = 0b001101,
43     PERMISSION_FAULT_LEVEL2 = 0b001110,
44     PERMISSION_FAULT_LEVEL3 = 0b001111,
45     SYNCHRONOUS_EXTERNAL_ABORT = 0b010000,
46     SYNC_TAG_CHECK_FAULT = 0b010001,
47     SEA_TTW_LEVEL_NEG1 = 0b010011,
48     SEA_TTW_LEVEL0 = 0b010100,
49     SEA_TTW_LEVEL1 = 0b010101,
50     SEA_TTW_LEVEL2 = 0b010110,
51     SEA_TTW_LEVEL3 = 0b010111,
52     ECC_PARITY = 0b011000,
53     ECC_PARITY_TTW_LEVEL_NEG1 = 0b011011,
54     ECC_PARITY_TTW_LEVEL0 = 0b011100,
55     ECC_PARITY_TTW_LEVEL1 = 0b011101,
56     ECC_PARITY_TTW_LEVEL2 = 0b011110,
57     ECC_PARITY_TTW_LEVEL3 = 0b011111,
58     /// Valid only for data fault.
59     ALIGNMENT_FAULT = 0b100001,
60     /// Valid only for instruction fault.
61     GRANULE_PROTECTION_FAULT_LEVEL_NEG = 0b100011,
62     /// Valid only for instruction fault.
63     GRANULE_PROTECTION_FAULT_LEVEL0 = 0b100100,
64     /// Valid only for instruction fault.
65     GRANULE_PROTECTION_FAULT_LEVEL1 = 0b100101,
66     /// Valid only for instruction fault.
67     GRANULE_PROTECTION_FAULT_LEVEL2 = 0b100110,
68     /// Valid only for instruction fault.
69     GRANULE_PROTECTION_FAULT_LEVEL3 = 0b100111,
70     ADDRESS_SIZE_FAULT_LEVEL_NEG1 = 0b101001,
71     TRANSLATION_FAULT_LEVEL_NEG1 = 0b101011,
72     TLB_CONFLICT_ABORT = 0b110000,
73     UNSUPPORTED_HW_UPDATE_FAULT = 0b110001,
74 }
75 
76 /// Support for embedding within IssDataAbort/IssInstructionAbort
77 impl FaultStatusCode {
78     const fn from_bits(bits: u32) -> Self {
79         FaultStatusCode((bits & 0x3f) as u8)
80     }
81 
82     const fn into_bits(self) -> u32 {
83         self.0 as u32
84     }
85 }
86 
87 #[bitfield(u32)]
88 pub struct IssDataAbort {
89     #[bits(6)]
90     pub dfsc: FaultStatusCode,
91     // Write operation (write not read)
92     pub wnr: bool,
93     pub s1ptw: bool,
94     pub cm: bool,
95     pub ea: bool,
96     /// FAR not valid
97     pub fnv: bool,
98     #[bits(2)]
99     pub set: u8,
100     pub vncr: bool,
101     /// Acquire/release
102     pub ar: bool,
103     /// (ISV==1) 64-bit, (ISV==0) FAR is approximate
104     pub sf: bool,
105     #[bits(5)]
106     /// Register index.
107     pub srt: u8,
108     /// Sign extended.
109     pub sse: bool,
110     #[bits(2)]
111     /// access width log2
112     pub sas: u8,
113     /// Valid ESREL2 iss field.
114     pub isv: bool,
115     #[bits(7)]
116     _unused: u8,
117 }
118 
119 #[open_enum]
120 #[repr(u8)]
121 pub enum ExceptionClass {
122     UNKNOWN = 0b000000,
123     WFI = 0b000001,
124     MCR_MRC_COPROC_15 = 0b000011,
125     MCRR_MRRC_COPROC_15 = 0b000100,
126     MCR_MRC_COPROC_14 = 0b000101,
127     LDC_STC = 0b000110,
128     FP_OR_SIMD = 0b000111,
129     VMRS = 0b001000,
130     POINTER_AUTH_HCR_OR_SCR = 0b001001,
131     LS64 = 0b001010,
132     MRRC_COPROC_14 = 0b001100,
133     BRANCH_TARGET = 0b001101,
134     ILLEGAL_STATE = 0b001110,
135     SVC32 = 0b010001,
136     HVC32 = 0b010010,
137     SMC32 = 0b010011,
138     SVC = 0b010101,
139     HVC = 0b010110,
140     SMC = 0b010111,
141     SYSTEM = 0b011000,
142     SVE = 0b011001,
143     ERET = 0b011010,
144     TSTART = 0b011011,
145     POINTER_AUTH = 0b011100,
146     SME = 0b011101,
147     INSTRUCTION_ABORT_LOWER = 0b100000,
148     INSTRUCTION_ABORT = 0b100001,
149     PC_ALIGNMENT = 0b100010,
150     DATA_ABORT_LOWER = 0b100100,
151     DATA_ABORT = 0b100101,
152     SP_ALIGNMENT_FAULT = 0b100110,
153     MEMORY_OP = 0b100111,
154     FP_EXCEPTION_32 = 0b101000,
155     FP_EXCEPTION_64 = 0b101100,
156     SERROR = 0b101111,
157     BREAKPOINT_LOWER = 0b110000,
158     BREAKPOINT = 0b110001,
159     STEP_LOWER = 0b110010,
160     STEP = 0b110011,
161     WATCHPOINT_LOWER = 0b110100,
162     WATCHPOINT = 0b110101,
163     BRK32 = 0b111000,
164     VECTOR_CATCH_32 = 0b111010,
165     BRK = 0b111100,
166 }
167 
168 #[allow(non_upper_case_globals)]
169 // PSR (Processor State Register) bits.
170 // Taken from arch/arm64/include/uapi/asm/ptrace.h.
171 const PSR_MODE_EL1h: u64 = 0x0000_0005;
172 const PSR_F_BIT: u64 = 0x0000_0040;
173 const PSR_I_BIT: u64 = 0x0000_0080;
174 const PSR_A_BIT: u64 = 0x0000_0100;
175 const PSR_D_BIT: u64 = 0x0000_0200;
176 // Taken from arch/arm64/kvm/inject_fault.c.
177 pub const PSTATE_FAULT_BITS_64: u64 = PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT;
178 
179 // AArch64 system register encoding:
180 // See https://developer.arm.com/documentation/ddi0487 (chapter D12)
181 //
182 //   31      22  21 20 19 18 16 15 12 11  8 7   5 4  0
183 //  +----------+---+-----+-----+-----+-----+-----+----+
184 //  |1101010100| L | op0 | op1 | CRn | CRm | op2 | Rt |
185 //  +----------+---+-----+-----+-----+-----+-----+----+
186 //
187 // Notes:
188 // - L and Rt are reserved as implementation defined fields, ignored.
189 
190 const SYSREG_HEAD: u32 = 0b1101010100u32 << 22;
191 const SYSREG_OP0_SHIFT: u32 = 19;
192 const SYSREG_OP0_MASK: u32 = 0b11u32 << 19;
193 const SYSREG_OP1_SHIFT: u32 = 16;
194 const SYSREG_OP1_MASK: u32 = 0b111u32 << 16;
195 const SYSREG_CRN_SHIFT: u32 = 12;
196 const SYSREG_CRN_MASK: u32 = 0b1111u32 << 12;
197 const SYSREG_CRM_SHIFT: u32 = 8;
198 const SYSREG_CRM_MASK: u32 = 0b1111u32 << 8;
199 const SYSREG_OP2_SHIFT: u32 = 5;
200 const SYSREG_OP2_MASK: u32 = 0b111u32 << 5;
201 
202 /// Define the ID of system registers
203 #[macro_export]
204 macro_rules! arm64_sys_reg {
205     ($name: tt, $op0: tt, $op1: tt, $crn: tt, $crm: tt, $op2: tt) => {
206         pub const $name: u32 = SYSREG_HEAD
207             | ((($op0 as u32) << SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK as u32)
208             | ((($op1 as u32) << SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK as u32)
209             | ((($crn as u32) << SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK as u32)
210             | ((($crm as u32) << SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK as u32)
211             | ((($op2 as u32) << SYSREG_OP2_SHIFT) & SYSREG_OP2_MASK as u32);
212     };
213 }
214 
215 arm64_sys_reg!(MPIDR_EL1, 3, 0, 0, 0, 5);
216 arm64_sys_reg!(ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0);
217 arm64_sys_reg!(TTBR1_EL1, 3, 0, 2, 0, 1);
218 arm64_sys_reg!(TCR_EL1, 3, 0, 2, 0, 2);
219 
220 pub const AARCH64_ARCH_TIMER_PHYS_SECURE_IRQ: u32 = 13;
221 pub const AARCH64_ARCH_TIMER_PHYS_NONSECURE_IRQ: u32 = 14;
222 pub const AARCH64_ARCH_TIMER_VIRT_IRQ: u32 = 11;
223 pub const AARCH64_ARCH_TIMER_HYP_IRQ: u32 = 10;
224 
225 // PMU PPI interrupt number
226 pub const AARCH64_PMU_IRQ: u32 = 7;
227 
228 pub const AARCH64_MIN_PPI_IRQ: u32 = 16;
229