diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2020-12-05 16:57:12 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2020-12-05 16:57:12 +0100 |
commit | 99696c414ac1011a59aa4aeb03976c45b1d70856 (patch) | |
tree | 441a03e5e8912aa12fc9aee524a948b102f7f0dc | |
parent | 4ca5e1b3a33d49d0904b39477149517665a78d8a (diff) | |
download | plan9front-99696c414ac1011a59aa4aeb03976c45b1d70856.tar.xz |
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
-rw-r--r-- | sys/src/9/pc/fns.h | 1 | ||||
-rw-r--r-- | sys/src/9/pc/memory.c | 36 | ||||
-rw-r--r-- | sys/src/9/pc/mtrr.c | 10 | ||||
-rw-r--r-- | sys/src/9/pc64/fns.h | 1 |
4 files changed, 48 insertions, 0 deletions
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); |