Memory management

This commit is contained in:
2022-01-06 22:02:55 +01:00
parent 5d790cadbb
commit ec99fbf801
6 changed files with 203 additions and 29 deletions

View File

@@ -0,0 +1,37 @@
#include <stdint.h>
#include <memory.h>
#include <debug.h>
#include <multiboot.h>
uint64_t kernel_P4;
void memory_init()
{
kernel_P4 = (uint64_t)&BootP4;
uint64_t start, end;
uint32_t type, i = 0;
debug_info("Parsing memory map\n");
while(!multiboot_get_memory_area(i++, &start, &end, &type))
{
debug("0x%016x-0x%016x (%d)\n", start, end, type);
for(uint64_t p = start; p < end; p += PAGE_SIZE)
{
if(p >= V2P(&kernel_start) && p < V2P(&kernel_end))
continue;
uint64_t vaddr = (uint64_t)P2V(p);
uint64_t page = vmm_get_page(kernel_P4, vaddr);
if(page == (uint64_t)-1 || !(page & PAGE_PRESENT))
{
uint16_t flags = PAGE_WRITE | PAGE_PRESENT;
vmm_set_page(kernel_P4, vaddr, p, flags);
}
if(type == MMAP_FREE)
pmm_free(p);
}
}
}

26
src/kernel/memory/pmm.c Normal file
View File

@@ -0,0 +1,26 @@
#include <stdint.h>
#include <memory.h>
// Physical address of next page
uint64_t next = 0;
void pmm_free(uint64_t page)
{
*(uint64_t *)P2V(page) = next;
next = page;
}
uint64_t pmm_alloc()
{
if(!next) return 0;
uint64_t page = next;
next = *(uint64_t *)P2V(page);
return page;
}
uint64_t pmm_calloc()
{
uint64_t page = pmm_alloc();
memset(P2V(page), 0, PAGE_SIZE);
return page;
}

94
src/kernel/memory/vmm.c Normal file
View File

@@ -0,0 +1,94 @@
#include <stdint.h>
#include <memory.h>
#include <debug.h>
#define FLAGS_MASK (PAGE_SIZE-1)
#define MASK_FLAGS(addr) ((uint64_t)addr & ~FLAGS_MASK)
#define PRESENT(p) (p & PAGE_PRESENT)
#define PT(ptr) ((uint64_t *)P2V(MASK_FLAGS(ptr)))
#define P4E(P4, addr) (PT(P4)[P4_OFFSET(addr)])
#define P3E(P4, addr) (PT(P4E(P4, addr))[P3_OFFSET(addr)])
#define P2E(P4, addr) (PT(P3E(P4, addr))[P2_OFFSET(addr)])
#define P1E(P4, addr) (PT(P2E(P4, addr))[P1_OFFSET(addr)])
static int P1_exists(uint64_t P4, uint64_t addr)
{
if (P4 && PRESENT(P4E(P4, addr)) && PRESENT(P3E(P4, addr)) && PRESENT(P2E(P4, addr)))
return 1;
return 0;
}
static int touch_P1(uint64_t P4, uint64_t addr, uint16_t flags)
{
if (!P4) return -1;
if(!PRESENT(P4E(P4, addr)) && (!(P4E(P4,addr) = pmm_calloc())))
return -1;
P4E(P4, addr) |= flags | PAGE_PRESENT;
if(!PRESENT(P3E(P4, addr)) && (!(P3E(P4, addr) = pmm_calloc())))
return -1;
P3E(P4, addr) |= flags | PAGE_PRESENT;
if(!PRESENT(P2E(P4, addr)) && (!(P2E(P4, addr) = pmm_calloc())))
return -1;
P2E(P4, addr) |= flags | PAGE_PRESENT;
return 0;
}
uint64_t vmm_get_page(uint64_t P4, uint64_t addr)
{
if(P1_exists(P4, addr))
return P1E(P4, addr);
return -1;
}
int vmm_set_page(uint64_t P4, uint64_t addr, uint64_t page, uint16_t flags)
{
if(!P1_exists(P4, addr))
if(touch_P1(P4, addr, flags))
return -1;
P1E(P4, addr) = page | flags;
return 0;
}
void vmm_clear_page(uint64_t P4, uint64_t addr, int free)
{
if(!P1_exists(P4, addr))
return;
uint64_t *pt;
P1E(P4, addr) = 0;
if(!free)
return;
pt = PT(P2E(P4, addr));
for(int i = 0; i < ENTRIES_PER_PT; i++)
if(pt[i])
return;
pmm_free(MASK_FLAGS(P2E(P4, addr)));
P2E(P4, addr) = 0;
pt = PT(P3E(P4, addr));
for(int i = 0; i < ENTRIES_PER_PT; i++)
if(pt[i])
return;
pmm_free(MASK_FLAGS(P3E(P4, addr)));
P3E(P4, addr) = 0;
pt = PT(P4E(P4, addr));
for(int i = 0; i < ENTRIES_PER_PT; i++)
if(pt[i])
return;
pmm_free(MASK_FLAGS(P4E(P4, addr)));
P4E(P4, addr) = 0;
}