Module Name:    src
Committed By:   uwe
Date:           Wed Dec  9 04:02:20 UTC 2020

Modified Files:
        src/sys/arch/sparc/sparc: pmap.c

Log Message:
sp_tlb_flush() - fix inline asm miscompiled by newer gcc versions.

As one national park director once said: "my problems start when the
dumber of my visitors meet the smarter of my bears".

Old inline asm used specific hardcoded registers "assuming that gcc
doesn't do anything funny with these".  Unfortunately now it does,
especially when this function is inlined.  We ended up restoring a
wrong context.  The result was mysterious infinite memory faults.

Rewrite in safer inline asm, so that gcc is not confused.

Many thanks to chs@ for his patience.


To generate a diff of this commit:
cvs rdiff -u -r1.367 -r1.368 src/sys/arch/sparc/sparc/pmap.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/sparc/sparc/pmap.c
diff -u src/sys/arch/sparc/sparc/pmap.c:1.367 src/sys/arch/sparc/sparc/pmap.c:1.368
--- src/sys/arch/sparc/sparc/pmap.c:1.367	Sat Mar 14 14:05:43 2020
+++ src/sys/arch/sparc/sparc/pmap.c	Wed Dec  9 04:02:20 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap.c,v 1.367 2020/03/14 14:05:43 ad Exp $ */
+/*	$NetBSD: pmap.c,v 1.368 2020/12/09 04:02:20 uwe Exp $ */
 
 /*
  * Copyright (c) 1996
@@ -56,7 +56,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.367 2020/03/14 14:05:43 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.368 2020/12/09 04:02:20 uwe Exp $");
 
 #include "opt_ddb.h"
 #include "opt_kgdb.h"
@@ -631,42 +631,39 @@ void 		(*pmap_rmu_p)(struct pmap *, vadd
 /*
  * SP versions of the tlb flush operations.
  *
- * Turn off traps to prevent register window overflows
- * from writing user windows to the wrong stack.
+ * Turn off traps to prevent register window overflows from writing
+ * user windows to the wrong stack.  Cf. tlb_flush_page_real() &c.
  */
 static void
 sp_tlb_flush(int va, int ctx, int lvl)
 {
-	/*
-	 * XXX convert %o3 (oldpsr), %o4 (SRMMU_CXR) and %o5 (old context)
-	 * into generically named registers.  right now we're assuming that
-	 * gcc doesn't do anything funny with these registers.
-	 */
-
-	/* Traps off */
-	__asm("rd	%psr, %o3");
-	__asm("wr	%%o3, %0, %%psr" :: "n" (PSR_ET));
+	int opsr, octx;
 
-	/* Save context */
-	__asm("mov	%0, %%o4" :: "n"(SRMMU_CXR));
-	__asm("lda	[%%o4]%0, %%o5" :: "n"(ASI_SRMMU));
-
-	/* Set new context and flush type bits */
 	va &= ~0xfff;
-	__asm("sta	%1, [%%o4]%0" :: "n"(ASI_SRMMU), "r"(ctx));
 	va |= lvl;
 
-	/* Do the TLB flush */
-	__asm("sta	%%g0, [%1]%0" :: "n"(ASI_SRMMUFP), "r"(va));
+	/*
+	 * Turn off traps.
+	 *
+	 * Like setpsr((opsr = getpsr()) & ~PSR_ET); but we can shave
+	 * off one instruction b/c we never disable traps recursively,
+	 * so we can use the xor done by wrpsr itself to clear the
+	 * bit.
+	 *
+	 * XXX: Add to asm.h?  We can use this in cache.c too.
+	 */
+	opsr = getpsr();	/* KDASSERT(opsr & PSR_ET); */
+	__asm volatile ("wr %0, %1, %%psr" :: "r"(opsr), "n"(PSR_ET));
+	__asm volatile ("nop; nop;nop");
+
+	octx = getcontext4m();	/* save context */
 
-	/* Restore context */
-	__asm("sta	%%o5, [%%o4]%0" :: "n"(ASI_SRMMU));
+	/* Do the TLB flush in "ctx" */
+	setcontext4m(ctx);
+	__asm volatile("sta %%g0, [%0]%1" :: "r"(va), "n"(ASI_SRMMUFP));
 
-	/* and turn traps on again */
-	__asm("wr	%o3, 0, %psr");
-	__asm("nop");
-	__asm("nop");
-	__asm("nop");
+	setcontext4m(octx);	/* restore context */
+	setpsr(opsr);		/* turn traps on again */
 }
 
 static inline void

Reply via email to