summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavem <davem@openbsd.org>1996-01-14 00:39:18 +0000
committerdavem <davem@openbsd.org>1996-01-14 00:39:18 +0000
commit8d71c1d45f236c6efb0f749c2d53ba9433acf66a (patch)
treeeeb341f608833329d9623bf9826ba74ecc73cfb2
parentFix typo (diff)
downloadwireguard-openbsd-8d71c1d45f236c6efb0f749c2d53ba9433acf66a.tar.xz
wireguard-openbsd-8d71c1d45f236c6efb0f749c2d53ba9433acf66a.zip
The sun mmu is very broken, and we all can thank crashme for
helping me find this bug. On execution of an atomic load/store instruction the chip will only say that a read fault is happening, we then load up a readonly translation to the accessed page, and we get the fault again still showing a read-fault. We end up faulting in a loop forever and the process appears to be completely stuck. The algorithm to fix this problem goes like this. If we get a non-text fault, and the fault type is VM_PROT_READ, and the SER_PROT bit is set in the syncronous fault error register, we take a peek at the instruction at pc. If this instruction is indeed an ldstub or a swap variant we or in VM_PROT_WRITE to the fault type.
-rw-r--r--sys/arch/sparc/sparc/trap.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/sys/arch/sparc/sparc/trap.c b/sys/arch/sparc/sparc/trap.c
index 2f6103499da..2925b0adea2 100644
--- a/sys/arch/sparc/sparc/trap.c
+++ b/sys/arch/sparc/sparc/trap.c
@@ -598,6 +598,22 @@ mem_access_fault(type, ser, v, pc, psr, tf)
if (VA_INHOLE(v))
goto fault;
ftype = ser & SER_WRITE ? VM_PROT_READ|VM_PROT_WRITE : VM_PROT_READ;
+ if(ftype == VM_PROT_READ && (ser & SER_PROT) && type != T_TEXTFAULT) {
+ /* If this is an ldstub or swap instruction
+ * then we are about to fault in a loop forever
+ * as only the read part of the fault will be
+ * reported by the mmu.
+ */
+ int error, insn;
+
+ error = copyin((caddr_t) pc, &insn, sizeof(int));
+ if(!error) {
+ insn = (insn >> 16); /* high word */
+ insn &= 0xc168;
+ if(insn == 0xc068)
+ ftype |= VM_PROT_WRITE;
+ }
+ }
va = trunc_page(v);
if (psr & PSR_PS) {
extern char Lfsbail[];