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;