Page MenuHomeFreeBSD

D16533.id46654.diff
No OneTemporary

D16533.id46654.diff

Index: head/sys/arm64/arm64/undefined.c
===================================================================
--- head/sys/arm64/arm64/undefined.c
+++ head/sys/arm64/arm64/undefined.c
@@ -53,6 +53,135 @@
*/
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.
@@ -63,9 +192,6 @@
{
int reg;
-#define MRS_MASK 0xfff00000
-#define MRS_VALUE 0xd5300000
-#define MRS_REGISTER(insn) ((insn) & 0x1f)
#define MRS_ID_AA64MMFR2_EL0_MASK (MRS_MASK | 0x000fffe0)
#define MRS_ID_AA64MMFR2_EL0_VALUE (MRS_VALUE | 0x00080740)
@@ -93,6 +219,7 @@
LIST_INIT(&undef_handlers[0]);
LIST_INIT(&undef_handlers[1]);
+ install_undef_handler(true, user_mrs_handler);
install_undef_handler(false, id_aa64mmfr2_handler);
}

File Metadata

Mime Type
text/plain
Expires
Wed, Oct 14, 5:04 PM (5 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40809944
Default Alt Text
D16533.id46654.diff (3 KB)

Event Timeline