Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F162804916
D17301.id48393.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D17301.id48393.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Sat, Jul 18, 2:18 AM (19 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35159265
Default Alt Text
D17301.id48393.diff (10 KB)
Attached To
Mode
D17301: Export ID_AA64PFR0_EL1 to userland
Attached
Detach File
Event Timeline
Log In to Comment