Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/aarch64/aarch64 add support swp,swpb instruction em...



details:   https://anonhg.NetBSD.org/src/rev/0ca5c3cbaaaa
branches:  trunk
changeset: 974186:0ca5c3cbaaaa
user:      ryo <ryo%NetBSD.org@localhost>
date:      Sun Jul 26 07:26:52 2020 +0000

description:
add support swp,swpb instruction emulation

diffstat:

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

diffs (81 lines):

diff -r d9c669137313 -r 0ca5c3cbaaaa sys/arch/aarch64/aarch64/trap.c
--- a/sys/arch/aarch64/aarch64/trap.c   Sun Jul 26 07:25:38 2020 +0000
+++ b/sys/arch/aarch64/aarch64/trap.c   Sun Jul 26 07:26:52 2020 +0000
@@ -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 @@
        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 @@
        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.



Home | Main Index | Thread Index | Old Index