Module Name:    src
Committed By:   rin
Date:           Sun Nov 24 04:08:36 UTC 2019

Modified Files:
        src/sys/arch/aarch64/aarch64: exec_machdep.c netbsd32_machdep.c trap.c
        src/sys/arch/aarch64/include: netbsd32_machdep.h param.h proc.h

Log Message:
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.

- ep_machine_arch (default: earmv7hf) is copied from executables, as we
  do for mips64. "uname -p" reports earmv6hf if compiled for earmv6hf;
  configure scripts etc can determine the appropriate architecture.

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.

XXX
pullup to netbsd-9


To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/aarch64/aarch64/exec_machdep.c
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/aarch64/aarch64/netbsd32_machdep.c
cvs rdiff -u -r1.20 -r1.21 src/sys/arch/aarch64/aarch64/trap.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/aarch64/include/netbsd32_machdep.h
cvs rdiff -u -r1.12 -r1.13 src/sys/arch/aarch64/include/param.h
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/aarch64/include/proc.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/aarch64/aarch64/exec_machdep.c
diff -u src/sys/arch/aarch64/aarch64/exec_machdep.c:1.4 src/sys/arch/aarch64/aarch64/exec_machdep.c:1.5
--- src/sys/arch/aarch64/aarch64/exec_machdep.c:1.4	Wed Nov 28 08:12:15 2018
+++ src/sys/arch/aarch64/aarch64/exec_machdep.c	Sun Nov 24 04:08:36 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: exec_machdep.c,v 1.4 2018/11/28 08:12:15 ryo Exp $ */
+/* $NetBSD: exec_machdep.c,v 1.5 2019/11/24 04:08:36 rin Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: exec_machdep.c,v 1.4 2018/11/28 08:12:15 ryo Exp $");
+__KERNEL_RCSID(1, "$NetBSD: exec_machdep.c,v 1.5 2019/11/24 04:08:36 rin Exp $");
 
 #include "opt_compat_netbsd.h"
 #include "opt_compat_netbsd32.h"
@@ -83,6 +83,13 @@ aarch64_netbsd_elf32_probe(struct lwp *l
 	    ID_AA64PFR0_EL1_EL0_64_32)
 		return ENOEXEC;
 
+	/*
+	 * Copy (if any) the machine_arch of the executable to the proc.
+	 */
+	if (epp->ep_machine_arch[0] != 0)
+		strlcpy(l->l_proc->p_md.md_march32, epp->ep_machine_arch,
+		    sizeof(l->l_proc->p_md.md_march32));
+
 	return 0;
 }
 #endif

