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.