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