Source-Changes-HG archive

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

[src/netbsd-9]: src/sys/arch/hppa/hppa Pull up following revision(s) (request...



details:   https://anonhg.NetBSD.org/src/rev/dc09027cda75
branches:  netbsd-9
changeset: 366707:dc09027cda75
user:      martin <martin%NetBSD.org@localhost>
date:      Fri Jun 10 16:28:16 2022 +0000

description:
Pull up following revision(s) (requested by skrll in ticket #1466):

        sys/arch/hppa/hppa/trap.c: revision 1.119

Handle 'NA' (non-access) traps for the lpa and probe instructions.  The
change is inspired by OpenBSD with a bunch of my own, mainly stylistic,
changes.

Thanks to Tom Lane for the analysis.

PR/56118: sporadic app crashes in HPPA -current

diffstat:

 sys/arch/hppa/hppa/trap.c |  161 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 157 insertions(+), 4 deletions(-)

diffs (199 lines):

diff -r 3b60bae5208d -r dc09027cda75 sys/arch/hppa/hppa/trap.c
--- a/sys/arch/hppa/hppa/trap.c Mon Jun 06 11:36:16 2022 +0000
+++ b/sys/arch/hppa/hppa/trap.c Fri Jun 10 16:28:16 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: trap.c,v 1.111.4.1 2020/04/25 10:52:56 martin Exp $    */
+/*     $NetBSD: trap.c,v 1.111.4.2 2022/06/10 16:28:16 martin Exp $    */
 
 /*-
  * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
@@ -58,7 +58,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.111.4.1 2020/04/25 10:52:56 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.111.4.2 2022/06/10 16:28:16 martin Exp $");
 
 /* #define INTRDEBUG */
 /* #define TRAPDEBUG */
@@ -480,6 +480,93 @@
 }
 #endif /* DEBUG */
 
+
+#define __PABITS(x, y)         __BITS(31 - (x), 31 - (y))
+#define __PABIT(x)             __BIT(31 - (x))
+
+#define LPA_MASK                                \
+     (                      __PABITS(0, 5)     | \
+                            __PABITS(18, 25))
+#define LPA                                     \
+     (__SHIFTIN(1,          __PABITS(0, 5))    | \
+      __SHIFTIN(0x4d, __PABITS(18, 25)))
+
+
+#define PROBE_ENCS     (0x46 | 0xc6 | 0x47 | 0xc7)
+#define PROBE_PL       __PABITS(14, 15)
+#define PROBE_IMMED    __PABIT(18)
+#define PROBE_RW       __PABIT(25)
+
+#define PROBE_MASK                               \
+    ((                      __PABITS(0, 5)     | \
+                            __PABITS(18, 25)   | \
+                            __PABIT(26))       ^ \
+     (PROBE_IMMED | PROBE_RW))
+
+#define PROBE                                   \
+    ((__SHIFTIN(1,          __PABITS(0, 5))    | \
+      __SHIFTIN(PROBE_ENCS, __PABITS(18, 25))  | \
+      __SHIFTIN(0,          __PABIT(26)))      ^ \
+     (PROBE_IMMED | PROBE_RW))
+
+/* for hppa64 */
+CTASSERT(sizeof(register_t) == sizeof(u_int));
+size_t hppa_regmap[] = {
+       0,      /* r0 is special case */
+       offsetof(struct trapframe, tf_r1  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_rp  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r3  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r4  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r5  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r6  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r7  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r8  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r9  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r10 ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r11 ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r12 ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r13 ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r14 ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r15 ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r16 ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r17 ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r18 ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_t4  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_t3  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_t2  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_t1  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_arg3) / sizeof(register_t),
+       offsetof(struct trapframe, tf_arg2) / sizeof(register_t),
+       offsetof(struct trapframe, tf_arg1) / sizeof(register_t),
+       offsetof(struct trapframe, tf_arg0) / sizeof(register_t),
+       offsetof(struct trapframe, tf_dp  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_ret0) / sizeof(register_t),
+       offsetof(struct trapframe, tf_ret1) / sizeof(register_t),
+       offsetof(struct trapframe, tf_sp  ) / sizeof(register_t),
+       offsetof(struct trapframe, tf_r31 ) / sizeof(register_t),
+};
+
+
+static inline register_t
+tf_getregno(struct trapframe *tf, u_int regno)
+{
+       register_t *tf_reg = (register_t *)tf;
+       if (regno == 0)
+               return 0;
+       else
+               return tf_reg[hppa_regmap[regno]];
+}
+
+static inline void
+tf_setregno(struct trapframe *tf, u_int regno, register_t val)
+{
+       register_t *tf_reg = (register_t *)tf;
+       if (regno == 0)
+               return;
+       else
+               tf_reg[hppa_regmap[regno]] = val;
+}
+
 void
 trap(int type, struct trapframe *frame)
 {
@@ -593,6 +680,7 @@
                mtctl(frame->tf_eiem, CR_EIEM);
        }
 
+       const bool user = (type & T_USER) != 0;
        switch (type) {
        case T_NONEXIST:
        case T_NONEXIST|T_USER:
@@ -817,11 +905,76 @@
                trapsignal(l, &ksi);
                break;
 
+       case T_ITLBMISSNA:      case T_USER | T_ITLBMISSNA:
+       case T_DTLBMISSNA:      case T_USER | T_DTLBMISSNA:
+               vm = p->p_vmspace;
+
+               if (!vm) {
+#ifdef TRAPDEBUG
+                       printf("trap: no vm, p=%p\n", p);
+#endif
+                       goto dead_end;
+               }
+
+               /*
+                * it could be a kernel map for exec_map faults
+                */
+               if (!user && space == HPPA_SID_KERNEL)
+                       map = kernel_map;
+               else {
+                       map = &vm->vm_map;
+               }
+
+               va = trunc_page(va);
+
+               if ((opcode & LPA_MASK) == LPA) {
+                       /* lpa failure case */
+                       const u_int regno =
+                           __SHIFTOUT(opcode, __PABITS(27, 31));
+                       tf_setregno(frame, regno, 0);
+                       frame->tf_ipsw |= PSW_N;
+               } else if ((opcode & PROBE_MASK) == PROBE) {
+                       u_int pl;
+                       if ((opcode & PROBE_IMMED) == 0) {
+                               pl = __SHIFTOUT(opcode, __PABITS(14, 15));
+                       } else {
+                               const u_int plreg =
+                                   __SHIFTOUT(opcode, __PABITS(11, 15));
+                               pl = tf_getregno(frame, plreg);
+                       }
+                       bool ok = true;
+                       if ((user && space == HPPA_SID_KERNEL) ||
+                           (frame->tf_iioq_head & 3) != pl ||
+                           (user && va >= VM_MAXUSER_ADDRESS)) {
+                               ok = false;
+                       } else {
+                               /* Never call uvm_fault in interrupt context. */
+                               KASSERT(curcpu()->ci_intr_depth == 0);
+
+                               const bool read =
+                                   __SHIFTOUT(opcode, PROBE_RW) == 0;
+                               onfault = pcb->pcb_onfault;
+                               pcb->pcb_onfault = 0;
+                               ret = uvm_fault(map, va, read ?
+                                   VM_PROT_READ : VM_PROT_WRITE);
+                               pcb->pcb_onfault = onfault;
+
+                               if (ret)
+                                       ok = false;
+                       }
+                       if (!ok) {
+                               const u_int regno =
+                                   __SHIFTOUT(opcode, __PABITS(27, 31));
+                               tf_setregno(frame, regno, 0);
+                               frame->tf_ipsw |= PSW_N;
+                       }
+               } else {
+               }
+               break;
+
        case T_DATACC:          case T_USER | T_DATACC:
        case T_ITLBMISS:        case T_USER | T_ITLBMISS:
        case T_DTLBMISS:        case T_USER | T_DTLBMISS:
-       case T_ITLBMISSNA:      case T_USER | T_ITLBMISSNA:
-       case T_DTLBMISSNA:      case T_USER | T_DTLBMISSNA:
        case T_TLB_DIRTY:       case T_USER | T_TLB_DIRTY:
                vm = p->p_vmspace;
 



Home | Main Index | Thread Index | Old Index