--- linux-2.4.3-ac3/arch/i386/kernel/setup.c Wed Apr 4 16:30:35 2001 +++ linux/arch/i386/kernel/setup.c Wed Apr 4 16:34:03 2001 @@ -447,8 +447,8 @@ /* * Sanitize the BIOS e820 map. * - * Some e820 responses include overlapping entries. The following - * replaces the original e820 map with a new one, removing overlaps. + * Some e820 responses include overlapping memory regions. If overlaps are + * found, we'll replace the original e820 map with a new one (w/o overlaps). * */ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) @@ -464,14 +464,14 @@ struct change_member *change_tmp; unsigned long current_type, last_type; unsigned long long last_addr; + int overlap_entries, overlaps_found; int chgidx, still_changing; - int overlap_entries; int new_bios_entry; int old_nr, new_nr; int i; /* - Visually we're performing the following (1,2,3,4 = memory types)... + Visually, we're performing the following (1,2,3,4 = mem types): Sample memory map (w/overlaps): ____22__________________ @@ -517,7 +517,7 @@ if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) return -1; - /* create pointers for initial change-point information (for sorting) */ + /* create pointers for initial change-point info (used for sorting) */ for (i=0; i < 2*old_nr; i++) change_point[i] = &change_point_list[i]; @@ -535,13 +535,15 @@ while (still_changing) { still_changing = 0; for (i=1; i < 2*old_nr; i++) { - /* if > , swap */ - /* or, if current= & last=, swap */ - if ((change_point[i]->addr < change_point[i-1]->addr) || - ((change_point[i]->addr == change_point[i-1]->addr) && - (change_point[i]->addr == change_point[i]->pbios->addr) && - (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) - ) + /* if < , swap */ + /* or, if curr= & last=, swap */ + if ((change_point[i]->addraddr) || + ((change_point[i]->addr == + change_point[i-1]->addr) && + (change_point[i]->addr == + change_point[i]->pbios->addr) && + (change_point[i-1]->addr != + change_point[i-1]->pbios->addr))) { change_tmp = change_point[i]; change_point[i] = change_point[i-1]; @@ -552,47 +554,72 @@ } /* create a new bios memory map, removing overlaps */ - overlap_entries=0; /* number of entries in the overlap table */ - new_bios_entry=0; /* index for creating new bios map entries */ - last_type = 0; /* start with undefined memory type */ - last_addr = 0; /* start with 0 as last starting address */ - /* loop through change-points, determining affect on the new bios map */ + overlaps_found=0; /* indicates whether or not an overlap was found */ + overlap_entries=0; /* number of entries in the overlap table */ + new_bios_entry=0; /* index for creating new bios map entries */ + last_type = 0; /* start with undefined memory type */ + last_addr = 0; /* start with 0 as last starting address */ + /* loop through change-points, determining affect on new bios map */ for (chgidx=0; chgidx < 2*old_nr; chgidx++) { /* keep track of all overlapping bios entries */ - if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) + if (change_point[chgidx]->addr == + change_point[chgidx]->pbios->addr) { - /* add map entry to overlap list (> 1 entry implies an overlap) */ - overlap_list[overlap_entries++]=change_point[chgidx]->pbios; + /* add entry to overlap list (>1 implies overlap) */ + overlap_list[overlap_entries++]= + change_point[chgidx]->pbios; + /* check for legitimately overlapped memory regions */ + if (overlap_entries == 2) + { + /* note: it's possible to have 2 entries w/out + an overlap ([0]=end_addr, [1]=start_addr) */ + if ((overlap_list[0]->addr + + overlap_list[0]->size) != + (overlap_list[1]->addr)) + { + overlaps_found = 1; + } + } + else if (overlap_entries > 1) + { + overlaps_found = 1; + } } else { - /* remove entry from list (order independent, so swap with last) */ + /* remove entry from list (order independent, so swap + with last) */ for (i=0; ipbios) - overlap_list[i] = overlap_list[overlap_entries-1]; + if (overlap_list[i] == + change_point[chgidx]->pbios) + { + overlap_list[i] = + overlap_list[overlap_entries-1]; + } } overlap_entries--; } - /* if there are overlapping entries, decide which "type" to use */ - /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ + /* if overlapping entries, decide which "type" to use */ + /* (larger takes precedence -- 1=usable, 2,3,4,4+=unusable) */ current_type = 0; for (i=0; itype > current_type) current_type = overlap_list[i]->type; - /* continue building up new bios map based on this information */ + /* continue building new bios map based on this information */ if (current_type != last_type) { if (last_type != 0) { new_bios[new_bios_entry].size = change_point[chgidx]->addr - last_addr; - /* move forward only if the new size was non-zero */ + /* move forward if the new size is non-zero */ if (new_bios[new_bios_entry].size != 0) if (++new_bios_entry >= E820MAX) - break; /* no more space left for new bios entries */ + break; /* no more space */ } if (current_type != 0) { - new_bios[new_bios_entry].addr = change_point[chgidx]->addr; + new_bios[new_bios_entry].addr = + change_point[chgidx]->addr; new_bios[new_bios_entry].type = current_type; last_addr=change_point[chgidx]->addr; } @@ -601,9 +628,36 @@ } new_nr = new_bios_entry; /* retain count for new bios entries */ - /* copy new bios mapping into original location */ - memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); - *pnr_map = new_nr; + /* if we found overlaps, replace bios map with an adjusted version */ + if (overlaps_found == 1) + { + printk(KERN_INFO "Overlaps found in BIOS memory map:\n"); + for (i = 0; i < old_nr; i++) { + printk(" BIOS-e820: %016Lx - %016Lx ", biosmap[i].addr, + biosmap[i].addr + biosmap[i].size); + switch (biosmap[i].type) { + case E820_RAM: + printk("(usable)\n"); + break; + case E820_RESERVED: + printk("(reserved)\n"); + break; + case E820_ACPI: + printk("(ACPI data)\n"); + break; + case E820_NVS: + printk("(ACPI NVS)\n"); + break; + default: + printk("type %lu\n", biosmap[i].type); + break; + } + } + printk(KERN_INFO "Compensating...\n"); + /* copy new bios mapping into original location */ + memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); + *pnr_map = new_nr; + } return 0; }