Subject: Re: Fwd: Current kernel I modified works fine on SS-20/HyperSPARC
To: None <fair@clock.org, port-sparc@netbsd.org>
From: Chris Torek <torek@BSDI.COM>
List: port-sparc
Date: 06/14/1999 07:34:36
Cleaning out some old mail...
>> HyperSPARC's MMU does not peek a modification of PTE.
I believe this is more generally true (i.e., it applies to other
Mbus-based sparcs as well). There are all kinds of interesting
potential races between on-chip store buffers and MMU updates of
ref/mod bits. (Note, losing or gaining a bogus ref bit is not
fatal, and gaining a bogus mod bit is not fatal, but losing a mod
bit could be fatal.) The code I use is this:
/*
* Update a valid PTE using the SWAP instruction, per SuperSPARC/MXCC
* manual, in such a way as to avoid losing R/M bits even if the CPU does
* a table walk while we are looking at the PTE. This seems like overkill
* on a uniprocessor, but following the manual is rarely a bad idea...
*
* Return the previous PTE.
*
* Note that this is not (yet) multiprocessor-ready.
*/
static int
updatepte(va, apte, bis, bic)
vm_offset_t va;
int *apte, bis, bic;
{
int oldval, swapval;
volatile int *vpte = (volatile int *)apte;
/* MP: lock out other cpus here */
#ifdef notdef
__asm__ __volatile__("stbar"); /* ??? */
#endif
/*
* Replace PTE with zero until the zero stays -- any change
* should occur only if the MMU updates a ref or mod bit. By
* using a SWAP instruction, the write will be atomic even in
* the presence of MP-caches and store buffers.
*/
oldval = 0;
do {
swapval = 0;
swap(swapval, vpte);
tlbflushpg4m(va);
oldval |= swapval;
} while (*vpte != 0);
/*
* Now that the PTE is 0, write a new value atomically. Use
* SWAP again to avoid having to drain the store buffer.
*/
swapval = (oldval & ~bic) | bis;
swap(swapval, vpte);
/* MP: unlock */
return (oldval);
}
Chris