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.
This commit is contained in:
parent
3818c9a287
commit
bd65e18f86
|
@ -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 *, vaddr_t, vaddr_t, int, int);
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
int opsr, octx;
|
||||
|
||||
/* 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));
|
||||
/*
|
||||
* 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");
|
||||
|
||||
/* Restore context */
|
||||
__asm("sta %%o5, [%%o4]%0" :: "n"(ASI_SRMMU));
|
||||
octx = getcontext4m(); /* save context */
|
||||
|
||||
/* and turn traps on again */
|
||||
__asm("wr %o3, 0, %psr");
|
||||
__asm("nop");
|
||||
__asm("nop");
|
||||
__asm("nop");
|
||||
/* 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
|
||||
|
|
Loading…
Reference in New Issue