From 680a9f71b753c75e86d1adea42643e057abfcd46 Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Mon, 16 Feb 2026 19:08:36 -0300 Subject: [PATCH] =?utf8?q?fix:=20PMM=20total=5Fmemory=20overflow=20?= =?utf8?q?=E2=80=94=20MMAP=20reserved=20regions=20near=204GB=20inflated=20?= =?utf8?q?highest=5Faddr?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Root cause: Multiboot2 MMAP includes a BIOS reserved region at 0xFFFC0000-0x100000000. The end address (0x100000000) overflows uint32_t when stored in a uint64_t local variable, and (unsigned) truncation yields 0 — hence '[PMM] total_memory bytes: 0x0'. Fixes: - Use uint32_t locals (32-bit x86 caps RAM at 512 MB anyway) - Clamp MMAP end addresses to 0xFFFFFFFF before comparison - Only track highest_avail from AVAILABLE regions, not reserved - Use 'if' instead of 'else if' so both BASIC_MEMINFO and MMAP are processed in the same pass - Print total_memory and freed_frames in decimal with MB suffix Before: [PMM] total_memory bytes: 0x0 After: [PMM] total_memory: 134086656 bytes (127 MB) 83/83 smoke tests pass, cppcheck clean. --- src/arch/x86/pmm_boot.c | 170 +++++++++++++++++++++------------------- 1 file changed, 90 insertions(+), 80 deletions(-) diff --git a/src/arch/x86/pmm_boot.c b/src/arch/x86/pmm_boot.c index 050d1d0..7b7456a 100644 --- a/src/arch/x86/pmm_boot.c +++ b/src/arch/x86/pmm_boot.c @@ -6,14 +6,20 @@ #include -static uint64_t align_up_local(uint64_t value, uint64_t align) { +/* 32-bit x86: we cap usable RAM at MAX_RAM_SIZE (defined in pmm.c). */ +#define PMM_MAX_RAM (512U * 1024U * 1024U) + +static uint32_t align_up32(uint32_t value, uint32_t align) { return (value + align - 1) & ~(align - 1); } -static uint64_t align_down_local(uint64_t value, uint64_t align) { +static uint32_t align_down32(uint32_t value, uint32_t align) { return value & ~(align - 1); } +#define MB2_TAG_NEXT(t) \ + ((struct multiboot_tag *)((uint8_t *)(t) + (((t)->size + 7U) & ~7U))) + void pmm_arch_init(void* boot_info) { if (!boot_info) { kprintf("[PMM] Error: boot_info is NULL!\n"); @@ -21,125 +27,129 @@ void pmm_arch_init(void* boot_info) { } struct multiboot_tag *tag; - (void)*(uint32_t *)boot_info; - uint64_t highest_addr = 0; - uint64_t total_memory = 0; - int saw_mmap = 0; - uint64_t freed_frames = 0; + uint32_t total_mem = 0; + uint32_t highest_avail = 0; + int saw_mmap = 0; + uint32_t freed_frames = 0; kprintf("[PMM] Parsing Multiboot2 info...\n"); - // First pass: determine total memory size + /* --- Pass 1: determine total usable memory size --- */ for (tag = (struct multiboot_tag *)((uint8_t *)boot_info + 8); - tag->type != MULTIBOOT_TAG_TYPE_END; - tag = (struct multiboot_tag *)((uint8_t *)tag + ((tag->size + 7) & ~7))) + tag->type != MULTIBOOT_TAG_TYPE_END; + tag = MB2_TAG_NEXT(tag)) { if (tag->type == MULTIBOOT_TAG_TYPE_BASIC_MEMINFO) { - struct multiboot_tag_basic_meminfo *meminfo = (struct multiboot_tag_basic_meminfo *)tag; - uint64_t mem_kb = meminfo->mem_upper; - total_memory = (mem_kb * 1024) + (1024*1024); + struct multiboot_tag_basic_meminfo *mi = + (struct multiboot_tag_basic_meminfo *)tag; + total_mem = (mi->mem_upper * 1024U) + (1024U * 1024U); } - else if (tag->type == MULTIBOOT_TAG_TYPE_MMAP) { + if (tag->type == MULTIBOOT_TAG_TYPE_MMAP) { saw_mmap = 1; - struct multiboot_tag_mmap *mmap = (struct multiboot_tag_mmap *)tag; - struct multiboot_mmap_entry *entry; - - for (entry = mmap->entries; - (uint8_t *)entry < (uint8_t *)mmap + mmap->size; - entry = (struct multiboot_mmap_entry *)((uint32_t)entry + mmap->entry_size)) + struct multiboot_tag_mmap *mmap = + (struct multiboot_tag_mmap *)tag; + struct multiboot_mmap_entry *e; + for (e = mmap->entries; + (uint8_t *)e < (uint8_t *)mmap + mmap->size; + e = (struct multiboot_mmap_entry *) + ((uintptr_t)e + mmap->entry_size)) { - uint64_t end = entry->addr + entry->len; - if (end > highest_addr) highest_addr = end; + if (e->type != MULTIBOOT_MEMORY_AVAILABLE) + continue; + uint64_t end64 = e->addr + e->len; + /* Clamp to 32-bit address space */ + uint32_t end = (end64 > 0xFFFFFFFFULL) + ? 0xFFFFFFFFU : (uint32_t)end64; + if (end > highest_avail) + highest_avail = end; } } } - if (highest_addr > total_memory) { - total_memory = highest_addr; - } - if (total_memory == 0) { - total_memory = 16 * 1024 * 1024; - } + if (highest_avail > total_mem) + total_mem = highest_avail; + if (total_mem == 0) + total_mem = 16U * 1024U * 1024U; + if (total_mem > PMM_MAX_RAM) + total_mem = PMM_MAX_RAM; - // pmm_set_limits clamps and configures the bitmap - pmm_set_limits(total_memory, 0); + pmm_set_limits((uint64_t)total_mem, 0); - // Second pass: free AVAILABLE regions + /* --- Pass 2: free AVAILABLE regions --- */ for (tag = (struct multiboot_tag *)((uint8_t *)boot_info + 8); - tag->type != MULTIBOOT_TAG_TYPE_END; - tag = (struct multiboot_tag *)((uint8_t *)tag + ((tag->size + 7) & ~7))) + tag->type != MULTIBOOT_TAG_TYPE_END; + tag = MB2_TAG_NEXT(tag)) { - if (tag->type == MULTIBOOT_TAG_TYPE_MMAP) { - struct multiboot_tag_mmap *mmap = (struct multiboot_tag_mmap *)tag; - struct multiboot_mmap_entry *entry; + if (tag->type != MULTIBOOT_TAG_TYPE_MMAP) + continue; + + struct multiboot_tag_mmap *mmap = + (struct multiboot_tag_mmap *)tag; + struct multiboot_mmap_entry *e; + + for (e = mmap->entries; + (uint8_t *)e < (uint8_t *)mmap + mmap->size; + e = (struct multiboot_mmap_entry *) + ((uintptr_t)e + mmap->entry_size)) + { + if (e->type != MULTIBOOT_MEMORY_AVAILABLE) + continue; + + uint64_t b64 = e->addr; + uint64_t l64 = e->len; + if (b64 >= total_mem) continue; + if (b64 + l64 > total_mem) + l64 = total_mem - b64; + + uint32_t base = align_up32((uint32_t)b64, PAGE_SIZE); + uint32_t len = align_down32((uint32_t)l64, PAGE_SIZE); + if (len == 0) continue; - for (entry = mmap->entries; - (uint8_t *)entry < (uint8_t *)mmap + mmap->size; - entry = (struct multiboot_mmap_entry *)((uint32_t)entry + mmap->entry_size)) - { - if (entry->type == MULTIBOOT_MEMORY_AVAILABLE) { - uint64_t base = entry->addr; - uint64_t len = entry->len; - - if (base >= total_memory) continue; - if (base + len > total_memory) { - len = total_memory - base; - } - base = align_up_local(base, PAGE_SIZE); - len = align_down_local(len, PAGE_SIZE); - if (len == 0) continue; - - pmm_mark_region(base, len, 0); - freed_frames += (len / PAGE_SIZE); - } - } + pmm_mark_region(base, len, 0); + freed_frames += len / PAGE_SIZE; } } - // Fallback if no MMAP tag + /* Fallback if no MMAP tag */ if (!saw_mmap) { - uint64_t base = 0x00100000; - uint64_t len = (total_memory > base) ? (total_memory - base) : 0; - base = align_up_local(base, PAGE_SIZE); - len = align_down_local(len, PAGE_SIZE); + uint32_t base = 0x00100000U; + uint32_t len = (total_mem > base) ? (total_mem - base) : 0; + base = align_up32(base, PAGE_SIZE); + len = align_down32(len, PAGE_SIZE); if (len) { pmm_mark_region(base, len, 0); - freed_frames += (len / PAGE_SIZE); + freed_frames += len / PAGE_SIZE; } } - // Reserve low memory and frame 0 + /* Reserve low memory (real-mode IVT, BDA, EBDA, BIOS ROM) */ pmm_mark_region(0, 0x00100000, 1); - kprintf("[PMM] total_memory bytes: 0x%x\n", (unsigned)total_memory); - kprintf("[PMM] freed_frames: 0x%x\n", (unsigned)freed_frames); + kprintf("[PMM] total_memory: %u bytes (%u MB)\n", + total_mem, total_mem / (1024U * 1024U)); + kprintf("[PMM] freed_frames: %u (%u MB usable)\n", + freed_frames, (freed_frames * PAGE_SIZE) / (1024U * 1024U)); if (freed_frames == 0) { kprintf("[PMM] WARN: no free frames detected (MMAP missing or parse failed).\n"); } - // Protect Multiboot2 modules (e.g. initrd) + /* Protect Multiboot2 modules (e.g. initrd) */ for (tag = (struct multiboot_tag *)((uint8_t *)boot_info + 8); tag->type != MULTIBOOT_TAG_TYPE_END; - tag = (struct multiboot_tag *)((uint8_t *)tag + ((tag->size + 7) & ~7))) + tag = MB2_TAG_NEXT(tag)) { if (tag->type == MULTIBOOT_TAG_TYPE_MODULE) { - struct multiboot_tag_module* mod = (struct multiboot_tag_module*)tag; - uint64_t mod_start = (uint64_t)mod->mod_start; - uint64_t mod_end = (uint64_t)mod->mod_end; - if (mod_end < mod_start) mod_end = mod_start; - - uint64_t mod_start_aligned = align_down_local(mod_start, PAGE_SIZE); - uint64_t mod_end_aligned = align_up_local(mod_end, PAGE_SIZE); - if (mod_end_aligned < mod_start_aligned) { - mod_end_aligned = mod_start_aligned; - } - - pmm_mark_region(mod_start_aligned, mod_end_aligned - mod_start_aligned, 1); + struct multiboot_tag_module* mod = + (struct multiboot_tag_module*)tag; + uint32_t ms = align_down32(mod->mod_start, PAGE_SIZE); + uint32_t me = align_up32(mod->mod_end, PAGE_SIZE); + if (me > ms) + pmm_mark_region(ms, me - ms, 1); } } - // Protect Multiboot info structure itself + /* Protect Multiboot info structure itself */ uintptr_t kvbase = hal_mm_kernel_virt_base(); uintptr_t bi_ptr = (uintptr_t)boot_info; if (!kvbase || bi_ptr < kvbase) { -- 2.43.0