/* * @author xamidev * @brief Physical memory manager from freelist * @license GPL-3.0-only */ /* pmm - Physical Memory Manager will manage 4kb pages physically it will probably need to get some info from Limine, to see which pages are used by kernel/bootloader/mmio/fb etc. */ #include "paging.h" #include #include #include #include #include "mem/misc/utils.h" #include "pmm.h" /* First we'll have to discover the physical memory layout, and for that we can use a Limine request. */ /* We will look for the biggest usable physical memory region and use this for the bitmap. The reserved memory will be ignored. */ struct limine_memmap_entry* biggest_entry; static void pmm_find_biggest_usable_region(struct limine_memmap_response* memmap, struct limine_hhdm_response* hhdm) { // Max length of a usable memory region uint64_t length_max = 0; uint64_t offset = hhdm->offset; DEBUG("Usable Memory:"); for (size_t i=0; ientry_count; i++) { struct limine_memmap_entry* entry = memmap->entries[i]; if (entry->type == LIMINE_MEMMAP_USABLE) { DEBUG("0x%p-0x%p mapped at 0x%p-0x%p", entry->base, entry->base+entry->length, entry->base+offset, entry->base+entry->length+offset); if (entry->length > length_max) { length_max = entry->length; biggest_entry = entry; } } } DEBUG("Biggest usable memory region:"); DEBUG("0x%p-0x%p mapped at 0x%p-0x%p", biggest_entry->base, biggest_entry->base + biggest_entry->length, biggest_entry->base+offset, biggest_entry->base+biggest_entry->length+offset); } // Offset from Higher Half Direct Map uint64_t hhdm_off; static uintptr_t g_freelist = 0; uintptr_t pmm_alloc() { if (!g_freelist) { panic(NULL, "PMM is out of memory!"); } uintptr_t addr = g_freelist; g_freelist = *(uintptr_t*) PHYS_TO_VIRT(g_freelist); return addr; } void pmm_free(uintptr_t addr) { *(uintptr_t*) PHYS_TO_VIRT(addr) = g_freelist; g_freelist = addr; } static void pmm_init_freelist() { // We simply call pmm_free() on each page that is marked USABLE // in our big memory region. uint64_t base = ALIGN_UP(biggest_entry->base, PAGE_SIZE); uint64_t end = ALIGN_DOWN(biggest_entry->base + biggest_entry->length, PAGE_SIZE); uint64_t page_count=0; for (uint64_t addr = base; addr < end; addr += PAGE_SIZE) { pmm_free(addr); //DEBUG("page %u lives at phys 0x%p (virt 0x%p)", page_count, addr, PHYS_TO_VIRT(addr)); page_count++; } DEBUG("%u frames in freelist, available for use (%u bytes)", page_count, page_count*PAGE_SIZE); } void pmm_init(struct limine_memmap_response* memmap, struct limine_hhdm_response* hhdm) { hhdm_off = hhdm->offset; pmm_find_biggest_usable_region(memmap, hhdm); //pmm_allocate_bitmap(hhdm); too complicated for my small brain // Now we have biggest USABLE region, // so to populate the free list we just iterate through it pmm_init_freelist(); }