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