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