Decode the arm64 SVE ID register

The field values are only valid when the ID_AA64PFR0_EL1.SVE or
ID_AA64PFR1_EL1.SME vields are non-zero. When this is not the case
the register is reserved as zero so is safe to read, but the SVEver
field will be incorrect so only print the decoded register when
the SVE or SME fields indicate it is valid.

Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Andrew Turner 2022-06-28 11:44:49 +00:00
parent 66ba742d2e
commit cb91f112a3
2 changed files with 150 additions and 0 deletions

View File

@ -132,6 +132,7 @@ struct cpu_desc {
uint64_t id_aa64mmfr2;
uint64_t id_aa64pfr0;
uint64_t id_aa64pfr1;
uint64_t id_aa64zfr0;
uint64_t ctr;
#ifdef COMPAT_FREEBSD32
uint64_t id_isar5;
@ -140,6 +141,7 @@ struct cpu_desc {
#endif
uint64_t clidr;
uint32_t ccsidr[MAX_CACHES][2]; /* 2 possible types. */
bool have_sve;
};
static struct cpu_desc cpu_desc[MAXCPU];
@ -157,6 +159,7 @@ static u_int cpu_print_regs;
#define PRINT_ID_AA64_MMFR2 0x00004000
#define PRINT_ID_AA64_PFR0 0x00010000
#define PRINT_ID_AA64_PFR1 0x00020000
#define PRINT_ID_AA64_ZFR0 0x00100000
#ifdef COMPAT_FREEBSD32
#define PRINT_ID_ISAR5 0x01000000
#define PRINT_MVFR0 0x02000000
@ -1251,6 +1254,70 @@ static struct mrs_field id_aa64pfr1_fields[] = {
MRS_FIELD_END,
};
/* ID_AA64ZFR0_EL1 */
static struct mrs_field_value id_aa64zfr0_f64mm[] = {
MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, F64MM, NONE, IMPL),
MRS_FIELD_VALUE_END,
};
static struct mrs_field_value id_aa64zfr0_f32mm[] = {
MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, F32MM, NONE, IMPL),
MRS_FIELD_VALUE_END,
};
static struct mrs_field_value id_aa64zfr0_i8mm[] = {
MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, I8MM, NONE, IMPL),
MRS_FIELD_VALUE_END,
};
static struct mrs_field_value id_aa64zfr0_sm4[] = {
MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, SM4, NONE, IMPL),
MRS_FIELD_VALUE_END,
};
static struct mrs_field_value id_aa64zfr0_sha3[] = {
MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, SHA3, NONE, IMPL),
MRS_FIELD_VALUE_END,
};
static struct mrs_field_value id_aa64zfr0_bf16[] = {
MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, BF16, NONE, BASE),
MRS_FIELD_VALUE(ID_AA64ZFR0_BF16_EBF, "BF16+EBF"),
MRS_FIELD_VALUE_END,
};
static struct mrs_field_value id_aa64zfr0_bitperm[] = {
MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, BitPerm, NONE, IMPL),
MRS_FIELD_VALUE_END,
};
static struct mrs_field_value id_aa64zfr0_aes[] = {
MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, AES, NONE, BASE),
MRS_FIELD_VALUE(ID_AA64ZFR0_AES_PMULL, "AES+PMULL"),
MRS_FIELD_VALUE_END,
};
static struct mrs_field_value id_aa64zfr0_svever[] = {
MRS_FIELD_VALUE(ID_AA64ZFR0_SVEver_SVE1, "SVE1"),
MRS_FIELD_VALUE(ID_AA64ZFR0_SVEver_SVE2, "SVE2"),
MRS_FIELD_VALUE_END,
};
static struct mrs_field id_aa64zfr0_fields[] = {
MRS_FIELD(ID_AA64ZFR0, F64MM, false, MRS_EXACT, id_aa64zfr0_f64mm),
MRS_FIELD(ID_AA64ZFR0, F32MM, false, MRS_EXACT, id_aa64zfr0_f32mm),
MRS_FIELD(ID_AA64ZFR0, I8MM, false, MRS_EXACT, id_aa64zfr0_i8mm),
MRS_FIELD(ID_AA64ZFR0, SM4, false, MRS_EXACT, id_aa64zfr0_sm4),
MRS_FIELD(ID_AA64ZFR0, SHA3, false, MRS_EXACT, id_aa64zfr0_sha3),
MRS_FIELD(ID_AA64ZFR0, BF16, false, MRS_EXACT, id_aa64zfr0_bf16),
MRS_FIELD(ID_AA64ZFR0, BitPerm, false, MRS_EXACT, id_aa64zfr0_bitperm),
MRS_FIELD(ID_AA64ZFR0, AES, false, MRS_EXACT, id_aa64zfr0_aes),
MRS_FIELD(ID_AA64ZFR0, SVEver, false, MRS_EXACT, id_aa64zfr0_svever),
MRS_FIELD_END,
};
#ifdef COMPAT_FREEBSD32
/* ID_ISAR5_EL1 */
static struct mrs_field_value id_isar5_vcma[] = {
@ -2153,6 +2220,12 @@ print_cpu_features(u_int cpu)
print_id_register(sb, "Auxiliary Features 1",
cpu_desc[cpu].id_aa64afr1, id_aa64afr1_fields);
/* AArch64 SVE Feature Register 0 */
/* We check the cpu == 0 case when setting PRINT_ID_AA64_ZFR0 */
if ((cpu_print_regs & PRINT_ID_AA64_ZFR0) != 0)
print_id_register(sb, "SVE Features 0",
cpu_desc[cpu].id_aa64zfr0, id_aa64zfr0_fields);
#ifdef COMPAT_FREEBSD32
/* AArch32 Instruction Set Attribute Register 5 */
if (cpu == 0 || (cpu_print_regs & PRINT_ID_ISAR5) != 0)
@ -2237,6 +2310,16 @@ identify_cpu(u_int cpu)
cpu_desc[cpu].id_aa64pfr0 = READ_SPECIALREG(id_aa64pfr0_el1);
cpu_desc[cpu].id_aa64pfr1 = READ_SPECIALREG(id_aa64pfr1_el1);
/*
* ID_AA64ZFR0_EL1 is only valid when at least one of:
* - ID_AA64PFR0_EL1.SVE is non-zero
* - ID_AA64PFR1_EL1.SME is non-zero
* In other cases it is zero, but still safe to read
*/
cpu_desc[cpu].have_sve =
(ID_AA64PFR0_SVE_VAL(cpu_desc[cpu].id_aa64pfr0) != 0);
cpu_desc[cpu].id_aa64zfr0 = READ_SPECIALREG(ID_AA64ZFR0_EL1_REG);
cpu_desc[cpu].clidr = READ_SPECIALREG(clidr_el1);
clidr = cpu_desc[cpu].clidr;
@ -2320,6 +2403,17 @@ check_cpu_regs(u_int cpu)
if (cpu_desc[cpu].id_aa64pfr1 != cpu_desc[0].id_aa64pfr1)
cpu_print_regs |= PRINT_ID_AA64_PFR1;
/* Only print if ID_AA64ZFR0_EL1 is valid */
if (cpu_desc[cpu].have_sve) {
/* Print if the value changed */
if (cpu_desc[cpu].id_aa64zfr0 != cpu_desc[0].id_aa64zfr0) {
cpu_print_regs |= PRINT_ID_AA64_ZFR0;
/* Print if it didn't, but the previous CPU was invalid */
} else if (cpu > 0 && !cpu_desc[cpu - 1].have_sve) {
cpu_print_regs |= PRINT_ID_AA64_ZFR0;
}
}
if (cpu_desc[cpu].ctr != cpu_desc[0].ctr) {
/*
* If the cache type register is different we may

View File

@ -1007,6 +1007,62 @@
#define ID_AA64PFR1_RAS_frac_V1 (UL(0x0) << ID_AA64PFR1_RAS_frac_SHIFT)
#define ID_AA64PFR1_RAS_frac_V2 (UL(0x1) << ID_AA64PFR1_RAS_frac_SHIFT)
/* ID_AA64ZFR0_EL1 */
#define ID_AA64ZFR0_EL1 MRS_REG(ID_AA64ZFR0_EL1)
#define ID_AA64ZFR0_EL1_REG MRS_REG_ALT_NAME(ID_AA64ZFR0_EL1)
#define ID_AA64ZFR0_EL1_op0 3
#define ID_AA64ZFR0_EL1_op1 0
#define ID_AA64ZFR0_EL1_CRn 0
#define ID_AA64ZFR0_EL1_CRm 4
#define ID_AA64ZFR0_EL1_op2 4
#define ID_AA64ZFR0_SVEver_SHIFT 0
#define ID_AA64ZFR0_SVEver_MASK (UL(0xf) << ID_AA64ZFR0_SVEver_SHIFT)
#define ID_AA64ZFR0_SVEver_VAL(x) ((x) & ID_AA64ZFR0_SVEver_MASK
#define ID_AA64ZFR0_SVEver_SVE1 (UL(0x0) << ID_AA64ZFR0_SVEver_SHIFT)
#define ID_AA64ZFR0_SVEver_SVE2 (UL(0x1) << ID_AA64ZFR0_SVEver_SHIFT)
#define ID_AA64ZFR0_AES_SHIFT 4
#define ID_AA64ZFR0_AES_MASK (UL(0xf) << ID_AA64ZFR0_AES_SHIFT)
#define ID_AA64ZFR0_AES_VAL(x) ((x) & ID_AA64ZFR0_AES_MASK
#define ID_AA64ZFR0_AES_NONE (UL(0x0) << ID_AA64ZFR0_AES_SHIFT)
#define ID_AA64ZFR0_AES_BASE (UL(0x1) << ID_AA64ZFR0_AES_SHIFT)
#define ID_AA64ZFR0_AES_PMULL (UL(0x2) << ID_AA64ZFR0_AES_SHIFT)
#define ID_AA64ZFR0_BitPerm_SHIFT 16
#define ID_AA64ZFR0_BitPerm_MASK (UL(0xf) << ID_AA64ZFR0_BitPerm_SHIFT)
#define ID_AA64ZFR0_BitPerm_VAL(x) ((x) & ID_AA64ZFR0_BitPerm_MASK
#define ID_AA64ZFR0_BitPerm_NONE (UL(0x0) << ID_AA64ZFR0_BitPerm_SHIFT)
#define ID_AA64ZFR0_BitPerm_IMPL (UL(0x1) << ID_AA64ZFR0_BitPerm_SHIFT)
#define ID_AA64ZFR0_BF16_SHIFT 20
#define ID_AA64ZFR0_BF16_MASK (UL(0xf) << ID_AA64ZFR0_BF16_SHIFT)
#define ID_AA64ZFR0_BF16_VAL(x) ((x) & ID_AA64ZFR0_BF16_MASK
#define ID_AA64ZFR0_BF16_NONE (UL(0x0) << ID_AA64ZFR0_BF16_SHIFT)
#define ID_AA64ZFR0_BF16_BASE (UL(0x1) << ID_AA64ZFR0_BF16_SHIFT)
#define ID_AA64ZFR0_BF16_EBF (UL(0x1) << ID_AA64ZFR0_BF16_SHIFT)
#define ID_AA64ZFR0_SHA3_SHIFT 32
#define ID_AA64ZFR0_SHA3_MASK (UL(0xf) << ID_AA64ZFR0_SHA3_SHIFT)
#define ID_AA64ZFR0_SHA3_VAL(x) ((x) & ID_AA64ZFR0_SHA3_MASK
#define ID_AA64ZFR0_SHA3_NONE (UL(0x0) << ID_AA64ZFR0_SHA3_SHIFT)
#define ID_AA64ZFR0_SHA3_IMPL (UL(0x1) << ID_AA64ZFR0_SHA3_SHIFT)
#define ID_AA64ZFR0_SM4_SHIFT 40
#define ID_AA64ZFR0_SM4_MASK (UL(0xf) << ID_AA64ZFR0_SM4_SHIFT)
#define ID_AA64ZFR0_SM4_VAL(x) ((x) & ID_AA64ZFR0_SM4_MASK
#define ID_AA64ZFR0_SM4_NONE (UL(0x0) << ID_AA64ZFR0_SM4_SHIFT)
#define ID_AA64ZFR0_SM4_IMPL (UL(0x1) << ID_AA64ZFR0_SM4_SHIFT)
#define ID_AA64ZFR0_I8MM_SHIFT 44
#define ID_AA64ZFR0_I8MM_MASK (UL(0xf) << ID_AA64ZFR0_I8MM_SHIFT)
#define ID_AA64ZFR0_I8MM_VAL(x) ((x) & ID_AA64ZFR0_I8MM_MASK
#define ID_AA64ZFR0_I8MM_NONE (UL(0x0) << ID_AA64ZFR0_I8MM_SHIFT)
#define ID_AA64ZFR0_I8MM_IMPL (UL(0x1) << ID_AA64ZFR0_I8MM_SHIFT)
#define ID_AA64ZFR0_F32MM_SHIFT 52
#define ID_AA64ZFR0_F32MM_MASK (UL(0xf) << ID_AA64ZFR0_F32MM_SHIFT)
#define ID_AA64ZFR0_F32MM_VAL(x) ((x) & ID_AA64ZFR0_F32MM_MASK
#define ID_AA64ZFR0_F32MM_NONE (UL(0x0) << ID_AA64ZFR0_F32MM_SHIFT)
#define ID_AA64ZFR0_F32MM_IMPL (UL(0x1) << ID_AA64ZFR0_F32MM_SHIFT)
#define ID_AA64ZFR0_F64MM_SHIFT 56
#define ID_AA64ZFR0_F64MM_MASK (UL(0xf) << ID_AA64ZFR0_F64MM_SHIFT)
#define ID_AA64ZFR0_F64MM_VAL(x) ((x) & ID_AA64ZFR0_F64MM_MASK
#define ID_AA64ZFR0_F64MM_NONE (UL(0x0) << ID_AA64ZFR0_F64MM_SHIFT)
#define ID_AA64ZFR0_F64MM_IMPL (UL(0x1) << ID_AA64ZFR0_F64MM_SHIFT)
/* ID_ISAR5_EL1 */
#define ID_ISAR5_EL1 MRS_REG(ID_ISAR5_EL1)
#define ID_ISAR5_EL1_op0 0x3