Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/netbsd-9]: src/sys/arch/aarch64/aarch64 Pull up following revision(s) (r...
details: https://anonhg.NetBSD.org/src/rev/5de386d6a389
branches: netbsd-9
changeset: 964251:5de386d6a389
user: martin <martin%NetBSD.org@localhost>
date: Fri Jan 01 13:14:29 2021 +0000
description:
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
diffstat:
sys/arch/aarch64/aarch64/trap.c | 160 ++++++++++++++++++++++++++-------------
1 files changed, 106 insertions(+), 54 deletions(-)
diffs (247 lines):
diff -r 88ee14424df7 -r 5de386d6a389 sys/arch/aarch64/aarch64/trap.c
--- a/sys/arch/aarch64/aarch64/trap.c Fri Jan 01 13:06:39 2021 +0000
+++ b/sys/arch/aarch64/aarch64/trap.c Fri Jan 01 13:14:29 2021 +0000
@@ -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 @@
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 @@
#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 @@
}
/* 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);
-
- switch (insn_size) {
- case 2:
- /* T32-16bit instruction */
+ insn_size = fetch_arm_insn(tf->tf_pc, tf->tf_spsr, &insn);
+ 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;
@@ -525,7 +577,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