Export ID_AA64PFR0_EL1 to userland
Create a user view of the ID_AA64PFR0_EL1 register with values common across all CPUs. Approved by: re (kib) Sponsored by: ABT Systems Ltd Differential Revision: https://reviews.freebsd.org/D17301
This commit is contained in:
parent
c7637c4d19
commit
e3f284eee7
@ -88,6 +88,7 @@ struct cpu_desc {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct cpu_desc cpu_desc[MAXCPU];
|
struct cpu_desc cpu_desc[MAXCPU];
|
||||||
|
struct cpu_desc user_cpu_desc;
|
||||||
static u_int cpu_print_regs;
|
static u_int cpu_print_regs;
|
||||||
#define PRINT_ID_AA64_AFR0 0x00000001
|
#define PRINT_ID_AA64_AFR0 0x00000001
|
||||||
#define PRINT_ID_AA64_AFR1 0x00000002
|
#define PRINT_ID_AA64_AFR1 0x00000002
|
||||||
@ -163,26 +164,77 @@ const struct cpu_implementers cpu_implementers[] = {
|
|||||||
CPU_IMPLEMENTER_NONE,
|
CPU_IMPLEMENTER_NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mrs_safe_value {
|
#define MRS_TYPE_MASK 0xf
|
||||||
u_int CRm;
|
#define MRS_INVALID 0
|
||||||
u_int Op2;
|
#define MRS_EXACT 1
|
||||||
uint64_t value;
|
#define MRS_EXACT_VAL(x) (MRS_EXACT | ((x) << 4))
|
||||||
|
#define MRS_EXACT_FIELD(x) ((x) >> 4)
|
||||||
|
#define MRS_LOWER 2
|
||||||
|
|
||||||
|
struct mrs_field {
|
||||||
|
bool sign;
|
||||||
|
u_int type;
|
||||||
|
u_int shift;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct mrs_safe_value safe_values[] = {
|
#define MRS_FIELD(_sign, _type, _shift) \
|
||||||
|
{ \
|
||||||
|
.sign = (_sign), \
|
||||||
|
.type = (_type), \
|
||||||
|
.shift = (_shift), \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MRS_FIELD_END { .type = MRS_INVALID, }
|
||||||
|
|
||||||
|
static struct mrs_field id_aa64pfr0_fields[] = {
|
||||||
|
MRS_FIELD(false, MRS_EXACT, ID_AA64PFR0_SVE_SHIFT),
|
||||||
|
MRS_FIELD(false, MRS_EXACT, ID_AA64PFR0_RAS_SHIFT),
|
||||||
|
MRS_FIELD(false, MRS_EXACT, ID_AA64PFR0_GIC_SHIFT),
|
||||||
|
MRS_FIELD(true, MRS_LOWER, ID_AA64PFR0_ADV_SIMD_SHIFT),
|
||||||
|
MRS_FIELD(true, MRS_LOWER, ID_AA64PFR0_FP_SHIFT),
|
||||||
|
MRS_FIELD(false, MRS_EXACT, ID_AA64PFR0_EL3_SHIFT),
|
||||||
|
MRS_FIELD(false, MRS_EXACT, ID_AA64PFR0_EL2_SHIFT),
|
||||||
|
MRS_FIELD(false, MRS_LOWER, ID_AA64PFR0_EL1_SHIFT),
|
||||||
|
MRS_FIELD(false, MRS_LOWER, ID_AA64PFR0_EL0_SHIFT),
|
||||||
|
MRS_FIELD_END,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mrs_field id_aa64dfr0_fields[] = {
|
||||||
|
MRS_FIELD(false, MRS_EXACT, ID_AA64DFR0_PMS_VER_SHIFT),
|
||||||
|
MRS_FIELD(false, MRS_EXACT, ID_AA64DFR0_CTX_CMPS_SHIFT),
|
||||||
|
MRS_FIELD(false, MRS_EXACT, ID_AA64DFR0_WRPS_SHIFT),
|
||||||
|
MRS_FIELD(false, MRS_EXACT, ID_AA64DFR0_BRPS_SHIFT),
|
||||||
|
MRS_FIELD(false, MRS_EXACT, ID_AA64DFR0_PMU_VER_SHIFT),
|
||||||
|
MRS_FIELD(false, MRS_EXACT, ID_AA64DFR0_TRACE_VER_SHIFT),
|
||||||
|
MRS_FIELD(false, MRS_EXACT_VAL(0x6), ID_AA64DFR0_DEBUG_VER_SHIFT),
|
||||||
|
MRS_FIELD_END,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mrs_user_reg {
|
||||||
|
u_int CRm;
|
||||||
|
u_int Op2;
|
||||||
|
size_t offset;
|
||||||
|
struct mrs_field *fields;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mrs_user_reg user_regs[] = {
|
||||||
{ /* id_aa64pfr0_el1 */
|
{ /* id_aa64pfr0_el1 */
|
||||||
.CRm = 4,
|
.CRm = 4,
|
||||||
.Op2 = 0,
|
.Op2 = 0,
|
||||||
.value = ID_AA64PFR0_ADV_SIMD_NONE | ID_AA64PFR0_FP_NONE |
|
.offset = __offsetof(struct cpu_desc, id_aa64pfr0),
|
||||||
ID_AA64PFR0_EL1_64 | ID_AA64PFR0_EL0_64,
|
.fields = id_aa64pfr0_fields,
|
||||||
},
|
},
|
||||||
{ /* id_aa64dfr0_el1 */
|
{ /* id_aa64dfr0_el1 */
|
||||||
.CRm = 5,
|
.CRm = 5,
|
||||||
.Op2 = 0,
|
.Op2 = 0,
|
||||||
.value = ID_AA64DFR0_DEBUG_VER_8,
|
.offset = __offsetof(struct cpu_desc, id_aa64dfr0),
|
||||||
|
.fields = id_aa64dfr0_fields,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define CPU_DESC_FIELD(desc, idx) \
|
||||||
|
*(uint64_t *)((char *)&(desc) + user_regs[(idx)].offset)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
user_mrs_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
|
user_mrs_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
|
||||||
uint32_t esr)
|
uint32_t esr)
|
||||||
@ -213,9 +265,9 @@ user_mrs_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
|
|||||||
Op2 = mrs_Op2(insn);
|
Op2 = mrs_Op2(insn);
|
||||||
value = 0;
|
value = 0;
|
||||||
|
|
||||||
for (i = 0; i < nitems(safe_values); i++) {
|
for (i = 0; i < nitems(user_regs); i++) {
|
||||||
if (safe_values[i].CRm == CRm && safe_values[i].Op2 == Op2) {
|
if (user_regs[i].CRm == CRm && user_regs[i].Op2 == Op2) {
|
||||||
value = safe_values[i].value;
|
value = CPU_DESC_FIELD(user_cpu_desc, i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,13 +307,65 @@ user_mrs_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_user_regs(u_int cpu)
|
||||||
|
{
|
||||||
|
struct mrs_field *fields;
|
||||||
|
uint64_t cur, value;
|
||||||
|
int i, j, cur_field, new_field;
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(user_regs); i++) {
|
||||||
|
value = CPU_DESC_FIELD(cpu_desc[cpu], i);
|
||||||
|
if (cpu == 0)
|
||||||
|
cur = value;
|
||||||
|
else
|
||||||
|
cur = CPU_DESC_FIELD(user_cpu_desc, i);
|
||||||
|
|
||||||
|
fields = user_regs[i].fields;
|
||||||
|
for (j = 0; fields[j].type != 0; j++) {
|
||||||
|
switch (fields[j].type & MRS_TYPE_MASK) {
|
||||||
|
case MRS_EXACT:
|
||||||
|
cur &= ~(0xfu << fields[j].shift);
|
||||||
|
cur |=
|
||||||
|
(uint64_t)MRS_EXACT_FIELD(fields[j].type) <<
|
||||||
|
fields[j].shift;
|
||||||
|
break;
|
||||||
|
case MRS_LOWER:
|
||||||
|
new_field = (value >> fields[j].shift) & 0xf;
|
||||||
|
cur_field = (cur >> fields[j].shift) & 0xf;
|
||||||
|
if ((fields[j].sign &&
|
||||||
|
(int)new_field < (int)cur_field) ||
|
||||||
|
(!fields[j].sign &&
|
||||||
|
(u_int)new_field < (u_int)cur_field)) {
|
||||||
|
cur &= ~(0xfu << fields[j].shift);
|
||||||
|
cur |= new_field << fields[j].shift;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
panic("Invalid field type: %d", fields[j].type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CPU_DESC_FIELD(user_cpu_desc, i) = cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
identify_cpu_sysinit(void *dummy __unused)
|
identify_cpu_sysinit(void *dummy __unused)
|
||||||
{
|
{
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
|
/* Create a user visible cpu description with safe values */
|
||||||
|
memset(&user_cpu_desc, 0, sizeof(user_cpu_desc));
|
||||||
|
/* Safe values for these registers */
|
||||||
|
user_cpu_desc.id_aa64pfr0 = ID_AA64PFR0_ADV_SIMD_NONE |
|
||||||
|
ID_AA64PFR0_FP_NONE | ID_AA64PFR0_EL1_64 | ID_AA64PFR0_EL0_64;
|
||||||
|
user_cpu_desc.id_aa64dfr0 = ID_AA64DFR0_DEBUG_VER_8;
|
||||||
|
|
||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) {
|
||||||
print_cpu_features(cpu);
|
print_cpu_features(cpu);
|
||||||
|
update_user_regs(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
install_undef_handler(true, user_mrs_handler);
|
install_undef_handler(true, user_mrs_handler);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user