- 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
This commit is contained in:
John Baldwin 2009-09-22 16:51:00 +00:00
parent fd3c9374ff
commit 07ee969179
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=197410
2 changed files with 107 additions and 39 deletions

View File

@ -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

View File

@ -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);
}