Module Name: src Committed By: ryo Date: Sun Jul 26 07:26:52 UTC 2020
Modified Files: src/sys/arch/aarch64/aarch64: trap.c Log Message: add support swp,swpb instruction emulation To generate a diff of this commit: cvs rdiff -u -r1.32 -r1.33 src/sys/arch/aarch64/aarch64/trap.c 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/trap.c diff -u src/sys/arch/aarch64/aarch64/trap.c:1.32 src/sys/arch/aarch64/aarch64/trap.c:1.33 --- src/sys/arch/aarch64/aarch64/trap.c:1.32 Sun Jul 26 07:25:38 2020 +++ src/sys/arch/aarch64/aarch64/trap.c Sun Jul 26 07:26:52 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: trap.c,v 1.32 2020/07/26 07:25:38 ryo Exp $ */ +/* $NetBSD: trap.c,v 1.33 2020/07/26 07:26:52 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.32 2020/07/26 07:25:38 ryo Exp $"); +__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.33 2020/07/26 07:26:52 ryo Exp $"); #include "opt_arm_intr_impl.h" #include "opt_compat_netbsd32.h" @@ -588,6 +588,46 @@ arm_cond_match(uint32_t insn, uint64_t s return (!match != !invert); } +uint8_t atomic_swap_8(volatile uint8_t *, uint8_t); + +static int +emul_arm_swp(uint32_t insn, struct trapframe *tf) +{ + struct faultbuf fb; + vaddr_t vaddr; + uint32_t val; + int Rn, Rd, Rm, error; + + Rn = __SHIFTOUT(insn, 0x000f0000); + Rd = __SHIFTOUT(insn, 0x0000f000); + Rm = __SHIFTOUT(insn, 0x0000000f); + + vaddr = tf->tf_reg[Rn] & 0xffffffff; + val = tf->tf_reg[Rm]; + + /* fault if insn is swp, and unaligned access */ + if ((insn & 0x00400000) == 0 && (vaddr & 3) != 0) { + tf->tf_far = vaddr; + return EFAULT; + } + + /* vaddr will always point to userspace, since it has only 32bit */ + if ((error = cpu_set_onfault(&fb)) == 0) { + if (insn & 0x00400000) { + /* swpb */ + val = atomic_swap_8(vaddr, val); + } else { + /* swp */ + val = atomic_swap_32(vaddr, val); + } + cpu_unset_onfault(); + tf->tf_reg[Rd] = val; + } else { + tf->tf_far = reg_far_el1_read(); + } + return error; +} + static enum emul_arm_result emul_thumb_insn(struct trapframe *tf, uint32_t insn, int insn_size) { @@ -635,6 +675,15 @@ emul_arm_insn(struct trapframe *tf) if ((insn & 0xf0000000) == 0xf0000000) goto unknown_insn; + /* swp,swpb */ + if ((insn & 0x0fb00ff0) == 0x01000090) { + if (arm_cond_match(insn, tf->tf_spsr)) { + if (emul_arm_swp(insn, tf) != 0) + return EMUL_ARM_FAULT; + } + goto emulated; + } + /* * Emulate ARMv6 instructions with cache operations * register (c7), that can be used in user mode.