Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/sparc/sparc sp_tlb_flush() - fix inline asm miscomp...



details:   https://anonhg.NetBSD.org/src/rev/28ca3c6ae76f
branches:  trunk
changeset: 978955:28ca3c6ae76f
user:      uwe <uwe%NetBSD.org@localhost>
date:      Wed Dec 09 04:02:20 2020 +0000

description:
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.

diffstat:

 sys/arch/sparc/sparc/pmap.c |  61 +++++++++++++++++++++-----------------------
 1 files changed, 29 insertions(+), 32 deletions(-)

diffs (88 lines):

diff -r 70e042484659 -r 28ca3c6ae76f sys/arch/sparc/sparc/pmap.c
--- a/sys/arch/sparc/sparc/pmap.c       Wed Dec 09 02:46:57 2020 +0000
+++ b/sys/arch/sparc/sparc/pmap.c       Wed Dec 09 04:02:20 2020 +0000
@@ -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 @@
 /*
  * 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)
 {
+       int opsr, octx;
+
+       va &= ~0xfff;
+       va |= 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.
+        * 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.
         */
-
-       /* Traps off */
-       __asm("rd       %psr, %o3");
-       __asm("wr       %%o3, %0, %%psr" :: "n" (PSR_ET));
-
-       /* 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));
-
-       /* Restore context */
-       __asm("sta      %%o5, [%%o4]%0" :: "n"(ASI_SRMMU));
-
-       /* and turn traps on again */
-       __asm("wr       %o3, 0, %psr");
-       __asm("nop");
-       __asm("nop");
-       __asm("nop");
+       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 */
+
+       /* Do the TLB flush in "ctx" */
+       setcontext4m(ctx);
+       __asm volatile("sta %%g0, [%0]%1" :: "r"(va), "n"(ASI_SRMMUFP));
+
+       setcontext4m(octx);     /* restore context */
+       setpsr(opsr);           /* turn traps on again */
 }
 
 static inline void



Home | Main Index | Thread Index | Old Index