Hi,
As it was recently discovered some newer machines have 40 bit
physical address size which means that the math that is good
for 36 bit paddr just doesn't cut it anymore. In fact the
memory region lengths we program into the MSRs are completely
off.
The following diff has some code ported from FreeBSD to address
this and other concerns. It substantiates a comment about TLB
invalidation by doing an actual TLB flush before we enable the
MTRR and also fixes an incorrect behavior and a race spotted by
Theo when we're setting MSR_MTRRdefType to be the same as in
boot CPU.
Please give this diff a spin as it might solve some weird problems
in X as well as fixing the speed problem for me which we believe is
caused by screwing up the uncacheable PCI device memory mappings.
diff --git arch/amd64/amd64/amd64_mem.c arch/amd64/amd64/amd64_mem.c
index 7cfe40a..c6d2e82 100644
--- arch/amd64/amd64/amd64_mem.c
+++ arch/amd64/amd64/amd64_mem.c
@@ -291,7 +291,7 @@ amd64_mrstoreone(struct mem_range_softc *sc)
if (cr4save & CR4_PGE)
lcr4(cr4save & ~CR4_PGE);
lcr0((rcr0() & ~CR0_NW) | CR0_CD); /* disable caches (CD = 1, NW = 0) */
- wbinvd(); /* flush caches, TLBs */
+ wbinvd(); /* flush caches */
wrmsr(MSR_MTRRdefType, rdmsr(MSR_MTRRdefType) & ~0x800); /*
disable MTRRs (E = 0) */
/* Set fixed-range MTRRs */
@@ -340,7 +340,7 @@ amd64_mrstoreone(struct mem_range_softc *sc)
/* base/type register */
omsrv = rdmsr(msr);
if (mrd->mr_flags & MDF_ACTIVE) {
- msrv = mrd->mr_base & 0xfffffffffffff000LL;
+ msrv = mrd->mr_base & mtrrmask;
msrv |= amd64_mrt2mtrr(mrd->mr_flags, omsrv);
} else {
msrv = 0;
@@ -349,14 +349,15 @@ amd64_mrstoreone(struct mem_range_softc *sc)
/* mask/active register */
if (mrd->mr_flags & MDF_ACTIVE) {
- msrv = 0x800 | (~(mrd->mr_len - 1) &
0x0000000ffffff000LL);
+ msrv = 0x800 | (~(mrd->mr_len - 1) & mtrrmask);
} else {
msrv = 0;
}
wrmsr(msr + 1, msrv);
}
- wbinvd(); /*
flush caches, TLBs */
- wrmsr(MSR_MTRRdefType, rdmsr(MSR_MTRRdefType) | 0x800); /* restore MTRR
state */
+ wbinvd(); /* flush caches
*/
+ tlbflushg(); /* flush TLB */
+ wrmsr(MSR_MTRRdefType, mtrrdef | 0x800); /* set MTRR
behaviour to match BSP and enable it */
lcr0(rcr0() & ~(CR0_CD | CR0_NW)); /* enable
caches CD = 0 and NW = 0 */
lcr4(cr4save); /* restore cr4
*/
}
@@ -615,7 +616,6 @@ void
amd64_mrinit_cpu(struct mem_range_softc *sc)
{
amd64_mrstoreone(sc); /* set MTRRs to match BSP */
- wrmsr(MSR_MTRRdefType, mtrrdef); /* set MTRR behaviour to match BSP */
}
void