Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/hppa/hppa Handle 'NA' (non-access) traps for the lp...



details:   https://anonhg.NetBSD.org/src/rev/a54a4e5cf682
branches:  trunk
changeset: 366698:a54a4e5cf682
user:      skrll <skrll%NetBSD.org@localhost>
date:      Thu Jun 09 16:38:23 2022 +0000

description:
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/pmap.c |    7 +-
 sys/arch/hppa/hppa/trap.c |  161 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 162 insertions(+), 6 deletions(-)

diffs (234 lines):

diff -r 61e7833f3313 -r a54a4e5cf682 sys/arch/hppa/hppa/pmap.c
--- a/sys/arch/hppa/hppa/pmap.c Thu Jun 09 14:02:30 2022 +0000
+++ b/sys/arch/hppa/hppa/pmap.c Thu Jun 09 16:38:23 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pmap.c,v 1.117 2022/05/26 05:34:04 skrll Exp $ */
+/*     $NetBSD: pmap.c,v 1.118 2022/06/09 16:38:23 skrll Exp $ */
 
 /*-
  * Copyright (c) 2001, 2002, 2020 The NetBSD Foundation, Inc.
@@ -65,7 +65,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.117 2022/05/26 05:34:04 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.118 2022/06/09 16:38:23 skrll Exp $");
 
 #include "opt_cputype.h"
 
@@ -1501,6 +1501,7 @@
                }
                batch = pdemask == sva && sva + PDE_SIZE <= eva;
 
+//XXXNH valid check?
                if ((pte = pmap_pte_get(pde, sva))) {
 
                        /* TODO measure here the speed tradeoff
@@ -1510,6 +1511,8 @@
                        pmap_pte_flush(pmap, sva, pte);
                        if (pte & PTE_PROT(TLB_WIRED))
                                pmap->pm_stats.wired_count--;
+
+//XXXNH move to pmap_pv_remove?
                        pmap->pm_stats.resident_count--;
 
                        /* iff properly accounted pde will be dropped anyway */
diff -r 61e7833f3313 -r a54a4e5cf682 sys/arch/hppa/hppa/trap.c
--- a/sys/arch/hppa/hppa/trap.c Thu Jun 09 14:02:30 2022 +0000
+++ b/sys/arch/hppa/hppa/trap.c Thu Jun 09 16:38:23 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: trap.c,v 1.118 2022/06/07 06:06:46 skrll Exp $ */
+/*     $NetBSD: trap.c,v 1.119 2022/06/09 16:38:23 skrll 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.118 2022/06/07 06:06:46 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.119 2022/06/09 16:38:23 skrll Exp $");
 
 /* #define INTRDEBUG */
 /* #define TRAPDEBUG */
@@ -478,6 +478,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)
 {
@@ -591,6 +678,7 @@
                mtctl(frame->tf_eiem, CR_EIEM);
        }
 
+       const bool user = (type & T_USER) != 0;
        switch (type) {
        case T_NONEXIST:
        case T_NONEXIST | T_USER:
@@ -815,11 +903,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