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/99fea32e2685
branches:  netbsd-9
changeset: 948813:99fea32e2685
user:      martin <martin%NetBSD.org@localhost>
date:      Fri Jan 01 12:31:19 2021 +0000

description:
Pull up following revision(s) (requested by rin in ticket #1169):

        sys/arch/aarch64/aarch64/trap.c: revision 1.21
        sys/arch/aarch64/aarch64/trap.c: revision 1.26

PR port-arm/54702
Add support for earmv6hf binaries on COMPAT_NETBSD32 for aarch64:
- Emulate ARMv6 instructions with cache operations register (c7), that
   are deprecated since ARMv7, and disabled on ARMv8 with LP64 kernel.

Many thanks to ryo@ for helping me to add support of Thumb-mode,
as well as providing exhaustive test cases:
   https://github.com/ryo/mcr_test/

We've confirmed:
- Emulation works in Thumb-mode.
- T32 16-bit length illegal instruction results in SIGILL, even if
   it is located nearby a boundary b/w mapped and unmapped pages.
- T32 32-bit instruction results in SIGSEGV if it is located across
   a boundary b/w mapped and unmapped pages.


When emulating obsoleted arm32 instructions, use ufetch(9) rather than
dereference tf_pc directly to retrieve an instruction.
Even if tf_pc is valid when processor decodes the instruction, someone
can unmap its page before tf_pc is read in the exception handler.
Now, SIGSEGV is delivered correctly to the process in this case, rather
than kernel panic.

Pointed out by maxv.

Discussed with ryo and skrll.

diffstat:

 sys/arch/aarch64/aarch64/trap.c |  124 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 122 insertions(+), 2 deletions(-)

diffs (157 lines):

diff -r 52ad94b463e2 -r 99fea32e2685 sys/arch/aarch64/aarch64/trap.c
--- a/sys/arch/aarch64/aarch64/trap.c   Wed Dec 30 15:12:38 2020 +0000
+++ b/sys/arch/aarch64/aarch64/trap.c   Fri Jan 01 12:31:19 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.17.4.2 2019/12/09 15:19:31 martin Exp $ */
+/* $NetBSD: trap.c,v 1.17.4.3 2021/01/01 12:31:19 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.2 2019/12/09 15:19:31 martin Exp $");
+__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.17.4.3 2021/01/01 12:31:19 martin Exp $");
 
 #include "opt_arm_intr_impl.h"
 #include "opt_compat_netbsd32.h"
@@ -348,6 +348,111 @@
        cpu_dosoftints();
 }
 
+#ifdef COMPAT_NETBSD32
+
+/*
+ * 32-bit length Thumb instruction. See ARMv7 DDI0406A A6.3.
+ */
+#define THUMB_32BIT(hi) (((hi) & 0xe000) == 0xe000 && ((hi) & 0x1800))
+
+static int
+fetch_arm_insn(struct trapframe *tf, uint32_t *insn)
+{
+
+       /* THUMB? */
+       if (tf->tf_spsr & SPSR_A32_T) {
+               uint16_t *pc = (uint16_t *)(tf->tf_pc & ~1UL); /* XXX */
+               uint16_t hi, lo;
+
+               if (ufetch_16(pc, &hi))
+                       return -1;
+
+               if (!THUMB_32BIT(hi)) {
+                       /* 16-bit Thumb instruction */
+                       *insn = hi;
+                       return 2;
+               }
+
+               /* 32-bit Thumb instruction */
+               if (ufetch_16(pc + 1, &lo))
+                       return -1;
+
+               *insn = ((uint32_t)hi << 16) | lo;
+               return 4;
+       }
+
+       if (ufetch_32((uint32_t *)tf->tf_pc, insn))
+               return -1;
+
+       return 4;
+}
+
+enum emul_arm_result {
+       EMUL_ARM_SUCCESS = 0,
+       EMUL_ARM_UNKNOWN,
+       EMUL_ARM_FAULT,
+};
+
+static enum emul_arm_result
+emul_arm_insn(struct trapframe *tf)
+{
+       uint32_t insn;
+       int insn_size;
+
+       insn_size = fetch_arm_insn(tf, &insn);
+
+       switch (insn_size) {
+       case 2:
+               /* T32-16bit instruction */
+
+               /* XXX: some T32 IT instruction deprecated should be emulated */
+               break;
+       case 4:
+               /* T32-32bit instruction, or A32 instruction */
+
+               /*
+                * Emulate ARMv6 instructions with cache operations
+                * register (c7), that can be used in user mode.
+                */
+               switch (insn & 0x0fff0fff) {
+               case 0x0e070f95:
+                       /*
+                        * mcr p15, 0, <Rd>, c7, c5, 4
+                        * (flush prefetch buffer)
+                        */
+                       __asm __volatile("isb sy" ::: "memory");
+                       goto emulated;
+               case 0x0e070f9a:
+                       /*
+                        * mcr p15, 0, <Rd>, c7, c10, 4
+                        * (data synchronization barrier)
+                        */
+                       __asm __volatile("dsb sy" ::: "memory");
+                       goto emulated;
+               case 0x0e070fba:
+                       /*
+                        * mcr p15, 0, <Rd>, c7, c10, 5
+                        * (data memory barrier)
+                        */
+                       __asm __volatile("dmb sy" ::: "memory");
+                       goto emulated;
+               default:
+                       break;
+               }
+               break;
+       default:
+               return EMUL_ARM_FAULT;
+       }
+
+       /* unknown, or unsupported instruction */
+       return EMUL_ARM_UNKNOWN;
+
+ emulated:
+       tf->tf_pc += insn_size;
+       return EMUL_ARM_SUCCESS;
+}
+#endif /* COMPAT_NETBSD32 */
+
 void
 trap_el0_32sync(struct trapframe *tf)
 {
@@ -395,11 +500,26 @@
                userret(l);
                break;
 
+       case ESR_EC_UNKNOWN:
+               switch (emul_arm_insn(tf)) {
+               case EMUL_ARM_SUCCESS:
+                       break;
+               case EMUL_ARM_UNKNOWN:
+                       goto unknown;
+               case EMUL_ARM_FAULT:
+                       do_trapsignal(l, SIGSEGV, SEGV_MAPERR,
+                           (void *)tf->tf_pc, esr);
+                       break;
+               }
+               userret(l);
+               break;
+
        case ESR_EC_CP15_RT:
        case ESR_EC_CP15_RRT:
        case ESR_EC_CP14_RT:
        case ESR_EC_CP14_DT:
        case ESR_EC_CP14_RRT:
+unknown:
 #endif /* COMPAT_NETBSD32 */
        default:
 #ifdef DDB



Home | Main Index | Thread Index | Old Index