Teach the arm64 ident CPU code to print non-ID registers

Add support for non-ID registers when printing CPU information. This is
used with the cache type register to print details of the cache on boot.

Sponsored by:	Innovate UK
This commit is contained in:
Andrew Turner 2020-02-26 13:22:23 +00:00
parent d985858aa6
commit a4c354bdd5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=358330

View File

@ -112,6 +112,7 @@ struct cpu_desc {
uint64_t id_aa64mmfr2;
uint64_t id_aa64pfr0;
uint64_t id_aa64pfr1;
uint64_t ctr;
};
static struct cpu_desc cpu_desc[MAXCPU];
@ -128,6 +129,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_CTR_EL0 0x10000000
struct cpu_parts {
u_int part_id;
@ -1089,14 +1091,66 @@ parse_cpu_features_hwcap(u_int cpu)
}
static void
print_id_register(struct sbuf *sb, const char *reg_name, uint64_t reg,
struct mrs_field *fields)
print_ctr_fields(struct sbuf *sb, uint64_t reg, void *arg)
{
sbuf_printf(sb, "%u byte D-cacheline,", CTR_DLINE_SIZE(reg));
sbuf_printf(sb, "%u byte I-cacheline,", CTR_ILINE_SIZE(reg));
reg &= ~(CTR_DLINE_MASK | CTR_ILINE_MASK);
switch(CTR_L1IP_VAL(reg)) {
case CTR_L1IP_VPIPT:
sbuf_printf(sb, "VPIPT");
break;
case CTR_L1IP_AIVIVT:
sbuf_printf(sb, "AIVIVT");
break;
case CTR_L1IP_VIVT:
sbuf_printf(sb, "VIVT");
break;
case CTR_L1IP_PIPT:
sbuf_printf(sb, "PIPT");
break;
}
sbuf_printf(sb, " ICache,");
reg &= ~CTR_L1IP_MASK;
sbuf_printf(sb, "%d byte ERG,", CTR_ERG_SIZE(reg));
sbuf_printf(sb, "%d byte CWG", CTR_CWG_SIZE(reg));
reg &= ~(CTR_ERG_MASK | CTR_CWG_MASK);
if (CTR_IDC_VAL(reg) == 0)
sbuf_printf(sb, ",IDC");
if (CTR_DIC_VAL(reg) == 0)
sbuf_printf(sb, ",DIC");
reg &= ~(CTR_IDC_MASK | CTR_DIC_MASK);
reg &= ~CTR_RES1;
if (reg != 0)
sbuf_printf(sb, ",%lx", reg);
}
static void
print_register(struct sbuf *sb, const char *reg_name, uint64_t reg,
void (*print_fields)(struct sbuf *, uint64_t, void *), void *arg)
{
struct mrs_field_value *fv;
int field, i, j, printed;
sbuf_printf(sb, "%29s = <", reg_name);
print_fields(sb, reg, arg);
sbuf_finish(sb);
printf("%s>\n", sbuf_data(sb));
sbuf_clear(sb);
}
static void
print_id_fields(struct sbuf *sb, uint64_t reg, void *arg)
{
struct mrs_field *fields = arg;
struct mrs_field_value *fv;
int field, i, j, printed;
#define SEP_STR ((printed++) == 0) ? "" : ","
printed = 0;
for (i = 0; fields[i].type != 0; i++) {
@ -1125,10 +1179,14 @@ print_id_register(struct sbuf *sb, const char *reg_name, uint64_t reg,
if (reg != 0)
sbuf_printf(sb, "%s%#lx", SEP_STR, reg);
#undef SEP_STR
}
sbuf_finish(sb);
printf("%s>\n", sbuf_data(sb));
sbuf_clear(sb);
static void
print_id_register(struct sbuf *sb, const char *reg_name, uint64_t reg,
struct mrs_field *fields)
{
print_register(sb, reg_name, reg, print_id_fields, fields);
}
static void
@ -1184,6 +1242,12 @@ print_cpu_features(u_int cpu)
"hardware bugs that may cause the incorrect operation of "
"atomic operations.\n");
/* Cache Type Register */
if (cpu == 0 || (cpu_print_regs & PRINT_CTR_EL0) != 0) {
print_register(sb, "Cache Type",
cpu_desc[cpu].ctr, print_ctr_fields, NULL);
}
/* AArch64 Instruction Set Attribute Register 0 */
if (cpu == 0 || (cpu_print_regs & PRINT_ID_AA64_ISAR0) != 0)
print_id_register(sb, "Instruction Set Attributes 0",
@ -1295,6 +1359,7 @@ identify_cpu(void)
cpu_desc[cpu].mpidr = get_mpidr();
CPU_AFFINITY(cpu) = cpu_desc[cpu].mpidr & CPU_AFF_MASK;
cpu_desc[cpu].ctr = READ_SPECIALREG(ctr_el0);
cpu_desc[cpu].id_aa64dfr0 = READ_SPECIALREG(id_aa64dfr0_el1);
cpu_desc[cpu].id_aa64dfr1 = READ_SPECIALREG(id_aa64dfr1_el1);
cpu_desc[cpu].id_aa64isar0 = READ_SPECIALREG(id_aa64isar0_el1);
@ -1364,6 +1429,9 @@ identify_cpu(void)
if (cpu_desc[cpu].id_aa64pfr1 != cpu_desc[0].id_aa64pfr1)
cpu_print_regs |= PRINT_ID_AA64_PFR1;
if (cpu_desc[cpu].ctr != cpu_desc[0].ctr)
cpu_print_regs |= PRINT_CTR_EL0;
/* Wake up the other CPUs */
atomic_store_rel_int(&ident_lock, 0);
__asm __volatile("sev" ::: "memory");