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
This commit is contained in:
rin 2019-11-24 04:08:36 +00:00
parent 8add6aa962
commit 197cf882e7
6 changed files with 145 additions and 14 deletions

View File

@ -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, struct exec_package *epp, void *eh0,
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

View File

@ -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 <ryo@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_machdep.c,v 1.8 2019/11/20 19:37:51 pgoyett
#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)

View File

@ -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

View File

@ -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_ */

View File

@ -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 */

View File

@ -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>