basic memory management

This commit is contained in:
nub31
2025-09-06 00:59:52 +02:00
parent bcf05c055e
commit a3822dd350
4 changed files with 129 additions and 14 deletions

View File

@@ -2,6 +2,7 @@
"files.associations": {
"bitset": "c",
"algorithm": "c",
"format": "c"
"format": "c",
"multiboot.h": "c"
}
}

View File

@@ -22,9 +22,10 @@ void x86_64_main(u32 magic, multiboot_info_t* info)
}
idt_init();
mem_init(info);
mem_alloc_2mb(MiB(128) + 1);
remap_pic();
enable_interrupts();
kernel_main();

View File

@@ -18,11 +18,6 @@ typedef struct
static memory_region_t usable_regions[USABLE_REGION_SIZE];
static size_t num_regions = 0;
#define KiB(count) ((u64)count * 1024)
#define MiB(count) (KiB((u64)count) * 1024)
#define GiB(count) (MiB((u64)count) * 1024)
#define TiB(count) (GiB((u64)count) * 1024)
// Fixed at 2mb for now
#define PAGE_SIZE MiB(2)
@@ -36,10 +31,18 @@ static u8 page_bitmap[BITMAP_SIZE];
static u64 total_pages = 0;
static u64 free_pages = 0;
#define PTE_MASK 0x00000000FFFFF000
#define PTE_PRESENT 1
#define PML4_INDEX(addr) (((addr) >> 39) & 0x1FF)
#define PDPT_INDEX(addr) (((addr) >> 30) & 0x1FF)
#define PD_INDEX(addr) (((addr) >> 21) & 0x1FF)
extern u64* pml4;
#define PTE_MASK 0x000FFFFFFFFFF000ULL
#define PTE_PRESENT (1ULL << 0)
#define PTE_WRITABLE (1ULL << 1)
#define PTE_USER (1ULL << 2)
#define PTE_PS (1ULL << 7)
extern u64 pml4[];
void mem_init(multiboot_info_t* info)
{
@@ -118,7 +121,7 @@ void mem_init(multiboot_info_t* info)
}
}
u64 mem_alloc_physical_page()
u64 mem_alloc_2mb_physical_page()
{
for (size_t i = 0; i < BITMAP_SIZE; i++)
{
@@ -139,7 +142,7 @@ u64 mem_alloc_physical_page()
return 0;
}
void mem_free_physical_page(u64 address)
void mem_free_2mb_physical_page(u64 address)
{
u64 page = address / PAGE_SIZE;
if (page < BITMAP_SIZE * 8)
@@ -151,3 +154,102 @@ void mem_free_physical_page(u64 address)
}
}
}
static u64 create_pte(u64 physical_address)
{
if (physical_address & MiB(2) - 1)
{
printf("Physical address not 2MB aligned (0x%x)\n", physical_address);
panic("Failed to create PTE");
}
return (physical_address & PTE_MASK) | PTE_PRESENT | PTE_WRITABLE | PTE_PS;
}
void mem_map_2mb_page(u64 virtual_address, u64 physical_address)
{
u64 pml4_idx = PML4_INDEX(virtual_address);
u64 pdpt_idx = PDPT_INDEX(virtual_address);
u64 pd_idx = PD_INDEX(virtual_address);
u64 pdpt = pml4[pml4_idx];
if (!(pdpt & PTE_PRESENT))
{
// todo(nub31): Dynamically create a pdpt table
printf("PDPT not present at PML4 index %u\n", pml4_idx);
panic("Failed to map virtual to physical page");
}
u64* pdpt_phys = (u64*)(pdpt & PTE_MASK);
u64 pd = pdpt_phys[pdpt_idx];
if (!(pd & PTE_PRESENT))
{
// todo(nub31): Dynamically create a pd table
printf("PD not present at PDPT index %u\n", pdpt_idx);
panic("Failed to map virtual to physical page");
}
u64* pd_phys = (u64*)(pd & PTE_MASK);
u64 entry = pd_phys[pd_idx];
if (entry & PTE_PRESENT)
{
printf("Virtual address 0x%x is already mapped\n", virtual_address);
panic("Failed to map virtual to physical page");
}
pd_phys[pd_idx] = create_pte(physical_address);
}
u64 mem_unmap_2mb_page(u64 virtual_address)
{
u64 pml4_idx = PML4_INDEX(virtual_address);
u64 pdpt_idx = PDPT_INDEX(virtual_address);
u64 pd_idx = PD_INDEX(virtual_address);
u64 pdpt_entry = pml4[pml4_idx];
if (!(pdpt_entry & PTE_PRESENT))
{
printf("PDPT not present at PML4 index %llu\n", pml4_idx);
panic("Failed to unmap virtual address");
}
u64* pdpt_phys = (u64*)(pdpt_entry & PTE_MASK);
u64 pd_entry = pdpt_phys[pdpt_idx];
if (!(pd_entry & PTE_PRESENT))
{
printf("PD not present at PDPT index %llu\n", pdpt_idx);
panic("Failed to unmap virtual address");
}
u64* pd_phys = (u64*)(pd_entry & PTE_MASK);
if (!(pd_phys[pd_idx] & PTE_PRESENT))
{
printf("Virtual address 0x%llx is not mapped\n", virtual_address);
panic("Failed to unmap virtual address");
}
u64 phys = pd_phys[pd_idx] & PTE_MASK;
pd_phys[pd_idx] = 0;
__asm__ volatile("invlpg (%0)" : : "r"(virtual_address) : "memory");
return phys;
}
void* mem_alloc_2mb(u64 virtual_address)
{
u64 phys = mem_alloc_2mb_physical_page();
if (!phys)
{
panic("Out of physical memory");
}
mem_map_2mb_page(virtual_address, phys);
return (void*)virtual_address;
}
void mem_free_2mb(u64 virtual_address)
{
u64 phys = mem_unmap_2mb_page(virtual_address);
mem_free_2mb_physical_page(phys);
}

View File

@@ -3,7 +3,18 @@
#include "std.h"
#include "x86_64/multiboot.h"
#define KiB(count) ((u64)count * 1024)
#define MiB(count) (KiB((u64)count) * 1024)
#define GiB(count) (MiB((u64)count) * 1024)
#define TiB(count) (GiB((u64)count) * 1024)
void mem_init(multiboot_info_t* info);
u64 mem_alloc_physical_page();
void mem_free_physical_page(u64 address);
u64 mem_alloc_2mb_physical_page();
void mem_free_2mb_physical_page(u64 address);
void mem_map_2mb_page(u64 virtual_address, u64 physical_address);
u64 mem_unmap_2mb_page(u64 virtual_address);
void* mem_alloc_2mb(u64 virtual_address);
void mem_free_2mb(u64 virtual_address);