Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/powerpc Add routines to fix unaligned memory access...



details:   https://anonhg.NetBSD.org/src/rev/8329a5442747
branches:  trunk
changeset: 366546:8329a5442747
user:      rin <rin%NetBSD.org@localhost>
date:      Mon May 30 13:58:51 2022 +0000

description:
Add routines to fix unaligned memory access for userland process.

Mainly intended for 403, which cannot handle unaligned memory access
at all (not only ones across page boundaries like 601).

For more details, see comments in fix_unaligned.c.

diffstat:

 sys/arch/powerpc/include/instr.h         |   20 +-
 sys/arch/powerpc/powerpc/fix_unaligned.c |  520 +++++++++++++++++++++++++++++++
 2 files changed, 539 insertions(+), 1 deletions(-)

diffs (truncated from 558 to 300 lines):

diff -r 4744c490526a -r 8329a5442747 sys/arch/powerpc/include/instr.h
--- a/sys/arch/powerpc/include/instr.h  Mon May 30 09:56:02 2022 +0000
+++ b/sys/arch/powerpc/include/instr.h  Mon May 30 13:58:51 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: instr.h,v 1.10 2022/05/29 11:55:05 rin Exp $ */
+/*     $NetBSD: instr.h,v 1.11 2022/05/30 13:58:51 rin Exp $ */
 
 /*
  * Copyright (c) 1992, 1993
@@ -318,6 +318,24 @@
 #define OPC31_OR       0x1bc
 
 /*
+ * Opcode 31 sub-types (load/store multiple bytes)
+ */
+#define        OPC31_LWZX      0x017
+#define        OPC31_LWZUX     0x037
+#define        OPC31_STWX      0x097
+#define        OPC31_STWUX     0x0b7
+#define        OPC31_LHZX      0x117
+#define        OPC31_LHZUX     0x137
+#define        OPC31_LHAX      0x157
+#define        OPC31_LHAUX     0x177
+#define        OPC31_STHX      0x197
+#define        OPC31_STHUX     0x1b7
+#define        OPC31_LWBRX     0x216
+#define        OPC31_STWBRX    0x296
+#define        OPC31_LHBRX     0x316
+#define        OPC31_STHBRX    0x396
+
+/*
  * Opcode 59 sub-types:
  */
 
