git: 18af5a180b29 - main - arm64: Enable MOPS usage in the kernel

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Tue, 10 Feb 2026 15:43:30 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=18af5a180b29f425b8427263be5517d3573ca220

commit 18af5a180b29f425b8427263be5517d3573ca220
Author:     Sarah Walker <sarah.walker2@arm.com>
AuthorDate: 2026-02-09 20:39:53 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2026-02-10 15:39:56 +0000

    arm64: Enable MOPS usage in the kernel
    
    Support handling kernel-side MOE exceptions.
    
    Reported by:    andrew
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D54943
---
 sys/arm64/arm64/trap.c | 123 +++++++++++++++++++++++++------------------------
 1 file changed, 63 insertions(+), 60 deletions(-)

diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c
index 3de56187657c..b3c68fa4826f 100644
--- a/sys/arm64/arm64/trap.c
+++ b/sys/arm64/arm64/trap.c
@@ -480,6 +480,66 @@ fpe_trap(struct thread *td, void *addr, uint32_t exception)
 }
 #endif
 
+static void
+handle_moe(struct thread *td, struct trapframe *frame, uint64_t esr)
+{
+	uint64_t src;
+	uint64_t dest;
+	uint64_t size;
+	int src_reg;
+	int dest_reg;
+	int size_reg;
+	int format_option;
+
+	format_option = esr & ISS_MOE_FORMAT_OPTION_MASK;
+	dest_reg = (esr & ISS_MOE_DESTREG_MASK) >> ISS_MOE_DESTREG_SHIFT;
+	size_reg = (esr & ISS_MOE_SIZEREG_MASK) >> ISS_MOE_SIZEREG_SHIFT;
+	dest = frame->tf_x[dest_reg];
+	size = frame->tf_x[size_reg];
+
+	/*
+	 * Put the registers back in the original format suitable for a
+	 * prologue instruction, using the generic return routine from the
+	 * Arm ARM (DDI 0487I.a) rules CNTMJ and MWFQH.
+	 */
+	if (esr & ISS_MOE_MEMINST) {
+		/* SET* instruction */
+		if (format_option == ISS_MOE_FORMAT_OPTION_A ||
+		    format_option == ISS_MOE_FORMAT_OPTION_A2) {
+			/* Format is from Option A; forward set */
+			frame->tf_x[dest_reg] = dest + size;
+			frame->tf_x[size_reg] = -size;
+		}
+	} else {
+		/* CPY* instruction */
+		src_reg = (esr & ISS_MOE_SRCREG_MASK) >> ISS_MOE_SRCREG_SHIFT;
+		src = frame->tf_x[src_reg];
+
+		if (format_option == ISS_MOE_FORMAT_OPTION_B ||
+		    format_option == ISS_MOE_FORMAT_OPTION_B2) {
+			/* Format is from Option B */
+			if (frame->tf_spsr & PSR_N) {
+				/* Backward copy */
+				frame->tf_x[dest_reg] = dest - size;
+				frame->tf_x[src_reg] = src + size;
+			}
+		} else {
+			/* Format is from Option A */
+			if (frame->tf_x[size_reg] & (1UL << 63)) {
+				/* Forward copy */
+				frame->tf_x[dest_reg] = dest + size;
+				frame->tf_x[src_reg] = src + size;
+				frame->tf_x[size_reg] = -size;
+			}
+		}
+	}
+
+	if (esr & ISS_MOE_FROM_EPILOGUE)
+		frame->tf_elr -= 8;
+	else
+		frame->tf_elr -= 4;
+}
+
 /*
  * See the comment above data_abort().
  */
@@ -589,6 +649,9 @@ do_el1h_sync(struct thread *td, struct trapframe *frame)
 		print_gp_register("far", far);
 		panic("Branch Target exception");
 		break;
+	case EXCP_MOE:
+		handle_moe(td, frame, esr);
+		break;
 	default:
 		print_registers(frame);
 		print_gp_register("far", far);
@@ -597,66 +660,6 @@ do_el1h_sync(struct thread *td, struct trapframe *frame)
 	}
 }
 
-static void
-handle_moe(struct thread *td, struct trapframe *frame, uint64_t esr)
-{
-	uint64_t src;
-	uint64_t dest;
-	uint64_t size;
-	int src_reg;
-	int dest_reg;
-	int size_reg;
-	int format_option;
-
-	format_option = esr & ISS_MOE_FORMAT_OPTION_MASK;
-	dest_reg = (esr & ISS_MOE_DESTREG_MASK) >> ISS_MOE_DESTREG_SHIFT;
-	size_reg = (esr & ISS_MOE_SIZEREG_MASK) >> ISS_MOE_SIZEREG_SHIFT;
-	dest = frame->tf_x[dest_reg];
-	size = frame->tf_x[size_reg];
-
-	/*
-	 * Put the registers back in the original format suitable for a
-	 * prologue instruction, using the generic return routine from the
-	 * Arm ARM (DDI 0487I.a) rules CNTMJ and MWFQH.
-	 */
-	if (esr & ISS_MOE_MEMINST) {
-		/* SET* instruction */
-		if (format_option == ISS_MOE_FORMAT_OPTION_A ||
-		    format_option == ISS_MOE_FORMAT_OPTION_A2) {
-			/* Format is from Option A; forward set */
-			frame->tf_x[dest_reg] = dest + size;
-			frame->tf_x[size_reg] = -size;
-		}
-	} else {
-		/* CPY* instruction */
-		src_reg = (esr & ISS_MOE_SRCREG_MASK) >> ISS_MOE_SRCREG_SHIFT;
-		src = frame->tf_x[src_reg];
-
-		if (format_option == ISS_MOE_FORMAT_OPTION_B ||
-		    format_option == ISS_MOE_FORMAT_OPTION_B2) {
-			/* Format is from Option B */
-			if (frame->tf_spsr & PSR_N) {
-				/* Backward copy */
-				frame->tf_x[dest_reg] = dest - size;
-				frame->tf_x[src_reg] = src + size;
-			}
-		} else {
-			/* Format is from Option A */
-			if (frame->tf_x[size_reg] & (1UL << 63)) {
-				/* Forward copy */
-				frame->tf_x[dest_reg] = dest + size;
-				frame->tf_x[src_reg] = src + size;
-				frame->tf_x[size_reg] = -size;
-			}
-		}
-	}
-
-	if (esr & ISS_MOE_FROM_EPILOGUE)
-		frame->tf_elr -= 8;
-	else
-		frame->tf_elr -= 4;
-}
-
 void
 do_el0_sync(struct thread *td, struct trapframe *frame)
 {