pub/libvex_guest_ppc64.h \
pub/libvex_guest_arm.h \
pub/libvex_guest_arm64.h \
+ pub/libvex_guest_arm64_sysregs.h \
pub/libvex_guest_s390x.h \
pub/libvex_guest_mips32.h \
pub/libvex_guest_mips64.h \
#include "libvex_basictypes.h"
#include "libvex_emnote.h"
#include "libvex_guest_arm64.h"
+#include "libvex_guest_arm64_sysregs.h"
#include "libvex_ir.h"
#include "libvex.h"
return crc;
}
+
/* CALLED FROM GENERATED CODE */
/* DIRTY HELPER (non-referentially-transparent) */
/* Horrible hack. On non-arm64 platforms, return 0. */
ULong w = 0x5555555555555555ULL; /* overwritten */
__asm__ __volatile__("mrs %0, id_aa64pfr0_el1" : "=r"(w));
- // The control word uses the following nibbles (as seen on RPi)
- // unsupported unless indicated
- // 0 to 3 - EL0 to EL3 exception level handling
- // 4 - FP includes half-precision (partial support)
- // 5 - AdvSIMD also includes haf-precision
-
- /* If half-precision fp is present we fall back to normal
- half precision implementation because of missing support in the emulation.
- If no AdvSIMD and FP are implemented, we preserve the value */
- w = (w >> 16);
- w &= 0xff;
- switch(w) {
- case 0x01:
- w = 0x0;
- break;
- case 0xff:
- w = (0xFF<<16);
- break;
- default:
- w = 0x0;
- break;
+ MASK_SYSTEM_REGISTER_FIELDS(w,
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64PFR0_EL0_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64PFR0_EL1_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64PFR0_FP_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64PFR0_ADVSIMD_SHIFT));
+
+ if (SYSTEM_REGISTER_FIELD(w, ID_AA64PFR0_FP_SHIFT) != ID_AA64PFR0_FP_NOT_PRESENT) {
+ CLAMP_REGISTER_FIELD_INPLACE(w, ID_AA64PFR0_FP_SHIFT, ID_AA64PFR0_FP_NHP_SUPPORTED);
+ }
+
+ if (SYSTEM_REGISTER_FIELD(w, ID_AA64PFR0_ADVSIMD_SHIFT) != ID_AA64PFR0_ADVSIMD_NOT_PRESENT) {
+ CLAMP_REGISTER_FIELD_INPLACE(w, ID_AA64PFR0_ADVSIMD_SHIFT, ID_AA64PFR0_ADVSIMD_NHP_SUPPORTED);
}
return w;
ULong w = 0x5555555555555555ULL; /* overwritten */
__asm__ __volatile__("mrs %0, id_aa64mmfr1_el1" : "=r"(w));
- /* Clear VH and HAFDBS bits */
- w &= ~(0xF0F);
+ // FIXME PJF we were just filtering out ID_AA64MMFR1_HAFDB and ID_AA64MMFR1_VH
+ // do we really support all of these?
+ MASK_SYSTEM_REGISTER_FIELDS(w,
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_VMIDBITS_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_HPDS_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_LO_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_PAN_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_SPECSEI_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_XNX_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_TWED_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_ETS_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_HCX_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_AFP_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_NTLBPA_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_TIDCP1_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_CMOW_SHIFT));
+
return w;
# else
return 0ULL;
ULong w = 0x5555555555555555ULL; /* overwritten */
__asm__ __volatile__("mrs %0, id_aa64isar0_el1" : "=r"(w));
- // In the mask below, nibbles are (higher nibbles all unsupported)
- // 0 - RES0
- // 1 - AES
- // 2 - SHA1
- // 3 - SHA2
- // 4 - CRC32
- // 5 - Atomic bits
- // 6 - TME (unsupported)
- // 7 - RDM
- // 8 - SHA3 (unsupported)
- // 9 - SM3 (unsupported)
- // 10 - SM4 (unsupported)
- // 11 - DP
-
- // 10
- // 109876543210
- w &= 0xF000F0FFFFFF;
+ MASK_SYSTEM_REGISTER_FIELDS(w,
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_AES_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_SHA1_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_SHA2_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_CRC32_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_ATOMICS_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_RDM_SHIFT) |
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_DP_SHIFT));
return w;
# else
ULong w = 0x5555555555555555ULL; /* overwritten */
__asm__ __volatile__("mrs %0, id_aa64isar1_el1" : "=r"(w));
- // only nibble 0 DBP
- w &= 0xF;
+ MASK_SYSTEM_REGISTER_FIELDS(w,
+ MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR1_DPB_SHIFT));
return w;
# else
--- /dev/null
+/*---------------------------------------------------------------*/
+/*--- begin libvex_guest_arm64_sysregs.h ---*/
+/*---------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2026 Paul Floyd
+ pjfloyd@wanadoo.fr
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __LIBVEX_PUB_GUEST_ARM64_SYSREGS_H
+#define __LIBVEX_PUB_GUEST_ARM64_SYSREGS_H
+
+/*---------------------------------------------------------------*/
+/*--- arm64 system register field definitions ---*/
+/*---------------------------------------------------------------*/
+
+/* These definitions are used when reading system registers
+ * to mask unsupported fields. They are also used by Valgrind
+ * during startup when determining hardware capabilities. */
+
+/* ID_AA64ISAR0_EL1 Instruction set attribute register 0 fields */
+#define ID_AA64ISAR0_FHM_SHIFT 48
+#define ID_AA64ISAR0_DP_SHIFT 44
+#define ID_AA64ISAR0_SM4_SHIFT 40
+#define ID_AA64ISAR0_SM3_SHIFT 36
+#define ID_AA64ISAR0_SHA3_SHIFT 32
+#define ID_AA64ISAR0_RDM_SHIFT 28
+#define ID_AA64ISAR0_ATOMICS_SHIFT 20
+#define ID_AA64ISAR0_CRC32_SHIFT 16
+#define ID_AA64ISAR0_SHA2_SHIFT 12
+#define ID_AA64ISAR0_SHA1_SHIFT 8
+#define ID_AA64ISAR0_AES_SHIFT 4
+#define ID_AA64ISAR0_RES0_SHIFT 0
+/* Field values */
+#define ID_AA64ISAR0_FHM_SUPPORTED 0x1
+#define ID_AA64ISAR0_DP_SUPPORTED 0x1
+#define ID_AA64ISAR0_SM4_SUPPORTED 0x1
+#define ID_AA64ISAR0_SM3_SUPPORTED 0x1
+#define ID_AA64ISAR0_SHA3_SUPPORTED 0x1
+#define ID_AA64ISAR0_RDM_SUPPORTED 0x1
+#define ID_AA64ISAR0_ATOMICS_SUPPORTED 0x2
+
+/* ID_AA64ISAR1_EL1 Instruction set attribute register 1 fields */
+#define ID_AA64ISAR1_I8MM_SHIFT 52
+#define ID_AA64ISAR1_BF16_SHIFT 44
+#define ID_AA64ISAR1_DPB_SHIFT 0
+/* Field values */
+#define ID_AA64ISAR1_I8MM_SUPPORTED 0x1
+#define ID_AA64ISAR1_BF16_SUPPORTED 0x1
+#define ID_AA64ISAR1_DPBCVAP_SUPPORTED 0x1
+#define ID_AA64ISAR1_DPBCVADP_SUPPORTED 0x2
+
+/* ID_AA64PFR0_EL1 Processor feature register 0 fields */
+#define ID_AA64PFR0_CSV3_SHIFT 60
+#define ID_AA64PFR0_CSV2_SHIFT 56
+#define ID_AA64PFR0_RME_SHIFT 52
+#define ID_AA64PFR0_DIT_SHIFT 48
+#define ID_AA64PFR0_AMU_SHIFT 44
+#define ID_AA64PFR0_MPAM_SHIFT 40
+#define ID_AA64PFR0_SEL2_SHIFT 36
+#define ID_AA64PFR0_SVE_SHIFT 32
+#define ID_AA64PFR0_RAS_SHIFT 28
+#define ID_AA64PFR0_GIC_SHIFT 24
+#define ID_AA64PFR0_ADVSIMD_SHIFT 20
+#define ID_AA64PFR0_FP_SHIFT 16
+#define ID_AA64PFR0_EL3_SHIFT 12
+#define ID_AA64PFR0_EL2_SHIFT 8
+#define ID_AA64PFR0_EL1_SHIFT 4
+#define ID_AA64PFR0_EL0_SHIFT 0
+/* Field values */
+#define ID_AA64PFR0_FP_NHP_SUPPORTED 0x0 /* FP but no half precision */
+#define ID_AA64PFR0_FP_HP_SUPPORTED 0x1 /* FP and half precision */
+#define ID_AA64PFR0_FP_NOT_PRESENT 0xf /* no FP present */
+#define ID_AA64PFR0_ADVSIMD_NHP_SUPPORTED 0x0
+#define ID_AA64PFR0_ADVSIMD_HP_SUPPORTED 0x1
+#define ID_AA64PFR0_ADVSIMD_NOT_PRESENT 0xf
+
+/* ID_AA64MMFR1_EL1 memory model feature register */
+#define ID_AA64MMFR1_RES0_SHIFT 60
+#define ID_AA64MMFR1_CMOW_SHIFT 56
+#define ID_AA64MMFR1_TIDCP1_SHIFT 52
+#define ID_AA64MMFR1_NTLBPA_SHIFT 48
+#define ID_AA64MMFR1_AFP_SHIFT 44
+#define ID_AA64MMFR1_HCX_SHIFT 40
+#define ID_AA64MMFR1_ETS_SHIFT 36
+#define ID_AA64MMFR1_TWED_SHIFT 32
+#define ID_AA64MMFR1_XNX_SHIFT 28
+#define ID_AA64MMFR1_SPECSEI_SHIFT 24
+#define ID_AA64MMFR1_PAN_SHIFT 20
+#define ID_AA64MMFR1_LO_SHIFT 16
+#define ID_AA64MMFR1_HPDS_SHIFT 12
+#define ID_AA64MMFR1_VH_SHIFT 8
+#define ID_AA64MMFR1_VMIDBITS_SHIFT 4
+#define ID_AA64MMFR1_HAFDBS_SHIFT 0
+
+#define SYSTEM_REGISTER_FIELD(val, shift) ((((val) >> (shift)) & 0xfULL))
+
+/* Feature support is specified in nibbles. That gives 16 possible
+ * levels. Usually 0 means no support. After that each successive
+ * level is a superset of the previous one. That means that if we do
+ * not fully support a level then we need to clamp to the previous
+ * level. */
+#define CLAMP_REGISTER_FIELD_INPLACE(val, shift, limit) \
+ do { \
+ if (SYSTEM_REGISTER_FIELD(val, shift) > (ULong)(limit)) { \
+ val &= ~(0xfULL << (shift)); \
+ val |= ((ULong)(limit) << (shift)); \
+ } \
+ } while (0)
+
+#define MAKE_SYSTEM_REGISTER_MASK_FIELD(shift) (0xfULL << (shift))
+#define MASK_SYSTEM_REGISTER_FIELDS(val, mask) (val) &= (mask)
+
+#endif /* ifndef __LIBVEX_PUB_GUEST_ARM64_SYSREGS_H */
+
+
+/*---------------------------------------------------------------*/
+/*--- libvex_guest_arm64_sysregs.h ---*/
+/*---------------------------------------------------------------*/
#include "pub_core_libcsignal.h" // for ppc32 messing with SIGILL and SIGFPE
#include "pub_core_debuglog.h"
+#include "libvex_guest_arm64_sysregs.h"
+
#define INSTR_PTR(regs) ((regs).vex.VG_INSTR_PTR)
#define STACK_PTR(regs) ((regs).vex.VG_STACK_PTR)
if (is_base_v8)
return True;
- /* ID_AA64ISAR0_EL1 Instruction set attribute register 0 fields */
- #define ID_AA64ISAR0_FHM_SHIFT 48
- #define ID_AA64ISAR0_DP_SHIFT 44
- #define ID_AA64ISAR0_SM4_SHIFT 40
- #define ID_AA64ISAR0_SM3_SHIFT 36
- #define ID_AA64ISAR0_SHA3_SHIFT 32
- #define ID_AA64ISAR0_RDM_SHIFT 28
- #define ID_AA64ISAR0_ATOMICS_SHIFT 20
- /* Field values */
- #define ID_AA64ISAR0_FHM_SUPPORTED 0x1
- #define ID_AA64ISAR0_DP_SUPPORTED 0x1
- #define ID_AA64ISAR0_SM4_SUPPORTED 0x1
- #define ID_AA64ISAR0_SM3_SUPPORTED 0x1
- #define ID_AA64ISAR0_SHA3_SUPPORTED 0x1
- #define ID_AA64ISAR0_RDM_SUPPORTED 0x1
- #define ID_AA64ISAR0_ATOMICS_SUPPORTED 0x2
-
- /* ID_AA64ISAR1_EL1 Instruction set attribute register 1 fields */
- #define ID_AA64ISAR1_I8MM_SHIFT 52
- #define ID_AA64ISAR1_BF16_SHIFT 44
- #define ID_AA64ISAR1_DPB_SHIFT 0
- /* Field values */
- #define ID_AA64ISAR1_I8MM_SUPPORTED 0x1
- #define ID_AA64ISAR1_BF16_SUPPORTED 0x1
- #define ID_AA64ISAR1_DPBCVAP_SUPPORTED 0x1
- #define ID_AA64ISAR1_DPBCVADP_SUPPORTED 0x2
-
- /* ID_AA64PFR0_EL1 Processor feature register 0 fields */
- #define ID_AA64PFR0_VFP16_SHIFT 20
- #define ID_AA64PFR0_FP16_SHIFT 16
- /* Field values */
- #define ID_AA64PFR0_VFP16_SUPPORTED 0x1
- #define ID_AA64PFR0_FP16_SUPPORTED 0x1
-
- #define get_cpu_ftr(id) ({ \
- unsigned long val; \
+
+ #define get_cpu_ftr(id, val) ({ \
asm("mrs %0, "#id : "=r" (val)); \
VG_(debugLog)(1, "machine", "ARM64: %-20s: 0x%016lx\n", #id, val); \
})
- get_cpu_ftr(ID_AA64ISAR0_EL1);
- get_cpu_ftr(ID_AA64ISAR1_EL1);
- get_cpu_ftr(ID_AA64PFR0_EL1);
-
- #define get_ftr(id, ftr, fval, have_ftr) ({ \
- unsigned long rval; \
- asm("mrs %0, "#id : "=r" (rval)); \
- have_ftr = (fval & ((rval >> ftr) & 0xf)) >= fval ? True : False; \
- })
+
+ unsigned long isar0;
+ unsigned long isar1;
+ unsigned long pfr0;
+
+ get_cpu_ftr(ID_AA64ISAR0_EL1, isar0);
+ get_cpu_ftr(ID_AA64ISAR1_EL1, isar1);
+ get_cpu_ftr(ID_AA64PFR0_EL1, pfr0);
/* Read ID_AA64ISAR0_EL1 attributes */
/* FHM indicates support for FMLAL and FMLSL instructions.
* Optional for v8.2.
*/
- get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_FHM_SHIFT,
- ID_AA64ISAR0_FHM_SUPPORTED, have_fhm);
+ have_fhm = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_FHM_SHIFT) >= ID_AA64ISAR0_FHM_SUPPORTED;
/* DP indicates support for UDOT and SDOT instructions.
* Optional for v8.2.
*/
- get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_DP_SHIFT,
- ID_AA64ISAR0_DP_SUPPORTED, have_dp);
+ have_dp = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_DP_SHIFT) >= ID_AA64ISAR0_DP_SUPPORTED;
/* SM4 indicates support for SM4E and SM4EKEY instructions.
* Optional for v8.2.
*/
- get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM4_SHIFT,
- ID_AA64ISAR0_SM4_SUPPORTED, have_sm4);
+ have_sm4 = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_SM4_SHIFT) >= ID_AA64ISAR0_SM4_SUPPORTED;
/* SM3 indicates support for SM3SS1, SM3TT1A, SM3TT1B, SM3TT2A, * SM3TT2B,
* SM3PARTW1, and SM3PARTW2 instructions.
* Optional for v8.2.
*/
- get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM3_SHIFT,
- ID_AA64ISAR0_SM3_SUPPORTED, have_sm3);
+ have_sm3 = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_SM3_SHIFT) >= ID_AA64ISAR0_SM3_SUPPORTED;
/* SHA3 indicates support for EOR3, RAX1, XAR, and BCAX instructions.
* Optional for v8.2.
*/
- get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA3_SHIFT,
- ID_AA64ISAR0_SHA3_SUPPORTED, have_sha3);
+ have_sha3 = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_SHA3_SHIFT) >= ID_AA64ISAR0_SHA3_SUPPORTED;
/* RDM indicates support for SQRDMLAH and SQRDMLSH instructions.
* Mandatory from v8.1 onwards.
*/
- get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_RDM_SHIFT,
- ID_AA64ISAR0_RDM_SUPPORTED, have_rdm);
+ have_rdm = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_RDM_SHIFT) >= ID_AA64ISAR0_RDM_SUPPORTED;
/* v8.1 ATOMICS indicates support for LDADD, LDCLR, LDEOR, LDSET, LDSMAX,
* LDSMIN, LDUMAX, LDUMIN, CAS, CASP, and SWP instructions.
* Mandatory from v8.1 onwards.
*/
- get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT,
- ID_AA64ISAR0_ATOMICS_SUPPORTED, have_atomics);
+ have_atomics = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_ATOMICS_SHIFT) >= ID_AA64ISAR0_ATOMICS_SUPPORTED;
/* Read ID_AA64ISAR1_EL1 attributes */
* instructions.
* Optional for v8.2.
*/
- get_ftr(ID_AA64ISAR1_EL1, ID_AA64ISAR1_I8MM_SHIFT,
- ID_AA64ISAR1_I8MM_SUPPORTED, have_i8mm);
+ have_i8mm = SYSTEM_REGISTER_FIELD(isar1, ID_AA64ISAR1_I8MM_SHIFT) >= ID_AA64ISAR1_I8MM_SUPPORTED;
/* BF16 indicates support for BFDOT, BFMLAL, BFMLAL2, BFMMLA, BFCVT, and
* BFCVT2 instructions.
* Optional for v8.2.
*/
- get_ftr(ID_AA64ISAR1_EL1, ID_AA64ISAR1_BF16_SHIFT,
- ID_AA64ISAR1_BF16_SUPPORTED, have_bf16);
+ have_bf16 = SYSTEM_REGISTER_FIELD(isar1, ID_AA64ISAR1_BF16_SHIFT) >= ID_AA64ISAR1_BF16_SUPPORTED;
/* DPB indicates support for DC CVAP instruction.
* Mandatory for v8.2 onwards.
*/
- get_ftr(ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT,
- ID_AA64ISAR1_DPBCVAP_SUPPORTED, have_dpbcvap);
+ have_dpbcvap = SYSTEM_REGISTER_FIELD(isar1, ID_AA64ISAR1_DPB_SHIFT) >= ID_AA64ISAR1_DPBCVAP_SUPPORTED;
/* DPB indicates support for DC CVADP instruction.
* Optional for v8.2.
*/
- get_ftr(ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT,
- ID_AA64ISAR1_DPBCVADP_SUPPORTED, have_dpbcvadp);
+ have_dpbcvadp = SYSTEM_REGISTER_FIELD(isar1, ID_AA64ISAR1_DPB_SHIFT) >= ID_AA64ISAR1_DPBCVADP_SUPPORTED;
/* Read ID_AA64PFR0_EL1 attributes */
/* VFP16 indicates support for half-precision vector arithmetic.
- * Optional for v8.2. Must be the same value as FP16.
+ * Optional for v8.2. Must be the same value as FP16. fp and
+ * advsimd are different to the usual isa/fp in that 0 means
+ * that the base features are present and 0xf means that the
+ * features are absent. Normally 0 means that the feature is absent.
*/
- get_ftr(ID_AA64PFR0_EL1, ID_AA64PFR0_VFP16_SHIFT,
- ID_AA64PFR0_VFP16_SUPPORTED, have_vfp16);
+ unsigned long advsimd = SYSTEM_REGISTER_FIELD(pfr0, ID_AA64PFR0_ADVSIMD_SHIFT);
+ have_vfp16 = advsimd >= ID_AA64PFR0_ADVSIMD_HP_SUPPORTED && advsimd != ID_AA64PFR0_ADVSIMD_NOT_PRESENT;
/* FP16 indicates support for half-precision scalar arithmetic.
* Optional for v8.2. Must be the same value as VFP16.
*/
- get_ftr(ID_AA64PFR0_EL1, ID_AA64PFR0_FP16_SHIFT,
- ID_AA64PFR0_FP16_SUPPORTED, have_fp16);
+ unsigned long fp = SYSTEM_REGISTER_FIELD(pfr0, ID_AA64PFR0_FP_SHIFT);
+ vg_assert(fp == advsimd);
+ have_fp16 = fp >= ID_AA64PFR0_FP_HP_SUPPORTED && fp != ID_AA64PFR0_FP_NOT_PRESENT;
if (have_fhm) vai.hwcaps |= VEX_HWCAPS_ARM64_FHM;
if (have_dpbcvap) vai.hwcaps |= VEX_HWCAPS_ARM64_DPBCVAP;
if (have_vfp16) vai.hwcaps |= VEX_HWCAPS_ARM64_VFP16;
#undef get_cpu_ftr
- #undef get_ftr
return True;
}