Module Name:    src
Committed By:   martin
Date:           Fri Jan  1 13:14:29 UTC 2021

Modified Files:
        src/sys/arch/aarch64/aarch64 [netbsd-9]: trap.c

Log Message:
Pull up following revision(s) (requested by rin in ticket #1175):

        sys/arch/aarch64/aarch64/trap.c: revision 1.28,1.31,1.32 (patch)

- add support conditionally execution for A32 instruction emulation
- separated the processing of ARM and THUMB emul clearly. do not confuse the 
Thumb-32bit instruction with the ARM instruction.
- use far_el1 instead of tf_pc to return correct fault address when instruction 
emulation


To generate a diff of this commit:
cvs rdiff -u -r1.17.4.4 -r1.17.4.5 src/sys/arch/aarch64/aarch64/trap.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/aarch64/aarch64/trap.c
diff -u src/sys/arch/aarch64/aarch64/trap.c:1.17.4.4 src/sys/arch/aarch64/aarch64/trap.c:1.17.4.5
--- src/sys/arch/aarch64/aarch64/trap.c:1.17.4.4	Fri Jan  1 12:58:35 2021
+++ src/sys/arch/aarch64/aarch64/trap.c	Fri Jan  1 13:14:29 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.17.4.4 2021/01/01 12:58:35 martin Exp $ */
+/* $NetBSD: trap.c,v 1.17.4.5 2021/01/01 13:14:29 martin Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.17.4.4 2021/01/01 12:58:35 martin Exp $");
+__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.17.4.5 2021/01/01 13:14:29 martin Exp $");
 
 #include "opt_arm_intr_impl.h"
 #include "opt_compat_netbsd32.h"
@@ -88,6 +88,12 @@ dtrace_trap_func_t		dtrace_trap_func = N
 int (*dtrace_invop_jump_addr)(struct trapframe *);
 #endif
 
+enum emul_arm_result {
+	EMUL_ARM_SUCCESS = 0,
+	EMUL_ARM_UNKNOWN,
+	EMUL_ARM_FAULT,
+};
+
 const char * const trap_names[] = {
 	[ESR_EC_UNKNOWN]	= "Unknown Reason (Illegal Instruction)",
 	[ESR_EC_SERROR]		= "SError Interrupt",
@@ -356,15 +362,15 @@ interrupt(struct trapframe *tf)
 #define THUMB_32BIT(hi) (((hi) & 0xe000) == 0xe000 && ((hi) & 0x1800))
 
 static int
-fetch_arm_insn(struct trapframe *tf, uint32_t *insn)
+fetch_arm_insn(uint64_t pc, uint64_t spsr, uint32_t *insn)
 {
 
 	/* THUMB? */
-	if (tf->tf_spsr & SPSR_A32_T) {
-		uint16_t *pc = (uint16_t *)(tf->tf_pc & ~1UL); /* XXX */
+	if (spsr & SPSR_A32_T) {
+		uint16_t *p = (uint16_t *)(pc & ~1UL); /* XXX */
 		uint16_t hi, lo;
 
-		if (ufetch_16(pc, &hi))
+		if (ufetch_16(p, &hi))
 			return -1;
 
 		if (!THUMB_32BIT(hi)) {
@@ -374,93 +380,139 @@ fetch_arm_insn(struct trapframe *tf, uin
 		}
 
 		/* 32-bit Thumb instruction */
-		if (ufetch_16(pc + 1, &lo))
+		if (ufetch_16(p + 1, &lo))
 			return -1;
 
 		*insn = ((uint32_t)hi << 16) | lo;
 		return 4;
 	}
 
-	if (ufetch_32((uint32_t *)tf->tf_pc, insn))
+	if (ufetch_32((uint32_t *)pc, insn))
 		return -1;
 
 	return 4;
 }
 
-enum emul_arm_result {
-	EMUL_ARM_SUCCESS = 0,
-	EMUL_ARM_UNKNOWN,
-	EMUL_ARM_FAULT,
-};
+static bool
+arm_cond_match(uint32_t insn, uint64_t spsr)
+{
+	bool invert = (insn >> 28) & 1;
+	bool match;
+
+	switch (insn >> 29) {
+	case 0:	/* EQ or NE */
+		match = spsr & SPSR_Z;
+		break;
+	case 1:	/* CS/HI or CC/LO */
+		match = spsr & SPSR_C;
+		break;
+	case 2:	/* MI or PL */
+		match = spsr & SPSR_N;
+		break;
+	case 3:	/* VS or VC */
+		match = spsr & SPSR_V;
+		break;
+	case 4:	/* HI or LS */
+		match = ((spsr & (SPSR_C | SPSR_Z)) == SPSR_C);
+		break;
+	case 5:	/* GE or LT */
+		match = (!(spsr & SPSR_N) == !(spsr & SPSR_V));
+		break;
+	case 6:	/* GT or LE */
+		match = !(spsr & SPSR_Z) &&
+		    (!(spsr & SPSR_N) == !(spsr & SPSR_V));
+		break;
+	case 7:	/* AL */
+		match = true;
+		break;
+	}
+	return (!match != !invert);
+}
+
+static enum emul_arm_result
+emul_thumb_insn(struct trapframe *tf, uint32_t insn, int insn_size)
+{
+	/* T32-16bit or 32bit instructions */
+	switch (insn_size) {
+	case 2:
+		/* Breakpoint used by GDB */
+		if (insn == 0xdefe) {
+			do_trapsignal(curlwp, SIGTRAP, TRAP_BRKPT,
+			    (void *)tf->tf_pc, 0);
+			return EMUL_ARM_SUCCESS;
+		}
+		/* XXX: some T32 IT instruction deprecated should be emulated */
+		break;
+	case 4:
+		break;
+	default:
+		return EMUL_ARM_FAULT;
+	}
+	return EMUL_ARM_UNKNOWN;
+}
 
 static enum emul_arm_result
 emul_arm_insn(struct trapframe *tf)
 {
-	struct lwp * const l = curlwp;
 	uint32_t insn;
 	int insn_size;
 
-	insn_size = fetch_arm_insn(tf, &insn);
+	insn_size = fetch_arm_insn(tf->tf_pc, tf->tf_spsr, &insn);
+	tf->tf_far = reg_far_el1_read();
 
-	switch (insn_size) {
-	case 2:
-		/* T32-16bit instruction */
-
-		/*
-		 * Breakpoint used by GDB.
-		 */
-		if (insn == 0xdefe)
-			goto trap;
+	if (tf->tf_spsr & SPSR_A32_T)
+		return emul_thumb_insn(tf, insn, insn_size);
+	if (insn_size != 4)
+		return EMUL_ARM_FAULT;
 
-		/* XXX: some T32 IT instruction deprecated should be emulated */
-		break;
-	case 4:
-		/* T32-32bit instruction, or A32 instruction */
+	/* Breakpoint used by GDB */
+	if (insn == 0xe6000011 || insn == 0xe7ffdefe) {
+		do_trapsignal(curlwp, SIGTRAP, TRAP_BRKPT,
+		    (void *)tf->tf_pc, 0);
+		return EMUL_ARM_SUCCESS;
+	}
 
-		/*
-		 * Breakpoint used by GDB.
-		 */
-		if (insn == 0xe6000011 || insn == 0xe7ffdefe) {
- trap:
-			do_trapsignal(l, SIGTRAP, TRAP_BRKPT,
-			    (void *)tf->tf_pc, 0);
-			return 0;
-		}
+	/* Unconditional instruction extension space? */
+	if ((insn & 0xf0000000) == 0xf0000000)
+		goto unknown_insn;
 
-		/*
-		 * Emulate ARMv6 instructions with cache operations
-		 * register (c7), that can be used in user mode.
-		 */
-		switch (insn & 0x0fff0fff) {
-		case 0x0e070f95:
+	/*
+	 * Emulate ARMv6 instructions with cache operations
+	 * register (c7), that can be used in user mode.
+	 */
+	switch (insn & 0x0fff0fff) {
+	case 0x0e070f95:
+		if (arm_cond_match(insn, tf->tf_spsr)) {
 			/*
 			 * mcr p15, 0, <Rd>, c7, c5, 4
 			 * (flush prefetch buffer)
 			 */
 			__asm __volatile("isb sy" ::: "memory");
-			goto emulated;
-		case 0x0e070f9a:
+		}
+		goto emulated;
+	case 0x0e070f9a:
+		if (arm_cond_match(insn, tf->tf_spsr)) {
 			/*
 			 * mcr p15, 0, <Rd>, c7, c10, 4
 			 * (data synchronization barrier)
 			 */
 			__asm __volatile("dsb sy" ::: "memory");
-			goto emulated;
-		case 0x0e070fba:
+		}
+		goto emulated;
+	case 0x0e070fba:
+		if (arm_cond_match(insn, tf->tf_spsr)) {
 			/*
 			 * mcr p15, 0, <Rd>, c7, c10, 5
 			 * (data memory barrier)
 			 */
 			__asm __volatile("dmb sy" ::: "memory");
-			goto emulated;
-		default:
-			break;
 		}
-		break;
+		goto emulated;
 	default:
-		return EMUL_ARM_FAULT;
+		break;
 	}
 
+ unknown_insn:
 	/* unknown, or unsupported instruction */
 	return EMUL_ARM_UNKNOWN;
 
@@ -525,7 +577,7 @@ trap_el0_32sync(struct trapframe *tf)
 			goto unknown;
 		case EMUL_ARM_FAULT:
 			do_trapsignal(l, SIGSEGV, SEGV_MAPERR,
-			    (void *)tf->tf_pc, esr);
+			    (void *)tf->tf_far, esr);
 			break;
 		}
 		userret(l);

Reply via email to