Module Name:    src
Committed By:   skrll
Date:           Thu Jun  9 16:38:23 UTC 2022

Modified Files:
        src/sys/arch/hppa/hppa: pmap.c trap.c

Log Message:
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


To generate a diff of this commit:
cvs rdiff -u -r1.117 -r1.118 src/sys/arch/hppa/hppa/pmap.c
cvs rdiff -u -r1.118 -r1.119 src/sys/arch/hppa/hppa/trap.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/hppa/hppa/pmap.c
diff -u src/sys/arch/hppa/hppa/pmap.c:1.117 src/sys/arch/hppa/hppa/pmap.c:1.118
--- src/sys/arch/hppa/hppa/pmap.c:1.117	Thu May 26 05:34:04 2022
+++ src/sys/arch/hppa/hppa/pmap.c	Thu Jun  9 16:38:23 2022
@@ -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 @@ pmap_remove(pmap_t pmap, vaddr_t sva, va
 		}
 		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_remove(pmap_t pmap, vaddr_t sva, va
 			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 */

Index: src/sys/arch/hppa/hppa/trap.c
diff -u src/sys/arch/hppa/hppa/trap.c:1.118 src/sys/arch/hppa/hppa/trap.c:1.119
--- src/sys/arch/hppa/hppa/trap.c:1.118	Tue Jun  7 06:06:46 2022
+++ src/sys/arch/hppa/hppa/trap.c	Thu Jun  9 16:38:23 2022
@@ -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 @@ out:
 }
 #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 @@ trap(int type, struct trapframe *frame)
 		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 @@ do_onfault:
 		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;
 

Reply via email to