Index: src/sys/arch/aarch64/aarch64/netbsd32_machdep.c
diff -u src/sys/arch/aarch64/aarch64/netbsd32_machdep.c:1.8 src/sys/arch/aarch64/aarch64/netbsd32_machdep.c:1.9
--- src/sys/arch/aarch64/aarch64/netbsd32_machdep.c:1.8	Wed Nov 20 19:37:51 2019
+++ src/sys/arch/aarch64/aarch64/netbsd32_machdep.c	Sun Nov 24 04:08:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_machdep.c,v 1.8 2019/11/20 19:37:51 pgoyette Exp $	*/
+/*	$NetBSD: netbsd32_machdep.c,v 1.9 2019/11/24 04:08:36 rin Exp $	*/
 
 /*
  * Copyright (c) 2018 Ryo Shimizu <r...@nerv.org>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.8 2019/11/20 19:37:51 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.9 2019/11/24 04:08:36 rin Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_compat_netbsd.h"
@@ -55,11 +55,7 @@ __KERNEL_RCSID(0, "$NetBSD: netbsd32_mac
 #include <aarch64/userret.h>
 
 const char machine32[] = MACHINE;
-#ifdef __AARCH64EB__
-const char machine_arch32[] = "earmv7hfeb";
-#else
-const char machine_arch32[] = "earmv7hf";
-#endif
+const char machine_arch32[] = MACHINE32_ARCH;
 
 void
 netbsd32_setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)

Index: src/sys/arch/aarch64/aarch64/trap.c
diff -u src/sys/arch/aarch64/aarch64/trap.c:1.20 src/sys/arch/aarch64/aarch64/trap.c:1.21
--- src/sys/arch/aarch64/aarch64/trap.c:1.20	Thu Nov 21 19:23:58 2019
+++ src/sys/arch/aarch64/aarch64/trap.c	Sun Nov 24 04:08:36 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.20 2019/11/21 19:23:58 ad Exp $ */
+/* $NetBSD: trap.c,v 1.21 2019/11/24 04:08:36 rin Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.20 2019/11/21 19:23:58 ad Exp $");
+__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.21 2019/11/24 04:08:36 rin Exp $");
 
 #include "opt_arm_intr_impl.h"
 #include "opt_compat_netbsd32.h"
@@ -321,6 +321,103 @@ interrupt(struct trapframe *tf)
 	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;
+
+		hi = *pc;
+		if (!THUMB_32BIT(hi)) {
+			/* 16-bit Thumb instruction */
+			*insn = hi;
+			return 2;
+		}
+
+		/*
+		 * 32-bit Thumb instruction:
+		 * We can safely retrieve the lower-half word without
+		 * consideration of a page fault; If present, it must
+		 * have occurred already in the decode stage.
+		 */
+		lo = *(pc + 1);
+
+		*insn = ((uint32_t)hi << 16) | lo;
+		return 4;
+	}
+
+	*insn = *(uint32_t *)tf->tf_pc;
+	return 4;
+}
+
+static int
+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;
+	}
+
+	/* unknown, or unsupported instruction */
+	return 1;
+
+ emulated:
+	tf->tf_pc += insn_size;
+	return 0;
+}
+#endif /* COMPAT_NETBSD32 */
+
 void
 trap_el0_32sync(struct trapframe *tf)
 {
@@ -371,11 +468,18 @@ trap_el0_32sync(struct trapframe *tf)
 		userret(l);
 		break;
 
+	case ESR_EC_UNKNOWN:
+		if (emul_arm_insn(tf))
+			goto unknown;
+		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

Index: src/sys/arch/aarch64/include/netbsd32_machdep.h
diff -u src/sys/arch/aarch64/include/netbsd32_machdep.h:1.2 src/sys/arch/aarch64/include/netbsd32_machdep.h:1.3
--- src/sys/arch/aarch64/include/netbsd32_machdep.h:1.2	Fri Oct 12 01:28:58 2018
+++ src/sys/arch/aarch64/include/netbsd32_machdep.h	Sun Nov 24 04:08:36 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_machdep.h,v 1.2 2018/10/12 01:28:58 ryo Exp $	*/
+/*	$NetBSD: netbsd32_machdep.h,v 1.3 2019/11/24 04:08:36 rin Exp $	*/
 
 #ifndef _MACHINE_NETBSD32_H_
 #define _MACHINE_NETBSD32_H_
@@ -107,4 +107,7 @@ struct netbsd32_arm_sync_icache_args {
 	netbsd32_size_t len;		/* Region size */
 };
 
+/* Support varying ABI names for netbsd32 */
+#define PROC_MACHINE_ARCH32(P)	((P)->p_md.md_march32)
+
 #endif /* _MACHINE_NETBSD32_H_ */

Index: src/sys/arch/aarch64/include/param.h
diff -u src/sys/arch/aarch64/include/param.h:1.12 src/sys/arch/aarch64/include/param.h:1.13
--- src/sys/arch/aarch64/include/param.h:1.12	Sat Oct 19 18:04:26 2019
+++ src/sys/arch/aarch64/include/param.h	Sun Nov 24 04:08:36 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: param.h,v 1.12 2019/10/19 18:04:26 jmcneill Exp $ */
+/* $NetBSD: param.h,v 1.13 2019/11/24 04:08:36 rin Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -59,9 +59,13 @@
 #  ifdef __AARCH64EB__
 #   define	_MACHINE_ARCH	aarch64eb
 #   define	MACHINE_ARCH	"aarch64eb"
+#   define	_MACHINE32_ARCH	earmv7hfeb
+#   define	MACHINE32_ARCH	"earmv7hfeb"
 #  else
 #   define	_MACHINE_ARCH	aarch64
 #   define	MACHINE_ARCH	"aarch64"
+#   define	_MACHINE32_ARCH	earmv7hf
+#   define	MACHINE32_ARCH	"earmv7hf"
 #  endif /* __AARCH64EB__ */
 # endif /* MACHINE_ARCH */
 #else
@@ -69,14 +73,20 @@
 # undef MACHINE
 # undef _MACHINE_ARCH
 # undef MACHINE_ARCH
+# undef _MACHINE32_ARCH
+# undef MACHINE32_ARCH
 # define	_MACHINE	aarch64
 # define	MACHINE		"aarch64"
 # ifdef __AARCH64EB__
 #  define	_MACHINE_ARCH	aarch64eb
 #  define	MACHINE_ARCH	"aarch64eb"
+#  define	_MACHINE32_ARCH	earmv7hfeb
+#  define	MACHINE32_ARCH	"earmv7hfeb"
 # else
 #  define	_MACHINE_ARCH	aarch64
 #  define	MACHINE_ARCH	"aarch64"
+#  define	_MACHINE32_ARCH	earmv7hf
+#  define	MACHINE32_ARCH	"earmv7hf"
 # endif /* __AARCH64EB__ */
 #endif /* !_KERNEL */
 

Index: src/sys/arch/aarch64/include/proc.h
diff -u src/sys/arch/aarch64/include/proc.h:1.3 src/sys/arch/aarch64/include/proc.h:1.4
--- src/sys/arch/aarch64/include/proc.h:1.3	Thu Dec 27 09:55:27 2018
+++ src/sys/arch/aarch64/include/proc.h	Sun Nov 24 04:08:36 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: proc.h,v 1.3 2018/12/27 09:55:27 mrg Exp $ */
+/* $NetBSD: proc.h,v 1.4 2019/11/24 04:08:36 rin Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -34,6 +34,10 @@
 
 #ifdef __aarch64__
 
+#ifdef _KERNEL_OPT
+#include "opt_compat_netbsd32.h"
+#endif
+
 struct mdlwp {
 	void *md_onfault;
 	struct trapframe *md_utf;
@@ -43,8 +47,15 @@ struct mdlwp {
 
 struct mdproc {
 	void (*md_syscall)(struct trapframe *);
+#ifdef COMPAT_NETBSD32
+	char md_march32[12];	/* machine arch of executable */
+#endif
 };
 
+#ifdef COMPAT_NETBSD32
+#define PROC0_MD_INITIALIZERS	.p_md = { .md_march32 = MACHINE32_ARCH },
+#endif
+
 #elif defined(__arm__)
 
 #include <arm/proc.h>

Reply via email to