svn commit: r338961 - in head/sys/arm64: arm64 include

Andrew Turner andrew at FreeBSD.org
Thu Sep 27 13:50:59 UTC 2018


Author: andrew
Date: Thu Sep 27 13:50:57 2018
New Revision: 338961
URL: https://svnweb.freebsd.org/changeset/base/338961

Log:
  Move the undefined instruction handler to identcpu.c so we have access
  to the registers from boot.
  
  Approved by:	re (kib)
  Sponsored by:	ABT Systems Ltd
  Differential Revision:	https://reviews.freebsd.org/D17301

Modified:
  head/sys/arm64/arm64/identcpu.c
  head/sys/arm64/arm64/undefined.c
  head/sys/arm64/include/undefined.h

Modified: head/sys/arm64/arm64/identcpu.c
==============================================================================
--- head/sys/arm64/arm64/identcpu.c	Thu Sep 27 12:20:32 2018	(r338960)
+++ head/sys/arm64/arm64/identcpu.c	Thu Sep 27 13:50:57 2018	(r338961)
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/atomic.h>
 #include <machine/cpu.h>
 #include <machine/cpufunc.h>
+#include <machine/undefined.h>
 
 static int ident_lock;
 
@@ -162,6 +163,98 @@ const struct cpu_implementers cpu_implementers[] = {
 	CPU_IMPLEMENTER_NONE,
 };
 
+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);
+}
+
 static void
 identify_cpu_sysinit(void *dummy __unused)
 {
@@ -170,6 +263,8 @@ identify_cpu_sysinit(void *dummy __unused)
 	CPU_FOREACH(cpu) {
 		print_cpu_features(cpu);
 	}
+
+	install_undef_handler(true, user_mrs_handler);
 }
 SYSINIT(idenrity_cpu, SI_SUB_SMP, SI_ORDER_ANY, identify_cpu_sysinit, NULL);
 

Modified: head/sys/arm64/arm64/undefined.c
==============================================================================
--- head/sys/arm64/arm64/undefined.c	Thu Sep 27 12:20:32 2018	(r338960)
+++ head/sys/arm64/arm64/undefined.c	Thu Sep 27 13:50:57 2018	(r338961)
@@ -53,135 +53,6 @@ struct undef_handler {
  */
 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 @@ undef_init(void)
 	LIST_INIT(&undef_handlers[0]);
 	LIST_INIT(&undef_handlers[1]);
 
-	install_undef_handler(true, user_mrs_handler);
 	install_undef_handler(false, id_aa64mmfr2_handler);
 }
 

Modified: head/sys/arm64/include/undefined.h
==============================================================================
--- head/sys/arm64/include/undefined.h	Thu Sep 27 12:20:32 2018	(r338960)
+++ head/sys/arm64/include/undefined.h	Thu Sep 27 13:50:57 2018	(r338961)
@@ -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 *);


More information about the svn-src-all mailing list