1 /* 2 * QEMU Arm CPU -- feature test functions 3 * 4 * Copyright (c) 2023 Linaro Ltd 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #ifndef TARGET_ARM_FEATURES_H 21 #define TARGET_ARM_FEATURES_H 22 23 /* 24 * Naming convention for isar_feature functions: 25 * Functions which test 32-bit ID registers should have _aa32_ in 26 * their name. Functions which test 64-bit ID registers should have 27 * _aa64_ in their name. These must only be used in code where we 28 * know for certain that the CPU has AArch32 or AArch64 respectively 29 * or where the correct answer for a CPU which doesn't implement that 30 * CPU state is "false" (eg when generating A32 or A64 code, if adding 31 * system registers that are specific to that CPU state, for "should 32 * we let this system register bit be set" tests where the 32-bit 33 * flavour of the register doesn't have the bit, and so on). 34 * Functions which simply ask "does this feature exist at all" have 35 * _any_ in their name, and always return the logical OR of the _aa64_ 36 * and the _aa32_ function. 37 */ 38 39 /* 40 * 32-bit feature tests via id registers. 41 */ 42 static inline bool isar_feature_aa32_thumb_div(const ARMISARegisters *id) 43 { 44 return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) != 0; 45 } 46 47 static inline bool isar_feature_aa32_arm_div(const ARMISARegisters *id) 48 { 49 return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) > 1; 50 } 51 52 static inline bool isar_feature_aa32_lob(const ARMISARegisters *id) 53 { 54 /* (M-profile) low-overhead loops and branch future */ 55 return FIELD_EX32(id->id_isar0, ID_ISAR0, CMPBRANCH) >= 3; 56 } 57 58 static inline bool isar_feature_aa32_jazelle(const ARMISARegisters *id) 59 { 60 return FIELD_EX32(id->id_isar1, ID_ISAR1, JAZELLE) != 0; 61 } 62 63 static inline bool isar_feature_aa32_aes(const ARMISARegisters *id) 64 { 65 return FIELD_EX32(id->id_isar5, ID_ISAR5, AES) != 0; 66 } 67 68 static inline bool isar_feature_aa32_pmull(const ARMISARegisters *id) 69 { 70 return FIELD_EX32(id->id_isar5, ID_ISAR5, AES) > 1; 71 } 72 73 static inline bool isar_feature_aa32_sha1(const ARMISARegisters *id) 74 { 75 return FIELD_EX32(id->id_isar5, ID_ISAR5, SHA1) != 0; 76 } 77 78 static inline bool isar_feature_aa32_sha2(const ARMISARegisters *id) 79 { 80 return FIELD_EX32(id->id_isar5, ID_ISAR5, SHA2) != 0; 81 } 82 83 static inline bool isar_feature_aa32_crc32(const ARMISARegisters *id) 84 { 85 return FIELD_EX32(id->id_isar5, ID_ISAR5, CRC32) != 0; 86 } 87 88 static inline bool isar_feature_aa32_rdm(const ARMISARegisters *id) 89 { 90 return FIELD_EX32(id->id_isar5, ID_ISAR5, RDM) != 0; 91 } 92 93 static inline bool isar_feature_aa32_vcma(const ARMISARegisters *id) 94 { 95 return FIELD_EX32(id->id_isar5, ID_ISAR5, VCMA) != 0; 96 } 97 98 static inline bool isar_feature_aa32_jscvt(const ARMISARegisters *id) 99 { 100 return FIELD_EX32(id->id_isar6, ID_ISAR6, JSCVT) != 0; 101 } 102 103 static inline bool isar_feature_aa32_dp(const ARMISARegisters *id) 104 { 105 return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0; 106 } 107 108 static inline bool isar_feature_aa32_fhm(const ARMISARegisters *id) 109 { 110 return FIELD_EX32(id->id_isar6, ID_ISAR6, FHM) != 0; 111 } 112 113 static inline bool isar_feature_aa32_sb(const ARMISARegisters *id) 114 { 115 return FIELD_EX32(id->id_isar6, ID_ISAR6, SB) != 0; 116 } 117 118 static inline bool isar_feature_aa32_predinv(const ARMISARegisters *id) 119 { 120 return FIELD_EX32(id->id_isar6, ID_ISAR6, SPECRES) != 0; 121 } 122 123 static inline bool isar_feature_aa32_bf16(const ARMISARegisters *id) 124 { 125 return FIELD_EX32(id->id_isar6, ID_ISAR6, BF16) != 0; 126 } 127 128 static inline bool isar_feature_aa32_i8mm(const ARMISARegisters *id) 129 { 130 return FIELD_EX32(id->id_isar6, ID_ISAR6, I8MM) != 0; 131 } 132 133 static inline bool isar_feature_aa32_ras(const ARMISARegisters *id) 134 { 135 return FIELD_EX32(id->id_pfr0, ID_PFR0, RAS) != 0; 136 } 137 138 static inline bool isar_feature_aa32_mprofile(const ARMISARegisters *id) 139 { 140 return FIELD_EX32(id->id_pfr1, ID_PFR1, MPROGMOD) != 0; 141 } 142 143 static inline bool isar_feature_aa32_m_sec_state(const ARMISARegisters *id) 144 { 145 /* 146 * Return true if M-profile state handling insns 147 * (VSCCLRM, CLRM, FPCTX access insns) are implemented 148 */ 149 return FIELD_EX32(id->id_pfr1, ID_PFR1, SECURITY) >= 3; 150 } 151 152 static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id) 153 { 154 /* Sadly this is encoded differently for A-profile and M-profile */ 155 if (isar_feature_aa32_mprofile(id)) { 156 return FIELD_EX32(id->mvfr1, MVFR1, FP16) > 0; 157 } else { 158 return FIELD_EX32(id->mvfr1, MVFR1, FPHP) >= 3; 159 } 160 } 161 162 static inline bool isar_feature_aa32_mve(const ARMISARegisters *id) 163 { 164 /* 165 * Return true if MVE is supported (either integer or floating point). 166 * We must check for M-profile as the MVFR1 field means something 167 * else for A-profile. 168 */ 169 return isar_feature_aa32_mprofile(id) && 170 FIELD_EX32(id->mvfr1, MVFR1, MVE) > 0; 171 } 172 173 static inline bool isar_feature_aa32_mve_fp(const ARMISARegisters *id) 174 { 175 /* 176 * Return true if MVE is supported (either integer or floating point). 177 * We must check for M-profile as the MVFR1 field means something 178 * else for A-profile. 179 */ 180 return isar_feature_aa32_mprofile(id) && 181 FIELD_EX32(id->mvfr1, MVFR1, MVE) >= 2; 182 } 183 184 static inline bool isar_feature_aa32_vfp_simd(const ARMISARegisters *id) 185 { 186 /* 187 * Return true if either VFP or SIMD is implemented. 188 * In this case, a minimum of VFP w/ D0-D15. 189 */ 190 return FIELD_EX32(id->mvfr0, MVFR0, SIMDREG) > 0; 191 } 192 193 static inline bool isar_feature_aa32_simd_r32(const ARMISARegisters *id) 194 { 195 /* Return true if D16-D31 are implemented */ 196 return FIELD_EX32(id->mvfr0, MVFR0, SIMDREG) >= 2; 197 } 198 199 static inline bool isar_feature_aa32_fpshvec(const ARMISARegisters *id) 200 { 201 return FIELD_EX32(id->mvfr0, MVFR0, FPSHVEC) > 0; 202 } 203 204 static inline bool isar_feature_aa32_fpsp_v2(const ARMISARegisters *id) 205 { 206 /* Return true if CPU supports single precision floating point, VFPv2 */ 207 return FIELD_EX32(id->mvfr0, MVFR0, FPSP) > 0; 208 } 209 210 static inline bool isar_feature_aa32_fpsp_v3(const ARMISARegisters *id) 211 { 212 /* Return true if CPU supports single precision floating point, VFPv3 */ 213 return FIELD_EX32(id->mvfr0, MVFR0, FPSP) >= 2; 214 } 215 216 static inline bool isar_feature_aa32_fpdp_v2(const ARMISARegisters *id) 217 { 218 /* Return true if CPU supports double precision floating point, VFPv2 */ 219 return FIELD_EX32(id->mvfr0, MVFR0, FPDP) > 0; 220 } 221 222 static inline bool isar_feature_aa32_fpdp_v3(const ARMISARegisters *id) 223 { 224 /* Return true if CPU supports double precision floating point, VFPv3 */ 225 return FIELD_EX32(id->mvfr0, MVFR0, FPDP) >= 2; 226 } 227 228 static inline bool isar_feature_aa32_vfp(const ARMISARegisters *id) 229 { 230 return isar_feature_aa32_fpsp_v2(id) || isar_feature_aa32_fpdp_v2(id); 231 } 232 233 /* 234 * We always set the FP and SIMD FP16 fields to indicate identical 235 * levels of support (assuming SIMD is implemented at all), so 236 * we only need one set of accessors. 237 */ 238 static inline bool isar_feature_aa32_fp16_spconv(const ARMISARegisters *id) 239 { 240 return FIELD_EX32(id->mvfr1, MVFR1, FPHP) > 0; 241 } 242 243 static inline bool isar_feature_aa32_fp16_dpconv(const ARMISARegisters *id) 244 { 245 return FIELD_EX32(id->mvfr1, MVFR1, FPHP) > 1; 246 } 247 248 /* 249 * Note that this ID register field covers both VFP and Neon FMAC, 250 * so should usually be tested in combination with some other 251 * check that confirms the presence of whichever of VFP or Neon is 252 * relevant, to avoid accidentally enabling a Neon feature on 253 * a VFP-no-Neon core or vice-versa. 254 */ 255 static inline bool isar_feature_aa32_simdfmac(const ARMISARegisters *id) 256 { 257 return FIELD_EX32(id->mvfr1, MVFR1, SIMDFMAC) != 0; 258 } 259 260 static inline bool isar_feature_aa32_vsel(const ARMISARegisters *id) 261 { 262 return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 1; 263 } 264 265 static inline bool isar_feature_aa32_vcvt_dr(const ARMISARegisters *id) 266 { 267 return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 2; 268 } 269 270 static inline bool isar_feature_aa32_vrint(const ARMISARegisters *id) 271 { 272 return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 3; 273 } 274 275 static inline bool isar_feature_aa32_vminmaxnm(const ARMISARegisters *id) 276 { 277 return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 4; 278 } 279 280 static inline bool isar_feature_aa32_pxn(const ARMISARegisters *id) 281 { 282 return FIELD_EX32(id->id_mmfr0, ID_MMFR0, VMSA) >= 4; 283 } 284 285 static inline bool isar_feature_aa32_pan(const ARMISARegisters *id) 286 { 287 return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) != 0; 288 } 289 290 static inline bool isar_feature_aa32_ats1e1(const ARMISARegisters *id) 291 { 292 return FIELD_EX32(id->id_mmfr3, ID_MMFR3, PAN) >= 2; 293 } 294 295 static inline bool isar_feature_aa32_pmuv3p1(const ARMISARegisters *id) 296 { 297 /* 0xf means "non-standard IMPDEF PMU" */ 298 return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 4 && 299 FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; 300 } 301 302 static inline bool isar_feature_aa32_pmuv3p4(const ARMISARegisters *id) 303 { 304 /* 0xf means "non-standard IMPDEF PMU" */ 305 return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 5 && 306 FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; 307 } 308 309 static inline bool isar_feature_aa32_pmuv3p5(const ARMISARegisters *id) 310 { 311 /* 0xf means "non-standard IMPDEF PMU" */ 312 return FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) >= 6 && 313 FIELD_EX32(id->id_dfr0, ID_DFR0, PERFMON) != 0xf; 314 } 315 316 static inline bool isar_feature_aa32_hpd(const ARMISARegisters *id) 317 { 318 return FIELD_EX32(id->id_mmfr4, ID_MMFR4, HPDS) != 0; 319 } 320 321 static inline bool isar_feature_aa32_ac2(const ARMISARegisters *id) 322 { 323 return FIELD_EX32(id->id_mmfr4, ID_MMFR4, AC2) != 0; 324 } 325 326 static inline bool isar_feature_aa32_ccidx(const ARMISARegisters *id) 327 { 328 return FIELD_EX32(id->id_mmfr4, ID_MMFR4, CCIDX) != 0; 329 } 330 331 static inline bool isar_feature_aa32_tts2uxn(const ARMISARegisters *id) 332 { 333 return FIELD_EX32(id->id_mmfr4, ID_MMFR4, XNX) != 0; 334 } 335 336 static inline bool isar_feature_aa32_half_evt(const ARMISARegisters *id) 337 { 338 return FIELD_EX32(id->id_mmfr4, ID_MMFR4, EVT) >= 1; 339 } 340 341 static inline bool isar_feature_aa32_evt(const ARMISARegisters *id) 342 { 343 return FIELD_EX32(id->id_mmfr4, ID_MMFR4, EVT) >= 2; 344 } 345 346 static inline bool isar_feature_aa32_dit(const ARMISARegisters *id) 347 { 348 return FIELD_EX32(id->id_pfr0, ID_PFR0, DIT) != 0; 349 } 350 351 static inline bool isar_feature_aa32_ssbs(const ARMISARegisters *id) 352 { 353 return FIELD_EX32(id->id_pfr2, ID_PFR2, SSBS) != 0; 354 } 355 356 static inline bool isar_feature_aa32_debugv7p1(const ARMISARegisters *id) 357 { 358 return FIELD_EX32(id->id_dfr0, ID_DFR0, COPDBG) >= 5; 359 } 360 361 static inline bool isar_feature_aa32_debugv8p2(const ARMISARegisters *id) 362 { 363 return FIELD_EX32(id->id_dfr0, ID_DFR0, COPDBG) >= 8; 364 } 365 366 static inline bool isar_feature_aa32_doublelock(const ARMISARegisters *id) 367 { 368 return FIELD_EX32(id->dbgdevid, DBGDEVID, DOUBLELOCK) > 0; 369 } 370 371 /* 372 * 64-bit feature tests via id registers. 373 */ 374 static inline bool isar_feature_aa64_aes(const ARMISARegisters *id) 375 { 376 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, AES) != 0; 377 } 378 379 static inline bool isar_feature_aa64_pmull(const ARMISARegisters *id) 380 { 381 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, AES) > 1; 382 } 383 384 static inline bool isar_feature_aa64_sha1(const ARMISARegisters *id) 385 { 386 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA1) != 0; 387 } 388 389 static inline bool isar_feature_aa64_sha256(const ARMISARegisters *id) 390 { 391 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA2) != 0; 392 } 393 394 static inline bool isar_feature_aa64_sha512(const ARMISARegisters *id) 395 { 396 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA2) > 1; 397 } 398 399 static inline bool isar_feature_aa64_crc32(const ARMISARegisters *id) 400 { 401 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, CRC32) != 0; 402 } 403 404 static inline bool isar_feature_aa64_atomics(const ARMISARegisters *id) 405 { 406 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, ATOMIC) != 0; 407 } 408 409 static inline bool isar_feature_aa64_rdm(const ARMISARegisters *id) 410 { 411 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, RDM) != 0; 412 } 413 414 static inline bool isar_feature_aa64_sha3(const ARMISARegisters *id) 415 { 416 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SHA3) != 0; 417 } 418 419 static inline bool isar_feature_aa64_sm3(const ARMISARegisters *id) 420 { 421 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SM3) != 0; 422 } 423 424 static inline bool isar_feature_aa64_sm4(const ARMISARegisters *id) 425 { 426 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, SM4) != 0; 427 } 428 429 static inline bool isar_feature_aa64_dp(const ARMISARegisters *id) 430 { 431 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, DP) != 0; 432 } 433 434 static inline bool isar_feature_aa64_fhm(const ARMISARegisters *id) 435 { 436 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, FHM) != 0; 437 } 438 439 static inline bool isar_feature_aa64_condm_4(const ARMISARegisters *id) 440 { 441 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) != 0; 442 } 443 444 static inline bool isar_feature_aa64_condm_5(const ARMISARegisters *id) 445 { 446 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) >= 2; 447 } 448 449 static inline bool isar_feature_aa64_rndr(const ARMISARegisters *id) 450 { 451 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, RNDR) != 0; 452 } 453 454 static inline bool isar_feature_aa64_tlbirange(const ARMISARegisters *id) 455 { 456 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TLB) == 2; 457 } 458 459 static inline bool isar_feature_aa64_tlbios(const ARMISARegisters *id) 460 { 461 return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TLB) != 0; 462 } 463 464 static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id) 465 { 466 return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0; 467 } 468 469 static inline bool isar_feature_aa64_fcma(const ARMISARegisters *id) 470 { 471 return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FCMA) != 0; 472 } 473 474 /* 475 * These are the values from APA/API/APA3. 476 * In general these must be compared '>=', per the normal Arm ARM 477 * treatment of fields in ID registers. 478 */ 479 typedef enum { 480 PauthFeat_None = 0, 481 PauthFeat_1 = 1, 482 PauthFeat_EPAC = 2, 483 PauthFeat_2 = 3, 484 PauthFeat_FPAC = 4, 485 PauthFeat_FPACCOMBINED = 5, 486 } ARMPauthFeature; 487 488 static inline ARMPauthFeature 489 isar_feature_pauth_feature(const ARMISARegisters *id) 490 { 491 /* 492 * Architecturally, only one of {APA,API,APA3} may be active (non-zero) 493 * and the other two must be zero. Thus we may avoid conditionals. 494 */ 495 return (FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, APA) | 496 FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, API) | 497 FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, APA3)); 498 } 499 500 static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id) 501 { 502 /* 503 * Return true if any form of pauth is enabled, as this 504 * predicate controls migration of the 128-bit keys. 505 */ 506 return isar_feature_pauth_feature(id) != PauthFeat_None; 507 } 508 509 static inline bool isar_feature_aa64_pauth_qarma5(const ARMISARegisters *id) 510 { 511 /* 512 * Return true if pauth is enabled with the architected QARMA5 algorithm. 513 * QEMU will always enable or disable both APA and GPA. 514 */ 515 return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, APA) != 0; 516 } 517 518 static inline bool isar_feature_aa64_pauth_qarma3(const ARMISARegisters *id) 519 { 520 /* 521 * Return true if pauth is enabled with the architected QARMA3 algorithm. 522 * QEMU will always enable or disable both APA3 and GPA3. 523 */ 524 return FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, APA3) != 0; 525 } 526 527 static inline bool isar_feature_aa64_sb(const ARMISARegisters *id) 528 { 529 return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SB) != 0; 530 } 531 532 static inline bool isar_feature_aa64_predinv(const ARMISARegisters *id) 533 { 534 return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SPECRES) != 0; 535 } 536 537 static inline bool isar_feature_aa64_frint(const ARMISARegisters *id) 538 { 539 return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FRINTTS) != 0; 540 } 541 542 static inline bool isar_feature_aa64_dcpop(const ARMISARegisters *id) 543 { 544 return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) != 0; 545 } 546 547 static inline bool isar_feature_aa64_dcpodp(const ARMISARegisters *id) 548 { 549 return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) >= 2; 550 } 551 552 static inline bool isar_feature_aa64_bf16(const ARMISARegisters *id) 553 { 554 return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, BF16) != 0; 555 } 556 557 static inline bool isar_feature_aa64_rcpc_8_3(const ARMISARegisters *id) 558 { 559 return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) != 0; 560 } 561 562 static inline bool isar_feature_aa64_rcpc_8_4(const ARMISARegisters *id) 563 { 564 return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) >= 2; 565 } 566 567 static inline bool isar_feature_aa64_i8mm(const ARMISARegisters *id) 568 { 569 return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, I8MM) != 0; 570 } 571 572 static inline bool isar_feature_aa64_hbc(const ARMISARegisters *id) 573 { 574 return FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, BC) != 0; 575 } 576 577 static inline bool isar_feature_aa64_mops(const ARMISARegisters *id) 578 { 579 return FIELD_EX64(id->id_aa64isar2, ID_AA64ISAR2, MOPS); 580 } 581 582 static inline bool isar_feature_aa64_fp_simd(const ARMISARegisters *id) 583 { 584 /* We always set the AdvSIMD and FP fields identically. */ 585 return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) != 0xf; 586 } 587 588 static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id) 589 { 590 /* We always set the AdvSIMD and FP fields identically wrt FP16. */ 591 return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1; 592 } 593 594 static inline bool isar_feature_aa64_aa32(const ARMISARegisters *id) 595 { 596 return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL0) >= 2; 597 } 598 599 static inline bool isar_feature_aa64_aa32_el1(const ARMISARegisters *id) 600 { 601 return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL1) >= 2; 602 } 603 604 static inline bool isar_feature_aa64_aa32_el2(const ARMISARegisters *id) 605 { 606 return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL2) >= 2; 607 } 608 609 static inline bool isar_feature_aa64_ras(const ARMISARegisters *id) 610 { 611 return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) != 0; 612 } 613 614 static inline bool isar_feature_aa64_doublefault(const ARMISARegisters *id) 615 { 616 return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) >= 2; 617 } 618 619 static inline bool isar_feature_aa64_sve(const ARMISARegisters *id) 620 { 621 return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0; 622 } 623 624 static inline bool isar_feature_aa64_sel2(const ARMISARegisters *id) 625 { 626 return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SEL2) != 0; 627 } 628 629 static inline bool isar_feature_aa64_rme(const ARMISARegisters *id) 630 { 631 return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RME) != 0; 632 } 633 634 static inline bool isar_feature_aa64_dit(const ARMISARegisters *id) 635 { 636 return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, DIT) != 0; 637 } 638 639 static inline bool isar_feature_aa64_scxtnum(const ARMISARegisters *id) 640 { 641 int key = FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, CSV2); 642 if (key >= 2) { 643 return true; /* FEAT_CSV2_2 */ 644 } 645 if (key == 1) { 646 key = FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, CSV2_FRAC); 647 return key >= 2; /* FEAT_CSV2_1p2 */ 648 } 649 return false; 650 } 651 652 static inline bool isar_feature_aa64_ssbs(const ARMISARegisters *id) 653 { 654 return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SSBS) != 0; 655 } 656 657 static inline bool isar_feature_aa64_bti(const ARMISARegisters *id) 658 { 659 return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0; 660 } 661 662 static inline bool isar_feature_aa64_mte_insn_reg(const ARMISARegisters *id) 663 { 664 return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) != 0; 665 } 666 667 static inline bool isar_feature_aa64_mte(const ARMISARegisters *id) 668 { 669 return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) >= 2; 670 } 671 672 static inline bool isar_feature_aa64_mte3(const ARMISARegisters *id) 673 { 674 return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, MTE) >= 3; 675 } 676 677 static inline bool isar_feature_aa64_sme(const ARMISARegisters *id) 678 { 679 return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SME) != 0; 680 } 681 682 static inline bool isar_feature_aa64_tgran4_lpa2(const ARMISARegisters *id) 683 { 684 return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4) >= 1; 685 } 686 687 static inline bool isar_feature_aa64_tgran4_2_lpa2(const ARMISARegisters *id) 688 { 689 unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4_2); 690 return t >= 3 || (t == 0 && isar_feature_aa64_tgran4_lpa2(id)); 691 } 692 693 static inline bool isar_feature_aa64_tgran16_lpa2(const ARMISARegisters *id) 694 { 695 return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16) >= 2; 696 } 697 698 static inline bool isar_feature_aa64_tgran16_2_lpa2(const ARMISARegisters *id) 699 { 700 unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16_2); 701 return t >= 3 || (t == 0 && isar_feature_aa64_tgran16_lpa2(id)); 702 } 703 704 static inline bool isar_feature_aa64_tgran4(const ARMISARegisters *id) 705 { 706 return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4) >= 0; 707 } 708 709 static inline bool isar_feature_aa64_tgran16(const ARMISARegisters *id) 710 { 711 return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16) >= 1; 712 } 713 714 static inline bool isar_feature_aa64_tgran64(const ARMISARegisters *id) 715 { 716 return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN64) >= 0; 717 } 718 719 static inline bool isar_feature_aa64_tgran4_2(const ARMISARegisters *id) 720 { 721 unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4_2); 722 return t >= 2 || (t == 0 && isar_feature_aa64_tgran4(id)); 723 } 724 725 static inline bool isar_feature_aa64_tgran16_2(const ARMISARegisters *id) 726 { 727 unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16_2); 728 return t >= 2 || (t == 0 && isar_feature_aa64_tgran16(id)); 729 } 730 731 static inline bool isar_feature_aa64_tgran64_2(const ARMISARegisters *id) 732 { 733 unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN64_2); 734 return t >= 2 || (t == 0 && isar_feature_aa64_tgran64(id)); 735 } 736 737 static inline bool isar_feature_aa64_fgt(const ARMISARegisters *id) 738 { 739 return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, FGT) != 0; 740 } 741 742 static inline bool isar_feature_aa64_vh(const ARMISARegisters *id) 743 { 744 return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, VH) != 0; 745 } 746 747 static inline bool isar_feature_aa64_lor(const ARMISARegisters *id) 748 { 749 return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, LO) != 0; 750 } 751 752 static inline bool isar_feature_aa64_pan(const ARMISARegisters *id) 753 { 754 return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) != 0; 755 } 756 757 static inline bool isar_feature_aa64_ats1e1(const ARMISARegisters *id) 758 { 759 return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 2; 760 } 761 762 static inline bool isar_feature_aa64_pan3(const ARMISARegisters *id) 763 { 764 return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, PAN) >= 3; 765 } 766 767 static inline bool isar_feature_aa64_hcx(const ARMISARegisters *id) 768 { 769 return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HCX) != 0; 770 } 771 772 static inline bool isar_feature_aa64_tidcp1(const ARMISARegisters *id) 773 { 774 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR1, TIDCP1) != 0; 775 } 776 777 static inline bool isar_feature_aa64_hafs(const ARMISARegisters *id) 778 { 779 return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) != 0; 780 } 781 782 static inline bool isar_feature_aa64_hdbs(const ARMISARegisters *id) 783 { 784 return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) >= 2; 785 } 786 787 static inline bool isar_feature_aa64_tts2uxn(const ARMISARegisters *id) 788 { 789 return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, XNX) != 0; 790 } 791 792 static inline bool isar_feature_aa64_uao(const ARMISARegisters *id) 793 { 794 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0; 795 } 796 797 static inline bool isar_feature_aa64_st(const ARMISARegisters *id) 798 { 799 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0; 800 } 801 802 static inline bool isar_feature_aa64_lse2(const ARMISARegisters *id) 803 { 804 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, AT) != 0; 805 } 806 807 static inline bool isar_feature_aa64_fwb(const ARMISARegisters *id) 808 { 809 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, FWB) != 0; 810 } 811 812 static inline bool isar_feature_aa64_ids(const ARMISARegisters *id) 813 { 814 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, IDS) != 0; 815 } 816 817 static inline bool isar_feature_aa64_half_evt(const ARMISARegisters *id) 818 { 819 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, EVT) >= 1; 820 } 821 822 static inline bool isar_feature_aa64_evt(const ARMISARegisters *id) 823 { 824 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, EVT) >= 2; 825 } 826 827 static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id) 828 { 829 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0; 830 } 831 832 static inline bool isar_feature_aa64_lva(const ARMISARegisters *id) 833 { 834 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, VARANGE) != 0; 835 } 836 837 static inline bool isar_feature_aa64_e0pd(const ARMISARegisters *id) 838 { 839 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, E0PD) != 0; 840 } 841 842 static inline bool isar_feature_aa64_nv(const ARMISARegisters *id) 843 { 844 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) != 0; 845 } 846 847 static inline bool isar_feature_aa64_nv2(const ARMISARegisters *id) 848 { 849 return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, NV) >= 2; 850 } 851 852 static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id) 853 { 854 return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 4 && 855 FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; 856 } 857 858 static inline bool isar_feature_aa64_pmuv3p4(const ARMISARegisters *id) 859 { 860 return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 && 861 FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; 862 } 863 864 static inline bool isar_feature_aa64_pmuv3p5(const ARMISARegisters *id) 865 { 866 return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 6 && 867 FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; 868 } 869 870 static inline bool isar_feature_aa64_debugv8p2(const ARMISARegisters *id) 871 { 872 return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, DEBUGVER) >= 8; 873 } 874 875 static inline bool isar_feature_aa64_doublelock(const ARMISARegisters *id) 876 { 877 return FIELD_SEX64(id->id_aa64dfr0, ID_AA64DFR0, DOUBLELOCK) >= 0; 878 } 879 880 static inline bool isar_feature_aa64_sve2(const ARMISARegisters *id) 881 { 882 return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SVEVER) != 0; 883 } 884 885 static inline bool isar_feature_aa64_sve2_aes(const ARMISARegisters *id) 886 { 887 return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, AES) != 0; 888 } 889 890 static inline bool isar_feature_aa64_sve2_pmull128(const ARMISARegisters *id) 891 { 892 return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, AES) >= 2; 893 } 894 895 static inline bool isar_feature_aa64_sve2_bitperm(const ARMISARegisters *id) 896 { 897 return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, BITPERM) != 0; 898 } 899 900 static inline bool isar_feature_aa64_sve_bf16(const ARMISARegisters *id) 901 { 902 return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, BFLOAT16) != 0; 903 } 904 905 static inline bool isar_feature_aa64_sve2_sha3(const ARMISARegisters *id) 906 { 907 return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SHA3) != 0; 908 } 909 910 static inline bool isar_feature_aa64_sve2_sm4(const ARMISARegisters *id) 911 { 912 return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SM4) != 0; 913 } 914 915 static inline bool isar_feature_aa64_sve_i8mm(const ARMISARegisters *id) 916 { 917 return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, I8MM) != 0; 918 } 919 920 static inline bool isar_feature_aa64_sve_f32mm(const ARMISARegisters *id) 921 { 922 return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, F32MM) != 0; 923 } 924 925 static inline bool isar_feature_aa64_sve_f64mm(const ARMISARegisters *id) 926 { 927 return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, F64MM) != 0; 928 } 929 930 static inline bool isar_feature_aa64_sme_f64f64(const ARMISARegisters *id) 931 { 932 return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, F64F64); 933 } 934 935 static inline bool isar_feature_aa64_sme_i16i64(const ARMISARegisters *id) 936 { 937 return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, I16I64) == 0xf; 938 } 939 940 static inline bool isar_feature_aa64_sme_fa64(const ARMISARegisters *id) 941 { 942 return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, FA64); 943 } 944 945 /* 946 * Feature tests for "does this exist in either 32-bit or 64-bit?" 947 */ 948 static inline bool isar_feature_any_fp16(const ARMISARegisters *id) 949 { 950 return isar_feature_aa64_fp16(id) || isar_feature_aa32_fp16_arith(id); 951 } 952 953 static inline bool isar_feature_any_predinv(const ARMISARegisters *id) 954 { 955 return isar_feature_aa64_predinv(id) || isar_feature_aa32_predinv(id); 956 } 957 958 static inline bool isar_feature_any_pmuv3p1(const ARMISARegisters *id) 959 { 960 return isar_feature_aa64_pmuv3p1(id) || isar_feature_aa32_pmuv3p1(id); 961 } 962 963 static inline bool isar_feature_any_pmuv3p4(const ARMISARegisters *id) 964 { 965 return isar_feature_aa64_pmuv3p4(id) || isar_feature_aa32_pmuv3p4(id); 966 } 967 968 static inline bool isar_feature_any_pmuv3p5(const ARMISARegisters *id) 969 { 970 return isar_feature_aa64_pmuv3p5(id) || isar_feature_aa32_pmuv3p5(id); 971 } 972 973 static inline bool isar_feature_any_ccidx(const ARMISARegisters *id) 974 { 975 return isar_feature_aa64_ccidx(id) || isar_feature_aa32_ccidx(id); 976 } 977 978 static inline bool isar_feature_any_tts2uxn(const ARMISARegisters *id) 979 { 980 return isar_feature_aa64_tts2uxn(id) || isar_feature_aa32_tts2uxn(id); 981 } 982 983 static inline bool isar_feature_any_debugv8p2(const ARMISARegisters *id) 984 { 985 return isar_feature_aa64_debugv8p2(id) || isar_feature_aa32_debugv8p2(id); 986 } 987 988 static inline bool isar_feature_any_ras(const ARMISARegisters *id) 989 { 990 return isar_feature_aa64_ras(id) || isar_feature_aa32_ras(id); 991 } 992 993 static inline bool isar_feature_any_half_evt(const ARMISARegisters *id) 994 { 995 return isar_feature_aa64_half_evt(id) || isar_feature_aa32_half_evt(id); 996 } 997 998 static inline bool isar_feature_any_evt(const ARMISARegisters *id) 999 { 1000 return isar_feature_aa64_evt(id) || isar_feature_aa32_evt(id); 1001 } 1002 1003 /* 1004 * Forward to the above feature tests given an ARMCPU pointer. 1005 */ 1006 #define cpu_isar_feature(name, cpu) \ 1007 ({ ARMCPU *cpu_ = (cpu); isar_feature_##name(&cpu_->isar); }) 1008 1009 #endif 1010