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