diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-09-16 23:36:06 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-09-16 23:36:06 +0200 |
commit | c24dd620f91a2ef84b88d2536a469e5358df1b8d (patch) | |
tree | 51000f01d840939cee5f44de460b0a8d91e29ab7 /sys/src/9/pc/memory.c | |
parent | c3a8711d12c4b6c56767fe8ef07d96d6ef2978e9 (diff) |
e820: handle duplicate and overlapping e820 entries, handle overflows
new algorithm:
sort entries by top address first. then for each entry we use:
base = max(base, last)
so we'll never map the same addresses twice.
Diffstat (limited to 'sys/src/9/pc/memory.c')
-rw-r--r-- | sys/src/9/pc/memory.c | 52 |
1 files changed, 32 insertions, 20 deletions
diff --git a/sys/src/9/pc/memory.c b/sys/src/9/pc/memory.c index 28cf44ed0..8f634c107 100644 --- a/sys/src/9/pc/memory.c +++ b/sys/src/9/pc/memory.c @@ -568,7 +568,7 @@ struct Emap { int type; uvlong base; - uvlong len; + uvlong top; }; static Emap emap[128]; int nemap; @@ -580,11 +580,15 @@ emapcmp(const void *va, const void *vb) a = (Emap*)va; b = (Emap*)vb; + if(a->top < b->top) + return -1; + if(a->top > b->top) + return 1; if(a->base < b->base) return -1; if(a->base > b->base) return 1; - return a->len - b->len; + return 0; } static void @@ -592,7 +596,7 @@ map(ulong base, ulong len, int type) { ulong e, n; ulong *table, flags, maxkpa; - + /* * Split any call crossing MemMin to make below simpler. */ @@ -611,7 +615,7 @@ map(ulong base, ulong len, int type) /* * Any non-memory below 16*MB is used as upper mem blocks. */ - if(type == MemUPA && base < 16*MB && base+len > 16*MB){ + if(type == MemUPA && base < 16*MB && len > 16*MB-base){ map(base, 16*MB-base, MemUMB); map(16*MB, len-(16*MB-base), MemUPA); return; @@ -633,7 +637,7 @@ map(ulong base, ulong len, int type) * Memory between KTZERO and end is the kernel itself * and is already mapped. */ - if(base < PADDR(KTZERO) && base+len > PADDR(KTZERO)){ + if(base < PADDR(KTZERO) && len > PADDR(KTZERO)-base){ map(base, PADDR(KTZERO)-base, type); return; } @@ -697,8 +701,7 @@ map(ulong base, ulong len, int type) static int e820scan(void) { - ulong base, len; - uvlong last; + ulong base, len, last; Emap *e; char *s; int i; @@ -707,7 +710,8 @@ e820scan(void) if((s = getconf("*e820")) == nil) if((s = getconf("e820")) == nil) return -1; - for(nemap = 0; nemap < nelem(emap); nemap++){ + nemap = 0; + while(nemap < nelem(emap)){ while(*s == ' ') s++; if(*s == 0) @@ -721,10 +725,11 @@ e820scan(void) e->base = strtoull(s, &s, 16); if(*s != ' ') break; - e->len = strtoull(s, &s, 16); - if(*s != ' ' && *s != 0 || e->len <= e->base) + e->top = strtoull(s, &s, 16); + if(*s != ' ' && *s != 0) break; - e->len -= e->base; + if(e->base < e->top) + nemap++; } if(nemap == 0) return -1; @@ -735,23 +740,30 @@ e820scan(void) /* * pull out the info but only about the low 32 bits... */ - if(e->base >= (1LL<<32)) + if(e->base >= (1ULL<<32)) break; - base = e->base; - if(base+e->len > (1LL<<32)) + if(e->top <= last) + continue; + if(e->base < last) + base = last; + else + base = e->base; + if(e->top > (1ULL<<32)) len = -base; else - len = e->len; + len = e->top - base; /* * If the map skips addresses, mark them available. */ - if(last < e->base) - map(last, e->base-last, MemUPA); - last = base+len; + if(last < base) + map(last, base-last, MemUPA); map(base, len, (e->type == 1) ? MemRAM : MemReserved); + last = base + len; + if(last == 0) + break; } - if(last < (1LL<<32)) - map(last, (u32int)-last, MemUPA); + if(last != 0) + map(last, -last, MemUPA); return 0; } |