Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 12 May 2025 12:50:24 GMT
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 5673ea5ca9ec - main - arm64: Start splitting out undef sys insn handling
Message-ID:  <202505121250.54CCoOn2082964@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=5673ea5ca9ec54bc53035d07fbe2ebb1be63a313

commit 5673ea5ca9ec54bc53035d07fbe2ebb1be63a313
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2025-05-12 11:06:45 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2025-05-12 11:06:45 +0000

    arm64: Start splitting out undef sys insn handling
    
    We shouldn't need to decode the instruction when handling an unknown
    SYS, MSR, or MRS instruction that raises an EXCP_MSR exception. The
    exception syndrome (esr) contains all the information we need and is
    safer to use than reading the instruction.
    
    Add a new set of callbacks for these instructions that we can pass in
    either the esr from hardware, or a generated version when we have to
    fall back to instruction decoding.
    
    Reviewed by:    harry.moulton_arm.com
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D50208
---
 sys/arm64/arm64/undefined.c   | 76 +++++++++++++++++++++++++++++++++++++++++++
 sys/arm64/include/armreg.h    |  2 ++
 sys/arm64/include/undefined.h |  3 ++
 3 files changed, 81 insertions(+)

diff --git a/sys/arm64/arm64/undefined.c b/sys/arm64/arm64/undefined.c
index 74b9de49a7ef..a88d47c182cf 100644
--- a/sys/arm64/arm64/undefined.c
+++ b/sys/arm64/arm64/undefined.c
@@ -82,10 +82,17 @@ struct undef_handler {
 	undef_handler_t		uh_handler;
 };
 
+/* System instruction handlers, e.g. msr, mrs, sys */
+struct sys_handler {
+	LIST_ENTRY(sys_handler) sys_link;
+	undef_sys_handler_t	sys_handler;
+};
+
 /*
  * Create the undefined instruction handler lists.
  * This allows us to handle instructions that will trap.
  */
+LIST_HEAD(, sys_handler) sys_handlers = LIST_HEAD_INITIALIZER(sys_handler);
 LIST_HEAD(, undef_handler) undef_handlers =
     LIST_HEAD_INITIALIZER(undef_handlers);
 #ifdef COMPAT_FREEBSD32
@@ -293,6 +300,72 @@ remove_undef_handler(void *handle)
 	free(handle, M_UNDEF);
 }
 
+void
+install_sys_handler(undef_sys_handler_t func)
+{
+	struct sys_handler *sysh;
+
+	sysh = malloc(sizeof(*sysh), M_UNDEF, M_WAITOK);
+	sysh->sys_handler = func;
+	LIST_INSERT_HEAD(&sys_handlers, sysh, sys_link);
+}
+
+bool
+undef_sys(uint64_t esr, struct trapframe *frame)
+{
+	struct sys_handler *sysh;
+
+	LIST_FOREACH(sysh, &sys_handlers, sys_link) {
+		if (sysh->sys_handler(esr, frame))
+			return (true);
+	}
+
+	return (false);
+}
+
+static bool
+undef_sys_insn(struct trapframe *frame, uint32_t insn)
+{
+	uint64_t esr;
+	int op0;
+	bool read;
+
+	read = false;
+	switch (insn & MRS_MASK) {
+	case MRS_VALUE:
+		read = true;
+		/* FALLTHROUGH */
+	case MSR_REG_VALUE:
+		op0 = mrs_Op0(insn);
+		break;
+	case MSR_IMM_VALUE:
+		/*
+		 * MSR (immediate) needs special handling. The
+		 * source register is always 31 (xzr), CRn is 4,
+		 * and op0 is hard coded as 0.
+		 */
+		if (MRS_REGISTER(insn) != 31)
+			return (false);
+		if (mrs_CRn(insn) != 4)
+			return (false);
+		op0 = 0;
+		break;
+	default:
+		return (false);
+	}
+
+	/* Create a fake EXCP_MSR esr value */
+	esr = EXCP_MSR << ESR_ELx_EC_SHIFT;
+	esr |= ESR_ELx_IL;
+	esr |= __ISS_MSR_REG(op0, mrs_Op1(insn), mrs_CRn(insn), mrs_CRm(insn),
+	    mrs_Op2(insn));
+	esr |= MRS_REGISTER(insn) << ISS_MSR_Rt_SHIFT;
+	if (read)
+		esr |= ISS_MSR_DIR;
+
+	return (undef_sys(esr, frame));
+}
+
 int
 undef_insn(struct trapframe *frame)
 {
@@ -317,6 +390,9 @@ undef_insn(struct trapframe *frame)
 	}
 #endif
 
+	if (undef_sys_insn(frame, insn))
+		return (1);
+
 	LIST_FOREACH(uh, &undef_handlers, uh_link) {
 		ret = uh->uh_handler(frame->tf_elr, insn, frame, frame->tf_esr);
 		if (ret)
diff --git a/sys/arm64/include/armreg.h b/sys/arm64/include/armreg.h
index 0e89ad57440f..aff33055a51d 100644
--- a/sys/arm64/include/armreg.h
+++ b/sys/arm64/include/armreg.h
@@ -38,6 +38,8 @@
 
 #define	MRS_MASK			0xfff00000
 #define	MRS_VALUE			0xd5300000
+#define	MSR_REG_VALUE			0xd5100000
+#define	MSR_IMM_VALUE			0xd5000000
 #define	MRS_SPECIAL(insn)		((insn) & 0x000fffe0)
 #define	MRS_REGISTER(insn)		((insn) & 0x0000001f)
 #define	 MRS_Op0_SHIFT			19
diff --git a/sys/arm64/include/undefined.h b/sys/arm64/include/undefined.h
index 104d6e9a8e67..c23b020e960f 100644
--- a/sys/arm64/include/undefined.h
+++ b/sys/arm64/include/undefined.h
@@ -35,6 +35,7 @@
 
 typedef int (*undef_handler_t)(vm_offset_t, uint32_t, struct trapframe *,
     uint32_t);
+typedef bool (*undef_sys_handler_t)(uint64_t, struct trapframe *);
 
 static inline int
 mrs_Op0(uint32_t insn)
@@ -57,11 +58,13 @@ MRS_GET(CRm)
 MRS_GET(Op2)
 
 void undef_init(void);
+void install_sys_handler(undef_sys_handler_t);
 void *install_undef_handler(undef_handler_t);
 #ifdef COMPAT_FREEBSD32
 void *install_undef32_handler(undef_handler_t);
 #endif
 void remove_undef_handler(void *);
+bool undef_sys(uint64_t, struct trapframe *);
 int undef_insn(struct trapframe *);
 
 #endif /* _KERNEL */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202505121250.54CCoOn2082964>