|
| 1 | +/* |
| 2 | + * Copyright (c) 2025 BayLibre SAS |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <zephyr/ztest.h> |
| 8 | +#include <zephyr/arch/arm64/lib_helpers.h> |
| 9 | +#include <stdint.h> |
| 10 | + |
| 11 | +ZTEST_SUITE(arm64_isa_features, NULL, NULL, NULL, NULL, NULL); |
| 12 | + |
| 13 | +ZTEST(arm64_isa_features, test_arm64_feature_detection) |
| 14 | +{ |
| 15 | + uint64_t pfr0 = read_id_aa64pfr0_el1(); |
| 16 | + uint64_t current_el = read_currentel(); |
| 17 | + uint64_t mmfr0 = read_id_aa64mmfr0_el1(); |
| 18 | + |
| 19 | + TC_PRINT("=== ARM64 ISA Feature Detection ===\n"); |
| 20 | + TC_PRINT("ID_AA64PFR0_EL1: 0x%016llx\n", pfr0); |
| 21 | + TC_PRINT("ID_AA64MMFR0_EL1: 0x%016llx\n", mmfr0); |
| 22 | + |
| 23 | + /* Check for ARMv9-A specific features */ |
| 24 | + TC_PRINT("\n=== Feature Analysis ===\n"); |
| 25 | + |
| 26 | + /* SVE support (Scalable Vector Extension) */ |
| 27 | + bool sve = is_sve_implemented(); |
| 28 | + |
| 29 | + TC_PRINT("SVE support: %s\n", sve ? "YES" : "NO"); |
| 30 | + |
| 31 | + /* Current Exception Level */ |
| 32 | + TC_PRINT("Current EL: EL%llu\n", GET_EL(current_el)); |
| 33 | + |
| 34 | + /* Check EL support */ |
| 35 | + TC_PRINT("EL0 AArch64: %s\n", is_el_implemented(0) ? "YES" : "NO"); |
| 36 | + TC_PRINT("EL1 AArch64: %s\n", is_el_implemented(1) ? "YES" : "NO"); |
| 37 | + TC_PRINT("EL2 AArch64: %s\n", is_el_implemented(2) ? "YES" : "NO"); |
| 38 | + TC_PRINT("EL3 AArch64: %s\n", is_el_implemented(3) ? "YES" : "NO"); |
| 39 | + |
| 40 | + /* Advanced SIMD (NEON) */ |
| 41 | + uint64_t advsimd = (pfr0 >> ID_AA64PFR0_ADVSIMD_SHIFT) & ID_AA64PFR0_ADVSIMD_MASK; |
| 42 | + |
| 43 | + TC_PRINT("Advanced SIMD (NEON): %s (0x%llx)\n", |
| 44 | + (advsimd == 0) ? "YES" : (advsimd == 0xf) ? "NO" : "PARTIAL", advsimd); |
| 45 | + |
| 46 | + /* Floating Point */ |
| 47 | + uint64_t fp = (pfr0 >> ID_AA64PFR0_FP_SHIFT) & ID_AA64PFR0_FP_MASK; |
| 48 | + |
| 49 | + TC_PRINT("Floating Point: %s (0x%llx)\n", |
| 50 | + (fp == 0) ? "YES" : (fp == 0xf) ? "NO" : "PARTIAL", fp); |
| 51 | + |
| 52 | + /* Check for additional ARMv8.5-A+ and ARMv9-A indicators */ |
| 53 | + uint64_t pfr1 = read_id_aa64pfr1_el1(); |
| 54 | + uint64_t isar0 = read_id_aa64isar0_el1(); |
| 55 | + uint64_t isar1 = read_id_aa64isar1_el1(); |
| 56 | + uint64_t isar2 = read_id_aa64isar2_el1(); |
| 57 | + |
| 58 | + TC_PRINT("\nID_AA64PFR1_EL1: 0x%016llx\n", pfr1); |
| 59 | + TC_PRINT("ID_AA64ISAR0_EL1: 0x%016llx\n", isar0); |
| 60 | + TC_PRINT("ID_AA64ISAR1_EL1: 0x%016llx\n", isar1); |
| 61 | + TC_PRINT("ID_AA64ISAR2_EL1: 0x%016llx\n", isar2); |
| 62 | + |
| 63 | + /* Check for ARMv8.1 LSE atomics */ |
| 64 | + uint64_t lse = (isar0 >> 20) & 0xf; |
| 65 | + |
| 66 | + TC_PRINT("LSE Atomics: %s (0x%llx)\n", lse ? "YES" : "NO", lse); |
| 67 | + |
| 68 | + /* Check for Pointer Authentication */ |
| 69 | + uint64_t pauth_api = (isar1 >> 4) & 0xf; |
| 70 | + uint64_t pauth_apa = (isar1 >> 8) & 0xf; |
| 71 | + uint64_t pauth_gpi = (isar1 >> 28) & 0xf; |
| 72 | + uint64_t pauth_gpa = (isar1 >> 24) & 0xf; |
| 73 | + |
| 74 | + TC_PRINT("Pointer Auth (API - Address ImplDef): %s (0x%llx)\n", |
| 75 | + pauth_api ? "YES" : "NO", pauth_api); |
| 76 | + TC_PRINT("Pointer Auth (APA - Address Arch): %s (0x%llx)\n", |
| 77 | + pauth_apa ? "YES" : "NO", pauth_apa); |
| 78 | + TC_PRINT("Pointer Auth (GPI - Instr ImplDef): %s (0x%llx)\n", |
| 79 | + pauth_gpi ? "YES" : "NO", pauth_gpi); |
| 80 | + TC_PRINT("Pointer Auth (GPA - Instr Arch): %s (0x%llx)\n", |
| 81 | + pauth_gpa ? "YES" : "NO", pauth_gpa); |
| 82 | + |
| 83 | + /* Decode APA level */ |
| 84 | + if (pauth_apa == 0x5) { |
| 85 | + TC_PRINT(" APA Level 5: Enhanced PAC with FPACCOMBINE\n"); |
| 86 | + } else if (pauth_apa == 0x4) { |
| 87 | + TC_PRINT(" APA Level 4: Enhanced PAC with FPAC\n"); |
| 88 | + } else if (pauth_apa == 0x3) { |
| 89 | + TC_PRINT(" APA Level 3: Enhanced PAC2\n"); |
| 90 | + } else if (pauth_apa == 0x1) { |
| 91 | + TC_PRINT(" APA Level 1: Basic PAC\n"); |
| 92 | + } |
| 93 | + |
| 94 | + /* Check for Branch Target Identification (ARMv8.5-A) */ |
| 95 | + uint64_t bti = (pfr1 >> 0) & 0xf; |
| 96 | + |
| 97 | + TC_PRINT("Branch Target Identification (BTI): %s (0x%llx)\n", bti ? "YES" : "NO", bti); |
| 98 | + |
| 99 | + /* Check for Memory Tagging Extensions (ARMv8.5-A) */ |
| 100 | + uint64_t mte = (pfr1 >> 8) & 0xf; |
| 101 | + |
| 102 | + TC_PRINT("Memory Tagging Extension (MTE): %s (0x%llx)\n", mte ? "YES" : "NO", mte); |
| 103 | + if (mte == 0x2) { |
| 104 | + TC_PRINT(" MTE Level 2: Full MTE\n"); |
| 105 | + } else if (mte == 0x1) { |
| 106 | + TC_PRINT(" MTE Level 1: EL0-only\n"); |
| 107 | + } |
| 108 | + |
| 109 | + /* Check for Random Number Generation (ARMv8.5-A) */ |
| 110 | + uint64_t rndr = (pfr1 >> 16) & 0xf; |
| 111 | + |
| 112 | + TC_PRINT("Random Number Generation (RNDR): %s (0x%llx)\n", rndr ? "YES" : "NO", rndr); |
| 113 | + |
| 114 | + /* Check for Speculative Store Bypass Safe (ARMv8.5-A) */ |
| 115 | + uint64_t ssbs = (pfr1 >> 12) & 0xf; |
| 116 | + |
| 117 | + TC_PRINT("Speculative Store Bypass Safe (SSBS): %s (0x%llx)\n", ssbs ? "YES" : "NO", ssbs); |
| 118 | + |
| 119 | + /* Check for additional ISAR2 features */ |
| 120 | + /* WFxT - Wait For Event/Interrupt with Timeout (ARMv8.7-A) */ |
| 121 | + uint64_t wfxt = (isar2 >> 0) & 0xf; |
| 122 | + |
| 123 | + TC_PRINT("WFxT (Wait with Timeout): %s (0x%llx)\n", wfxt ? "YES" : "NO", wfxt); |
| 124 | + |
| 125 | + /* RPRES - Reciprocal Estimate and Reciprocal Square Root Estimate */ |
| 126 | + uint64_t rpres = (isar2 >> 4) & 0xf; |
| 127 | + |
| 128 | + TC_PRINT("RPRES (Reciprocal Precision): %s (0x%llx)\n", rpres ? "YES" : "NO", rpres); |
| 129 | + |
| 130 | + /* GPA3 - Generic Pointer Authentication using QARMA3 */ |
| 131 | + uint64_t gpa3 = (isar2 >> 8) & 0xf; |
| 132 | + |
| 133 | + TC_PRINT("Pointer Auth (GPA3 - QARMA3): %s (0x%llx)\n", gpa3 ? "YES" : "NO", gpa3); |
| 134 | + |
| 135 | + /* APA3 - Address Pointer Authentication using QARMA3 */ |
| 136 | + uint64_t apa3 = (isar2 >> 12) & 0xf; |
| 137 | + |
| 138 | + TC_PRINT("Pointer Auth (APA3 - QARMA3): %s (0x%llx)\n", apa3 ? "YES" : "NO", apa3); |
| 139 | + |
| 140 | + /* MOPS - Memory Copy and Memory Set instructions (ARMv8.8-A) */ |
| 141 | + uint64_t mops = (isar2 >> 16) & 0xf; |
| 142 | + |
| 143 | + TC_PRINT("MOPS (Memory Copy/Set): %s (0x%llx)\n", mops ? "YES" : "NO", mops); |
| 144 | + |
| 145 | + /* BC - BC (Branch Consistency) model */ |
| 146 | + uint64_t bc = (isar2 >> 20) & 0xf; |
| 147 | + |
| 148 | + TC_PRINT("BC (Branch Consistency): %s (0x%llx)\n", bc ? "YES" : "NO", bc); |
| 149 | + |
| 150 | + TC_PRINT("\n=== Architecture Assessment ===\n"); |
| 151 | + if (sve) { |
| 152 | + TC_PRINT("Architecture: ARMv9-A (SVE detected)\n"); |
| 153 | + if (bti || mte || rndr) { |
| 154 | + TC_PRINT("ARMv8.5-A+ features: "); |
| 155 | + if (bti) { |
| 156 | + TC_PRINT("BTI "); |
| 157 | + } |
| 158 | + if (mte) { |
| 159 | + TC_PRINT("MTE "); |
| 160 | + } |
| 161 | + if (rndr) { |
| 162 | + TC_PRINT("RNDR "); |
| 163 | + } |
| 164 | + if (ssbs) { |
| 165 | + TC_PRINT("SSBS "); |
| 166 | + } |
| 167 | + TC_PRINT("\n"); |
| 168 | + } |
| 169 | + if (wfxt || mops || gpa3 || apa3) { |
| 170 | + TC_PRINT("ARMv8.7-A+ features: "); |
| 171 | + if (wfxt) { |
| 172 | + TC_PRINT("WFxT "); |
| 173 | + } |
| 174 | + if (mops) { |
| 175 | + TC_PRINT("MOPS "); |
| 176 | + } |
| 177 | + if (gpa3) { |
| 178 | + TC_PRINT("GPA3 "); |
| 179 | + } |
| 180 | + if (apa3) { |
| 181 | + TC_PRINT("APA3 "); |
| 182 | + } |
| 183 | + TC_PRINT("\n"); |
| 184 | + } |
| 185 | + } else if (bti || mte || rndr || ssbs) { |
| 186 | + TC_PRINT("Architecture: ARMv8.5-A+ (BTI/MTE/RNDR detected)\n"); |
| 187 | + } else if (lse >= 2 && (pauth_api || pauth_apa)) { |
| 188 | + TC_PRINT("Architecture: ARMv8.1+ with enhanced features (LSE Level 2+ and PAC)\n"); |
| 189 | + } else if (lse || pauth_api || pauth_apa) { |
| 190 | + TC_PRINT("Architecture: ARMv8.1+ with ARMv9-A features (LSE/PAC)\n"); |
| 191 | + } else { |
| 192 | + TC_PRINT("Architecture: ARMv8-A (no ARMv8.1+ features detected)\n"); |
| 193 | + } |
| 194 | + |
| 195 | + /* Decode LSE level */ |
| 196 | + if (lse >= 2) { |
| 197 | + TC_PRINT("LSE Level 2: Atomics with enhanced ordering\n"); |
| 198 | + } else if (lse == 1) { |
| 199 | + TC_PRINT("LSE Level 1: Basic atomic instructions\n"); |
| 200 | + } |
| 201 | + |
| 202 | + /* Basic validation that we can read system registers */ |
| 203 | + zassert_not_equal(pfr0, 0, "ID_AA64PFR0_EL1 should not be zero"); |
| 204 | + zassert_not_equal(current_el, 0, "CurrentEL should not be zero"); |
| 205 | + |
| 206 | + /* We should be running in EL1 */ |
| 207 | + zassert_equal(GET_EL(current_el), 1, "Should be running in EL1"); |
| 208 | + |
| 209 | + /* ARMv9-A configuration validation */ |
| 210 | + if (IS_ENABLED(CONFIG_ARMV9_A)) { |
| 211 | + /* ARMv9-A mandates SVE support */ |
| 212 | + zassert_true(sve, "CONFIG_ARMV9_A enabled but no SVE detected"); |
| 213 | + |
| 214 | + /* ARMv9-A should have enhanced security features */ |
| 215 | + zassert_true(pauth_api || pauth_apa, |
| 216 | + "CONFIG_ARMV9_A enabled but no Pointer Authentication detected"); |
| 217 | + |
| 218 | + /* If PAC is present, validate it's enhanced (Level 3+) */ |
| 219 | + if (pauth_apa) { |
| 220 | + zassert_true(pauth_apa >= 3, |
| 221 | + "CONFIG_ARMV9_A enabled but PAC level too low (0x%llx) - " |
| 222 | + "expected enhanced PAC (Level 3+)", pauth_apa); |
| 223 | + } |
| 224 | + |
| 225 | + /* ARMv9-A platforms should support modern atomic operations */ |
| 226 | + zassert_true(lse >= 1, |
| 227 | + "CONFIG_ARMV9_A enabled but no LSE atomics detected"); |
| 228 | + } |
| 229 | +} |
0 commit comments