Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/aarch64/aarch64 - add support conditionally executi...
details: https://anonhg.NetBSD.org/src/rev/f7d736e48d28
branches: trunk
changeset: 936351:f7d736e48d28
user: ryo <ryo%NetBSD.org@localhost>
date: Sun Jul 26 07:25:38 2020 +0000
description:
- 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
diffstat:
sys/arch/aarch64/aarch64/trap.c | 142 +++++++++++++++++++++++++++------------
1 files changed, 98 insertions(+), 44 deletions(-)
diffs (214 lines):
diff -r 28e5c3afb5b7 -r f7d736e48d28 sys/arch/aarch64/aarch64/trap.c
--- a/sys/arch/aarch64/aarch64/trap.c Sun Jul 26 07:24:27 2020 +0000
+++ b/sys/arch/aarch64/aarch64/trap.c Sun Jul 26 07:25:38 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.31 2020/07/08 03:45:13 ryo Exp $ */
+/* $NetBSD: trap.c,v 1.32 2020/07/26 07:25:38 ryo Exp $ */
/*-
* Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.31 2020/07/08 03:45:13 ryo Exp $");
+__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.32 2020/07/26 07:25:38 ryo Exp $");
#include "opt_arm_intr_impl.h"
#include "opt_compat_netbsd32.h"
@@ -374,8 +374,10 @@
{
uint32_t insn;
- if (ufetch_32((uint32_t *)tf->tf_pc, &insn))
+ if (ufetch_32((uint32_t *)tf->tf_pc, &insn)) {
+ tf->tf_far = reg_far_el1_read();
return EMUL_ARM_FAULT;
+ }
if ((insn & 0xffffffe0) == 0xd53b0020) {
/* mrs x?,ctr_el0 */
@@ -457,7 +459,7 @@
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);
@@ -550,74 +552,126 @@
return 4;
}
+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->tf_pc, tf->tf_spsr, &insn);
-
- switch (insn_size) {
- case 2:
- /* T32-16bit instruction */
+ tf->tf_far = reg_far_el1_read();
- /*
- * Breakpoint used by GDB.
- */
- if (insn == 0xdefe)
- goto trap;
-
- /* XXX: some T32 IT instruction deprecated should be emulated */
- break;
- case 4:
- /* T32-32bit instruction, or A32 instruction */
+ if (tf->tf_spsr & SPSR_A32_T)
+ return emul_thumb_insn(tf, insn, insn_size);
+ if (insn_size != 4)
+ return EMUL_ARM_FAULT;
- /*
- * Breakpoint used by GDB.
- */
- if (insn == 0xe6000011 || insn == 0xe7ffdefe) {
- trap:
- do_trapsignal(l, SIGTRAP, TRAP_BRKPT,
- (void *)tf->tf_pc, 0);
- return 0;
- }
+ /* Breakpoint used by GDB */
+ if (insn == 0xe6000011 || insn == 0xe7ffdefe) {
+ do_trapsignal(curlwp, SIGTRAP, TRAP_BRKPT,
+ (void *)tf->tf_pc, 0);
+ return EMUL_ARM_SUCCESS;
+ }
- /*
- * Emulate ARMv6 instructions with cache operations
- * register (c7), that can be used in user mode.
- */
- switch (insn & 0x0fff0fff) {
- case 0x0e070f95:
+ /* 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:
+ 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;
@@ -685,7 +739,7 @@
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);
Home |
Main Index |
Thread Index |
Old Index