Files
pepperOS/src/mem/paging/pmm.c
2026-02-07 02:18:15 +01:00

111 lines
3.1 KiB
C

/*
* @author xamidev <xamidev@riseup.net>
* @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 <limine.h>
#include <stddef.h>
#include <stdint.h>
#include <kernel.h>
#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; i<memmap->entry_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();
}