diff -r 4744c490526a -r 8329a5442747 sys/arch/powerpc/powerpc/fix_unaligned.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/powerpc/powerpc/fix_unaligned.c  Mon May 30 13:58:51 2022 +0000
@@ -0,0 +1,520 @@
+/*     $NetBSD: fix_unaligned.c,v 1.1 2022/05/30 13:58:51 rin Exp $    */
+
+/*
+ * Copyright (c) 2022 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Rin Okuyama.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Routines to fix unaligned memory access for userland process.
+ *
+ * Intended mainly for PPC_IBM403 at the moment:
+ *
+ * - Fetch and decode insn; 403 does not have DSISR.
+ *
+ * - Only for integer insn; unaligned floating-point load/store are taken
+ *   care of by FPU emulator. (Support for FPU insn should be trivial.)
+ *
+ * Also note:
+ *
+ * - For invalid forms, behaviors are undefined and not documented in
+ *   processor manuals. Here, we mimic what described in
+ *   "AIX 7.2 Assembler language reference":
+ *
+ *   - For "u" variants, ra is not updated if ra == 0 (or rd for load).
+ *
+ *   - Fix for {l,st}mw is disabled by default.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: fix_unaligned.c,v 1.1 2022/05/30 13:58:51 rin Exp $");
+
+#include "opt_ddb.h"
+#include "opt_ppcarch.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/evcnt.h>
+#include <sys/siginfo.h>
+#include <sys/systm.h>
+
+#include <powerpc/frame.h>
+#include <powerpc/instr.h>
+#include <powerpc/trap.h>
+
+#define        UA_EVCNT_ATTACH(name)                                           \
+    static struct evcnt unaligned_ev_##name =                          \
+       EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "unaligned", #name);   \
+       EVCNT_ATTACH_STATIC(unaligned_ev_##name)
+
+#define        UA_EVCNT_INCR(name)     unaligned_ev_##name.ev_count++
+
+UA_EVCNT_ATTACH(lwz);
+UA_EVCNT_ATTACH(lwzu);
+UA_EVCNT_ATTACH(stw);
+UA_EVCNT_ATTACH(stwu);
+UA_EVCNT_ATTACH(lhz);
+UA_EVCNT_ATTACH(lhzu);
+UA_EVCNT_ATTACH(lha);
+UA_EVCNT_ATTACH(lhau);
+UA_EVCNT_ATTACH(sth);
+UA_EVCNT_ATTACH(sthu);
+
+UA_EVCNT_ATTACH(lwzx);
+UA_EVCNT_ATTACH(lwzux);
+UA_EVCNT_ATTACH(stwx);
+UA_EVCNT_ATTACH(stwux);
+UA_EVCNT_ATTACH(lhzx);
+UA_EVCNT_ATTACH(lhzux);
+UA_EVCNT_ATTACH(lhax);
+UA_EVCNT_ATTACH(lhaux);
+UA_EVCNT_ATTACH(sthx);
+UA_EVCNT_ATTACH(sthux);
+UA_EVCNT_ATTACH(lwbrx);
+UA_EVCNT_ATTACH(stwbrx);
+UA_EVCNT_ATTACH(lhbrx);
+UA_EVCNT_ATTACH(sthbrx);
+
+UA_EVCNT_ATTACH(lmw);
+UA_EVCNT_ATTACH(stmw);
+
+UA_EVCNT_ATTACH(isi);
+UA_EVCNT_ATTACH(dsi);
+UA_EVCNT_ATTACH(unknown);
+UA_EVCNT_ATTACH(invalid);
+
+#if 0
+#define        UNALIGNED_DEBUG 1
+#define        FIX_UNALIGNED_LSTMW 1
+#endif
+
+#if defined(UNALIGNED_DEBUG)
+int unaligned_debug = 1;
+#elif defined(DEBUG)
+int unaligned_debug = 0;
+#endif
+
+#if defined(UNALIGNED_DEBUG) || defined(DEBUG)
+#define DPRINTF(fmt, args...)                                          \
+    do {                                                               \
+       if (unaligned_debug)                                            \
+               printf("%s: " fmt, __func__, ##args);                   \
+    } while (0)
+#else
+#define        DPRINTF(fmt, args...)   __nothing
+#endif
+
+#if defined(DDB) && (defined(UNALIGNED_DEBUG) || defined(DEBUG))
+extern vaddr_t opc_disasm(vaddr_t, int);
+#define        DISASM(tf, insn)                                                \
+    do {                                                               \
+       if (unaligned_debug)                                            \
+               opc_disasm((tf)->tf_srr0, (insn)->i_int);               \
+    } while (0)
+#else
+#define        DISASM(tf, insn)        __nothing
+#endif
+
+static bool emul_unaligned(struct trapframe *, ksiginfo_t *,
+    const union instr *);
+static bool do_lst(struct trapframe *, const union instr *, int);
+#ifdef FIX_UNALIGNED_LSTMW
+static bool do_lstmw(struct trapframe *, const union instr *, int);
+#endif
+
+bool
+fix_unaligned(struct trapframe *tf, ksiginfo_t *ksi)
+{
+       union instr insn;
+       int ret;
+
+       KSI_INIT_TRAP(ksi);
+
+       ret = ufetch_32((uint32_t *)tf->tf_srr0, (uint32_t *)&insn.i_int);
+       if (ret) {
+               UA_EVCNT_INCR(isi);
+               DPRINTF("EXC_ISI: ret: %d, srr0: 0x%08lx dear: 0x%08lx\n",
+                   ret, tf->tf_srr0, tf->tf_dear);
+               ksi->ksi_signo = SIGSEGV;
+               ksi->ksi_trap = EXC_ISI;
+               ksi->ksi_code = SEGV_MAPERR;
+               ksi->ksi_addr = (void *)tf->tf_srr0;
+               return true;
+       }
+
+       if (emul_unaligned(tf, ksi, &insn))
+               return true;
+
+       CTASSERT(sizeof(insn) == 4);    /* It was broken before... */
+       tf->tf_srr0 += sizeof(insn);
+       return false;
+}
+
+#define        UAF_STORE       0
+#define        UAF_LOAD        __BIT(0)
+#define        UAF_HALF        __BIT(1)
+#define        UAF_ALGEBRA     __BIT(2)
+#define        UAF_REVERSE     __BIT(3)
+#define        UAF_UPDATE      __BIT(4)
+
+static bool
+emul_unaligned(struct trapframe *tf, ksiginfo_t *ksi, const union instr *insn)
+{
+       int flags;
+
+       switch (insn->i_any.i_opcd) {
+       case OPC_LMW:
+               UA_EVCNT_INCR(lmw);
+#ifdef FIX_UNALIGNED_LSTMW
+               flags = UAF_LOAD;
+               if (do_lstmw(tf, insn, flags))
+                       goto fault;
+               return false;
+#else
+               goto unknown;
+#endif
+
+       case OPC_STMW:
+               UA_EVCNT_INCR(stmw);
+#ifdef FIX_UNALIGNED_LSTMW
+               flags = UAF_STORE;
+               if (do_lstmw(tf, insn, flags))
+                       goto fault;
+               return false;
+#else
+               goto unknown;
+#endif
+
+       case OPC_integer_31:
+               switch (insn->i_x.i_xo) {
+               case OPC31_LWZX:
+                       UA_EVCNT_INCR(lwzx);
+                       flags = UAF_LOAD;
+                       break;
+
+               case OPC31_LWZUX:
+                       UA_EVCNT_INCR(lwzux);
+                       flags = UAF_LOAD | UAF_UPDATE;
+                       break;
+
+               case OPC31_STWX:
+                       UA_EVCNT_INCR(stwx);
+                       flags = UAF_STORE;
+                       break;
+
+               case OPC31_STWUX:
+                       UA_EVCNT_INCR(stwux);
+                       flags = UAF_STORE | UAF_UPDATE;
+                       break;
+
+               case OPC31_LHZX:
+                       UA_EVCNT_INCR(lhzx);
+                       flags = UAF_LOAD | UAF_HALF;
+                       break;
+
+               case OPC31_LHZUX:
+                       UA_EVCNT_INCR(lhzux);
+                       flags = UAF_LOAD | UAF_HALF | UAF_UPDATE;
+                       break;
+
+               case OPC31_LHAX:
+                       UA_EVCNT_INCR(lhax);
+                       flags = UAF_LOAD | UAF_HALF | UAF_ALGEBRA;
+                       break;
+                       
+               case OPC31_LHAUX:
+                       UA_EVCNT_INCR(lhaux);
+                       flags = UAF_LOAD | UAF_HALF | UAF_ALGEBRA | UAF_UPDATE;
+                       break;
+
+               case OPC31_STHX:
+                       UA_EVCNT_INCR(sthx);
+                       flags = UAF_STORE | UAF_HALF;
+                       break;
+
+               case OPC31_STHUX:
+                       UA_EVCNT_INCR(sthux);
+                       flags = UAF_STORE | UAF_HALF | UAF_UPDATE;
+                       break;



Home | Main Index | Thread Index | Old Index