From 99696c414ac1011a59aa4aeb03976c45b1d70856 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 5 Dec 2020 16:57:12 +0100 Subject: [PATCH] pc, pc64: exclude memory regions with unusual MTRR cache attributes Use the MTRR registers to exclude memory ranges that do not have the expected cache attributes: RAM -> writeback UMB -> uncached UPA -> uncached --- sys/src/9/pc/fns.h | 1 + sys/src/9/pc/memory.c | 36 ++++++++++++++++++++++++++++++++++++ sys/src/9/pc/mtrr.c | 10 ++++++++++ sys/src/9/pc64/fns.h | 1 + 4 files changed, 48 insertions(+) diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h index a16c0cf74..36ac1911b 100644 --- a/sys/src/9/pc/fns.h +++ b/sys/src/9/pc/fns.h @@ -101,6 +101,7 @@ void mfence(void); void mmuinit(void); ulong* mmuwalk(ulong*, ulong, int, int); char* mtrr(uvlong, uvlong, char *); +char* mtrrattr(uvlong, uvlong *); void mtrrclock(void); int mtrrprint(char *, long); void mtrrsync(void); diff --git a/sys/src/9/pc/memory.c b/sys/src/9/pc/memory.c index e5eefd17b..6df499728 100644 --- a/sys/src/9/pc/memory.c +++ b/sys/src/9/pc/memory.c @@ -320,6 +320,27 @@ umbexclude(void) } } +static void +mtrrexclude(int type, char *expect) +{ + uvlong base, top, next, pa; + char *attr; + + for(base = memmapnext(-1, type); base != -1; base = memmapnext(base, type)){ + top = base + memmapsize(base, 0); + for(pa = base; pa < top; pa = next){ + next = top; + attr = mtrrattr(pa, &next); + if(attr != nil && strcmp(attr, expect) != 0){ + if(next > top) + next = top; + memmapadd(pa, next - pa, MemReserved); + } + base = pa; + } + } +} + static int e820scan(void) { @@ -362,6 +383,9 @@ e820scan(void) } } + /* RAM needs to be writeback */ + mtrrexclude(MemRAM, "wb"); + for(base = memmapnext(-1, MemRAM); base != -1; base = memmapnext(base, MemRAM)){ size = memmapsize(base, BY2PG) & ~(BY2PG-1); if(size != 0) @@ -376,6 +400,7 @@ ramscan(uintptr pa, uintptr top, uintptr chunk) { ulong save, pat, seed, *v, *k0; int i, n, w; + char *attr; pa += chunk-1; pa &= ~(chunk-1); @@ -389,6 +414,10 @@ ramscan(uintptr pa, uintptr top, uintptr chunk) pat = 0x12345678UL; for(; pa < top; pa += chunk){ + attr = mtrrattr(pa, nil); + if(attr != nil && strcmp(attr, "wb") != 0) + goto Skip; + /* write pattern */ seed = pat; if((v = vmap(pa, chunk)) == nil) @@ -420,6 +449,7 @@ ramscan(uintptr pa, uintptr top, uintptr chunk) Bad: vunmap(v, chunk); + Skip: if(pa+chunk <= 16*MB) memmapadd(pa, chunk, MemUMB); @@ -488,6 +518,12 @@ meminit0(void) */ if(e820scan() < 0) ramscan(MemMin, -((uintptr)MemMin), 4*MB); + + /* + * Exclude UMB's and UPA's with unusual cache attributes. + */ + mtrrexclude(MemUMB, "uc"); + mtrrexclude(MemUPA, "uc"); } /* diff --git a/sys/src/9/pc/mtrr.c b/sys/src/9/pc/mtrr.c index 03ceea784..3f72e9f64 100644 --- a/sys/src/9/pc/mtrr.c +++ b/sys/src/9/pc/mtrr.c @@ -691,6 +691,16 @@ mtrr(uvlong base, uvlong size, char *tstr) return nil; } +char* +mtrrattr(uvlong pa, uvlong *pnext) +{ + if(cpu0state.mask == 0) + return nil; + if(pnext != nil) + *pnext = getnext(&cpu0state, pa, nil); + return type2str(gettype(&cpu0state, pa, nil)); +} + int mtrrprint(char *buf, long bufsize) { diff --git a/sys/src/9/pc64/fns.h b/sys/src/9/pc64/fns.h index 5afd1c0b1..ad5315b5e 100644 --- a/sys/src/9/pc64/fns.h +++ b/sys/src/9/pc64/fns.h @@ -99,6 +99,7 @@ void mfence(void); void mmuinit(void); uintptr *mmuwalk(uintptr*, uintptr, int, int); char* mtrr(uvlong, uvlong, char *); +char* mtrrattr(uvlong, uvlong *); void mtrrclock(void); int mtrrprint(char *, long); void mtrrsync(void);