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

Reply via email to