Samuel Thibault, on Fri 12 Aug 2016 19:08:07 +0200, wrote: > What is supposed to exclude everything else? (modules, VGA BIOS, etc.)
I'm tempted to apply the attached patch at least to the Debian package to brown-tape-fix the issue. What it does is: - Make biosmem_load_segment look for the biggest area available inside the segment, instead of assuming that either the segment contains the biosmem heap and only the available part of the heap should be used, or it doesn't contain the heap, and thus the whole segment should be used. - Make biosmem_find_boot_data skip the biosmem heap, as well as the wholes in the biosmem map. Samuel
diff --git a/i386/i386at/biosmem.c b/i386/i386at/biosmem.c index a7a440e..2ca1f61 100644 --- a/i386/i386at/biosmem.c +++ b/i386/i386at/biosmem.c @@ -440,9 +440,34 @@ biosmem_find_boot_data(const struct multiboot_raw_info *mbi, uint32_t min, struct elf_shdr *shdr; uint32_t i, start, end = end; unsigned long tmp; + const struct biosmem_map_entry *entry; start = max; + /* Exclude unmapped areas */ + i = 0; + entry = biosmem_map; + while (entry < biosmem_map + biosmem_map_size) + { + /* Exclude memory before this entry */ + if (i < entry->base_addr) + biosmem_find_boot_data_update(min, &start, &end, i, entry->base_addr); + if (entry->type == BIOSMEM_TYPE_AVAILABLE) + /* Do not exclude this area */ + i = entry->base_addr + entry->length; + else + /* Exclude this area too */ + i = entry->base_addr; + entry++; + } + /* Exclude last entry and anything else beyond */ + if (i < max) + biosmem_find_boot_data_update(min, &start, &end, i, max); + + if (biosmem_heap_cur) + /* Heap is in use */ + biosmem_find_boot_data_update(min, &start, &end, biosmem_heap_cur, biosmem_heap_end); + biosmem_find_boot_data_update(min, &start, &end, _kvtophys(&_start), _kvtophys(&_end)); @@ -738,6 +763,8 @@ biosmem_load_segment(struct biosmem_segment *seg, uint64_t max_phys_end, phys_addr_t avail_start, phys_addr_t avail_end) { unsigned int seg_index; + phys_addr_t start, end, max_start, max_end; + uint32_t next; seg_index = seg - biosmem_segments; @@ -753,6 +780,34 @@ biosmem_load_segment(struct biosmem_segment *seg, uint64_t max_phys_end, phys_end = max_phys_end; } +#ifndef MACH_HYP + max_start = phys_start; + max_end = phys_start; + next = phys_start; + + do { + extern struct multiboot_info boot_info; + + start = next; + end = biosmem_find_boot_data((struct multiboot_raw_info *)&boot_info, start, phys_end, &next); + + if (end == 0) { + end = phys_end; + next = 0; + } + + if ((end - start) > (max_end - max_start)) { + max_start = start; + max_end = end; + } + } while (next != 0); + + max_start = round_page(max_start); + max_end = trunc_page(max_end); + + seg->avail_start = max_start; + seg->avail_end = max_end; +#else if ((avail_start < phys_start) || (avail_start >= phys_end)) avail_start = phys_start; @@ -761,7 +816,9 @@ biosmem_load_segment(struct biosmem_segment *seg, uint64_t max_phys_end, seg->avail_start = avail_start; seg->avail_end = avail_end; - vm_page_load(seg_index, phys_start, phys_end, avail_start, avail_end); +#endif + + vm_page_load(seg_index, phys_start, phys_end, seg->avail_start, seg->avail_end); } void __init