diff options
author | jhb <jhb@FreeBSD.org> | 2009-09-22 16:51:00 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2009-09-22 16:51:00 +0000 |
commit | 8f447f623d437fb0a267b2b61b337ba0f18ccd64 (patch) | |
tree | a62b0c208bf549d4ad7bf4bbf8e9b4f057cc789a /sys | |
parent | 28435a4f3664401249e27c20b6d9632cd427cef7 (diff) | |
download | FreeBSD-src-8f447f623d437fb0a267b2b61b337ba0f18ccd64.zip FreeBSD-src-8f447f623d437fb0a267b2b61b337ba0f18ccd64.tar.gz |
- Split the logic to parse an SMAP entry out into a separate function on
amd64 similar to i386. This fixes a bug on amd64 where overlapping
entries would not cause the SMAP parsing to stop.
- Change the SMAP parsing code to do a sorted insertion into physmap[]
instead of an append to support systems with out-of-order SMAP entries.
PR: amd64/138220
Reported by: James R. Van Artsdalen james of jrv org
MFC after: 3 days
Diffstat (limited to 'sys')
-rw-r--r-- | sys/amd64/amd64/machdep.c | 106 | ||||
-rw-r--r-- | sys/i386/i386/machdep.c | 40 |
2 files changed, 107 insertions, 39 deletions
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 0bfd7ad..95db5d2 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -1192,6 +1192,77 @@ isa_irq_pending(void) u_int basemem; +static int +add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp) +{ + int i, insert_idx, physmap_idx; + + physmap_idx = *physmap_idxp; + + if (boothowto & RB_VERBOSE) + printf("SMAP type=%02x base=%016lx len=%016lx\n", + smap->type, smap->base, smap->length); + + if (smap->type != SMAP_TYPE_MEMORY) + return (1); + + if (smap->length == 0) + return (0); + + /* + * Find insertion point while checking for overlap. Start off by + * assuming the new entry will be added to the end. + */ + insert_idx = physmap_idx + 2; + for (i = 0; i <= physmap_idx; i += 2) { + if (smap->base < physmap[i + 1]) { + if (smap->base + smap->length <= physmap[i]) { + insert_idx = i; + break; + } + if (boothowto & RB_VERBOSE) + printf( + "Overlapping memory regions, ignoring second region\n"); + return (1); + } + } + + /* See if we can prepend to the next entry. */ + if (insert_idx <= physmap_idx && + smap->base + smap->length == physmap[insert_idx]) { + physmap[insert_idx] = smap->base; + return (1); + } + + /* See if we can append to the previous entry. */ + if (insert_idx > 0 && smap->base == physmap[insert_idx - 1]) { + physmap[insert_idx - 1] += smap->length; + return (1); + } + + physmap_idx += 2; + *physmap_idxp = physmap_idx; + if (physmap_idx == PHYSMAP_SIZE) { + printf( + "Too many segments in the physical address map, giving up\n"); + return (0); + } + + /* + * Move the last 'N' entries down to make room for the new + * entry if needed. + */ + for (i = physmap_idx; i > insert_idx; i -= 2) { + physmap[i] = physmap[i - 2]; + physmap[i + 1] = physmap[i - 1]; + } + + /* Insert the new entry. */ + physmap[insert_idx] = smap->base; + physmap[insert_idx + 1] = smap->base + smap->length; + return (1); +} + /* * Populate the (physmap) array with base/bound pairs describing the * available physical memory in the system, then test this memory and @@ -1235,40 +1306,9 @@ getmemsize(caddr_t kmdp, u_int64_t first) smapsize = *((u_int32_t *)smapbase - 1); smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize); - for (smap = smapbase; smap < smapend; smap++) { - if (boothowto & RB_VERBOSE) - printf("SMAP type=%02x base=%016lx len=%016lx\n", - smap->type, smap->base, smap->length); - - if (smap->type != SMAP_TYPE_MEMORY) - continue; - - if (smap->length == 0) - continue; - - for (i = 0; i <= physmap_idx; i += 2) { - if (smap->base < physmap[i + 1]) { - if (boothowto & RB_VERBOSE) - printf( - "Overlapping or non-monotonic memory region, ignoring second region\n"); - continue; - } - } - - if (smap->base == physmap[physmap_idx + 1]) { - physmap[physmap_idx + 1] += smap->length; - continue; - } - - physmap_idx += 2; - if (physmap_idx == PHYSMAP_SIZE) { - printf( - "Too many segments in the physical address map, giving up\n"); + for (smap = smapbase; smap < smapend; smap++) + if (!add_smap_entry(smap, physmap, &physmap_idx)) break; - } - physmap[physmap_idx] = smap->base; - physmap[physmap_idx + 1] = smap->base + smap->length; - } /* * Find the 'base memory' segment for SMP diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 1a6b3c6..96c8f25 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -1946,7 +1946,7 @@ sdtossd(sd, ssd) static int add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp) { - int i, physmap_idx; + int i, insert_idx, physmap_idx; physmap_idx = *physmap_idxp; @@ -1968,17 +1968,34 @@ add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp) } #endif + /* + * Find insertion point while checking for overlap. Start off by + * assuming the new entry will be added to the end. + */ + insert_idx = physmap_idx + 2; for (i = 0; i <= physmap_idx; i += 2) { if (smap->base < physmap[i + 1]) { + if (smap->base + smap->length <= physmap[i]) { + insert_idx = i; + break; + } if (boothowto & RB_VERBOSE) printf( - "Overlapping or non-monotonic memory region, ignoring second region\n"); + "Overlapping memory regions, ignoring second region\n"); return (1); } } - if (smap->base == physmap[physmap_idx + 1]) { - physmap[physmap_idx + 1] += smap->length; + /* See if we can prepend to the next entry. */ + if (insert_idx <= physmap_idx && + smap->base + smap->length == physmap[insert_idx]) { + physmap[insert_idx] = smap->base; + return (1); + } + + /* See if we can append to the previous entry. */ + if (insert_idx > 0 && smap->base == physmap[insert_idx - 1]) { + physmap[insert_idx - 1] += smap->length; return (1); } @@ -1989,8 +2006,19 @@ add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp) "Too many segments in the physical address map, giving up\n"); return (0); } - physmap[physmap_idx] = smap->base; - physmap[physmap_idx + 1] = smap->base + smap->length; + + /* + * Move the last 'N' entries down to make room for the new + * entry if needed. + */ + for (i = physmap_idx; i > insert_idx; i -= 2) { + physmap[i] = physmap[i - 2]; + physmap[i + 1] = physmap[i - 1]; + } + + /* Insert the new entry. */ + physmap[insert_idx] = smap->base; + physmap[insert_idx + 1] = smap->base + smap->length; return (1); } |