mm/pmm: Stop mmap_get_info() at first memory hole per Multiboot spec
diff --git a/common/mm/pmm.s2.c b/common/mm/pmm.s2.c
index 55d12ef9..a309dbb5 100644
--- a/common/mm/pmm.s2.c
+++ b/common/mm/pmm.s2.c
@@ -690,25 +690,35 @@ void *ext_mem_alloc_type_aligned_mode(uint64_t count, uint32_t type, size_t alig
struct meminfo mmap_get_info(size_t mmap_count, struct memmap_entry *mmap) {
struct meminfo info = {0};
- for (size_t i = 0; i < mmap_count; i++) {
- if (mmap[i].type == MEMMAP_USABLE) {
- // NOTE: Upper memory starts at address 1MiB and the
- // value of uppermem is the address of the first upper memory
- // hole minus 1MiB.
- if (mmap[i].base < 0x100000) {
- if (mmap[i].base + mmap[i].length > 0x100000) {
- size_t low_len = 0x100000 - mmap[i].base;
-
- info.lowermem += low_len;
- info.uppermem += mmap[i].length - low_len;
- } else {
- info.lowermem += mmap[i].length;
- }
- } else {
- info.uppermem += mmap[i].length;
+ // Find contiguous usable memory from address 0 (lower) and 1 MiB (upper)
+ // by iteratively extending a frontier. Handles unsorted entries.
+ uint64_t lower_end = 0;
+ uint64_t upper_end = 0x100000;
+ bool progress;
+
+ do {
+ progress = false;
+ for (size_t i = 0; i < mmap_count; i++) {
+ if (mmap[i].type != MEMMAP_USABLE)
+ continue;
+ uint64_t base = mmap[i].base;
+ uint64_t top = base + mmap[i].length;
+ if (base <= lower_end && top > lower_end) {
+ lower_end = top;
+ progress = true;
+ }
+ if (base <= upper_end && top > upper_end) {
+ upper_end = top;
+ progress = true;
}
}
- }
+ } while (progress);
+
+ if (lower_end > 0x100000)
+ lower_end = 0x100000;
+
+ info.lowermem = lower_end;
+ info.uppermem = upper_end - 0x100000;
return info;
}
