Page MenuHomeFreeBSD

D17301.id48393.diff
No OneTemporary

D17301.id48393.diff

Index: sys/arm64/arm64/identcpu.c
===================================================================
--- sys/arm64/arm64/identcpu.c
+++ sys/arm64/arm64/identcpu.c
@@ -43,6 +43,7 @@
#include <machine/atomic.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
+#include <machine/undefined.h>
static int ident_lock;
@@ -87,6 +88,8 @@
};
struct cpu_desc cpu_desc[MAXCPU];
+struct cpu_desc user_cpu_desc;
+
static u_int cpu_print_regs;
#define PRINT_ID_AA64_AFR0 0x00000001
#define PRINT_ID_AA64_AFR1 0x00000002
@@ -162,14 +165,211 @@
CPU_IMPLEMENTER_NONE,
};
+#define MRS_TYPE_MASK 0xf
+#define MRS_INVALID 0
+#define MRS_EXACT 1
+#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;
+};
+
+#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_safe_value {
+ u_int CRm;
+ u_int Op2;
+ size_t offset;
+ struct mrs_field *fields;
+};
+
+static struct mrs_safe_value safe_values[] = {
+ { /* id_aa64pfr0_el1 */
+ .CRm = 4,
+ .Op2 = 0,
+ .offset = __offsetof(struct cpu_desc, id_aa64pfr0),
+ .fields = id_aa64pfr0_fields,
+ },
+ { /* id_aa64dfr0_el1 */
+ .CRm = 5,
+ .Op2 = 0,
+ .offset = __offsetof(struct cpu_desc, id_aa64dfr0),
+ .fields = id_aa64dfr0_fields,
+ },
+};
+
+#define CPU_DESC_FIELD(desc, idx) \
+ *(uint64_t *)((char *)&(desc) + safe_values[(idx)].offset)
+
+static int
+user_mrs_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
+ uint32_t esr)
+{
+ uint64_t value;
+ int CRm, Op2, i, reg;
+
+ if ((insn & MRS_MASK) != MRS_VALUE)
+ return (0);
+
+ /*
+ * We only emulate Op0 == 3, Op1 == 0, CRn == 0, CRm == {0, 4-7}.
+ * These are in the EL1 CPU identification space.
+ * CRm == 0 holds MIDR_EL1, MPIDR_EL1, and REVID_EL1.
+ * CRm == {4-7} holds the ID_AA64 registers.
+ *
+ * For full details see the ARMv8 ARM (ARM DDI 0487C.a)
+ * Table D9-2 System instruction encodings for non-Debug System
+ * register accesses.
+ */
+ if (mrs_Op0(insn) != 3 || mrs_Op1(insn) != 0 || mrs_CRn(insn) != 0)
+ return (0);
+
+ CRm = mrs_CRm(insn);
+ if (CRm > 7 || (CRm < 4 && CRm != 0))
+ return (0);
+
+ Op2 = mrs_Op2(insn);
+ value = 0;
+
+ for (i = 0; i < nitems(safe_values); i++) {
+ if (safe_values[i].CRm == CRm && safe_values[i].Op2 == Op2) {
+ value = CPU_DESC_FIELD(user_cpu_desc, i);
+ break;
+ }
+ }
+
+ if (CRm == 0) {
+ switch (Op2) {
+ case 0:
+ value = READ_SPECIALREG(midr_el1);
+ break;
+ case 5:
+ value = READ_SPECIALREG(mpidr_el1);
+ break;
+ case 6:
+ value = READ_SPECIALREG(revidr_el1);
+ break;
+ default:
+ return (0);
+ }
+ }
+
+ /*
+ * We will handle this instruction, move to the next so we
+ * don't trap here again.
+ */
+ frame->tf_elr += INSN_SIZE;
+
+ reg = MRS_REGISTER(insn);
+ /* If reg is 31 then write to xzr, i.e. do nothing */
+ if (reg == 31)
+ return (1);
+
+ if (reg < nitems(frame->tf_x))
+ frame->tf_x[reg] = value;
+ else if (reg == 30)
+ frame->tf_lr = value;
+
+ 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(safe_values); i++) {
+ value = CPU_DESC_FIELD(cpu_desc[cpu], i);
+ if (cpu == 0)
+ cur = value;
+ else
+ cur = CPU_DESC_FIELD(user_cpu_desc, i);
+
+ fields = safe_values[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
identify_cpu_sysinit(void *dummy __unused)
{
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) {
print_cpu_features(cpu);
+ update_user_regs(cpu);
}
+
+ install_undef_handler(true, user_mrs_handler);
}
SYSINIT(idenrity_cpu, SI_SUB_SMP, SI_ORDER_ANY, identify_cpu_sysinit, NULL);
Index: sys/arm64/arm64/undefined.c
===================================================================
--- sys/arm64/arm64/undefined.c
+++ sys/arm64/arm64/undefined.c
@@ -53,135 +53,6 @@
*/
LIST_HEAD(, undef_handler) undef_handlers[2];
-#define MRS_MASK 0xfff00000
-#define MRS_VALUE 0xd5300000
-#define MRS_SPECIAL(insn) ((insn) & 0x000fffe0)
-#define MRS_REGISTER(insn) ((insn) & 0x0000001f)
-#define MRS_Op0_SHIFT 19
-#define MRS_Op0_MASK 0x00080000
-#define MRS_Op1_SHIFT 16
-#define MRS_Op1_MASK 0x00070000
-#define MRS_CRn_SHIFT 12
-#define MRS_CRn_MASK 0x0000f000
-#define MRS_CRm_SHIFT 8
-#define MRS_CRm_MASK 0x00000f00
-#define MRS_Op2_SHIFT 5
-#define MRS_Op2_MASK 0x000000e0
-#define MRS_Rt_SHIFT 0
-#define MRS_Rt_MASK 0x0000001f
-
-static inline int
-mrs_Op0(uint32_t insn)
-{
-
- /* op0 is encoded without the top bit in a mrs instruction */
- return (2 | ((insn & MRS_Op0_MASK) >> MRS_Op0_SHIFT));
-}
-
-#define MRS_GET(op) \
-static inline int \
-mrs_##op(uint32_t insn) \
-{ \
- \
- return ((insn & MRS_##op##_MASK) >> MRS_##op##_SHIFT); \
-}
-MRS_GET(Op1)
-MRS_GET(CRn)
-MRS_GET(CRm)
-MRS_GET(Op2)
-
-struct mrs_safe_value {
- u_int CRm;
- u_int Op2;
- uint64_t value;
-};
-
-static struct mrs_safe_value safe_values[] = {
- { /* id_aa64pfr0_el1 */
- .CRm = 4,
- .Op2 = 0,
- .value = ID_AA64PFR0_ADV_SIMD_NONE | ID_AA64PFR0_FP_NONE |
- ID_AA64PFR0_EL1_64 | ID_AA64PFR0_EL0_64,
- },
- { /* id_aa64dfr0_el1 */
- .CRm = 5,
- .Op2 = 0,
- .value = ID_AA64DFR0_DEBUG_VER_8,
- },
-};
-
-static int
-user_mrs_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
- uint32_t esr)
-{
- uint64_t value;
- int CRm, Op2, i, reg;
-
- if ((insn & MRS_MASK) != MRS_VALUE)
- return (0);
-
- /*
- * We only emulate Op0 == 3, Op1 == 0, CRn == 0, CRm == {0, 4-7}.
- * These are in the EL1 CPU identification space.
- * CRm == 0 holds MIDR_EL1, MPIDR_EL1, and REVID_EL1.
- * CRm == {4-7} holds the ID_AA64 registers.
- *
- * For full details see the ARMv8 ARM (ARM DDI 0487C.a)
- * Table D9-2 System instruction encodings for non-Debug System
- * register accesses.
- */
- if (mrs_Op0(insn) != 3 || mrs_Op1(insn) != 0 || mrs_CRn(insn) != 0)
- return (0);
-
- CRm = mrs_CRm(insn);
- if (CRm > 7 || (CRm < 4 && CRm != 0))
- return (0);
-
- Op2 = mrs_Op2(insn);
- value = 0;
-
- for (i = 0; i < nitems(safe_values); i++) {
- if (safe_values[i].CRm == CRm && safe_values[i].Op2 == Op2) {
- value = safe_values[i].value;
- break;
- }
- }
-
- if (CRm == 0) {
- switch (Op2) {
- case 0:
- value = READ_SPECIALREG(midr_el1);
- break;
- case 5:
- value = READ_SPECIALREG(mpidr_el1);
- break;
- case 6:
- value = READ_SPECIALREG(revidr_el1);
- break;
- default:
- return (0);
- }
- }
-
- /*
- * We will handle this instruction, move to the next so we
- * don't trap here again.
- */
- frame->tf_elr += INSN_SIZE;
-
- reg = MRS_REGISTER(insn);
- /* If reg is 31 then write to xzr, i.e. do nothing */
- if (reg == 31)
- return (1);
-
- if (reg < nitems(frame->tf_x))
- frame->tf_x[reg] = value;
- else if (reg == 30)
- frame->tf_lr = value;
-
- return (1);
-}
-
/*
* Work around a bug in QEMU prior to 2.5.1 where reading unknown ID
* registers would raise an exception when they should return 0.
@@ -219,7 +90,6 @@
LIST_INIT(&undef_handlers[0]);
LIST_INIT(&undef_handlers[1]);
- install_undef_handler(true, user_mrs_handler);
install_undef_handler(false, id_aa64mmfr2_handler);
}
Index: sys/arm64/include/undefined.h
===================================================================
--- sys/arm64/include/undefined.h
+++ sys/arm64/include/undefined.h
@@ -36,6 +36,43 @@
typedef int (*undef_handler_t)(vm_offset_t, uint32_t, struct trapframe *,
uint32_t);
+#define MRS_MASK 0xfff00000
+#define MRS_VALUE 0xd5300000
+#define MRS_SPECIAL(insn) ((insn) & 0x000fffe0)
+#define MRS_REGISTER(insn) ((insn) & 0x0000001f)
+#define MRS_Op0_SHIFT 19
+#define MRS_Op0_MASK 0x00080000
+#define MRS_Op1_SHIFT 16
+#define MRS_Op1_MASK 0x00070000
+#define MRS_CRn_SHIFT 12
+#define MRS_CRn_MASK 0x0000f000
+#define MRS_CRm_SHIFT 8
+#define MRS_CRm_MASK 0x00000f00
+#define MRS_Op2_SHIFT 5
+#define MRS_Op2_MASK 0x000000e0
+#define MRS_Rt_SHIFT 0
+#define MRS_Rt_MASK 0x0000001f
+
+static inline int
+mrs_Op0(uint32_t insn)
+{
+
+ /* op0 is encoded without the top bit in a mrs instruction */
+ return (2 | ((insn & MRS_Op0_MASK) >> MRS_Op0_SHIFT));
+}
+
+#define MRS_GET(op) \
+static inline int \
+mrs_##op(uint32_t insn) \
+{ \
+ \
+ return ((insn & MRS_##op##_MASK) >> MRS_##op##_SHIFT); \
+}
+MRS_GET(Op1)
+MRS_GET(CRn)
+MRS_GET(CRm)
+MRS_GET(Op2)
+
void undef_init(void);
void *install_undef_handler(bool, undef_handler_t);
void remove_undef_handler(void *);

File Metadata

Mime Type
text/plain
Expires
Fri, Jul 17, 4:41 AM (51 m, 44 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35159265
Default Alt Text
D17301.id48393.diff (10 KB)

Event Timeline