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/4a23e6d2fed1
branches:  netbsd-9
changeset: 1002122:4a23e6d2fed1
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 77ea87e2aace -r 4a23e6d2fed1 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