fix/kernel: Fixed new VMM API
This commit is contained in:
parent
3aa5a1bb86
commit
6b811ad804
4 changed files with 151 additions and 74 deletions
|
@ -4,6 +4,14 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <boot/emk.h>
|
#include <boot/emk.h>
|
||||||
|
#include <mm/vmm.h>
|
||||||
|
|
||||||
|
// Macro to convert VALLOC_* flags to VMM_* page table flags
|
||||||
|
#define VFLAGS_TO_PFLAGS(flags) \
|
||||||
|
(VMM_PRESENT | \
|
||||||
|
(((flags) & VALLOC_WRITE) ? VMM_WRITE : 0) | \
|
||||||
|
(((flags) & VALLOC_USER) ? VMM_USER : 0) | \
|
||||||
|
(((flags) & VALLOC_EXEC) ? 0 : VMM_NX))
|
||||||
|
|
||||||
#define VMM_PRESENT (1ULL << 0)
|
#define VMM_PRESENT (1ULL << 0)
|
||||||
#define VMM_WRITE (1ULL << 1)
|
#define VMM_WRITE (1ULL << 1)
|
||||||
|
|
|
@ -68,7 +68,6 @@ void emk_entry(void)
|
||||||
hhdm_offset = hhdm_request.response->offset;
|
hhdm_offset = hhdm_request.response->offset;
|
||||||
log_early("HHDM Offset: %llx", hhdm_offset);
|
log_early("HHDM Offset: %llx", hhdm_offset);
|
||||||
pmm_init();
|
pmm_init();
|
||||||
log_early("Initialized physical page manager");
|
|
||||||
|
|
||||||
/* Test allocate a single physical page */
|
/* Test allocate a single physical page */
|
||||||
char *a = palloc(1, true);
|
char *a = palloc(1, true);
|
||||||
|
@ -78,6 +77,7 @@ void emk_entry(void)
|
||||||
*a = 32;
|
*a = 32;
|
||||||
log_early("Allocated 1 physical page: %llx", (uint64_t)a);
|
log_early("Allocated 1 physical page: %llx", (uint64_t)a);
|
||||||
pfree(a, 1);
|
pfree(a, 1);
|
||||||
|
log_early("Initialized physical page manager");
|
||||||
|
|
||||||
/* Setup virtual memory */
|
/* Setup virtual memory */
|
||||||
if (!kernel_address_request.response)
|
if (!kernel_address_request.response)
|
||||||
|
@ -91,14 +91,13 @@ void emk_entry(void)
|
||||||
log_early("Initialized paging");
|
log_early("Initialized paging");
|
||||||
|
|
||||||
/* Kernel Virtual Memory Context, not to be confused with KVM */
|
/* Kernel Virtual Memory Context, not to be confused with KVM */
|
||||||
vpm_ctx_t *kvm_ctx = vmm_init(kernel_pagemap);
|
vctx_t *kvm_ctx = vinit(kernel_pagemap, 0x1000);
|
||||||
if (!kvm_ctx)
|
if (!kvm_ctx)
|
||||||
{
|
{
|
||||||
kpanic(NULL, "Failed to create kernel VMM context");
|
kpanic(NULL, "Failed to create kernel VMM context");
|
||||||
}
|
}
|
||||||
log_early("Initialized virtual page manager");
|
|
||||||
|
|
||||||
char *b = valloc(kvm_ctx, 1, VMM_PRESENT | VMM_WRITE);
|
char *b = valloc(kvm_ctx, 1, VALLOC_RW);
|
||||||
if (!b)
|
if (!b)
|
||||||
{
|
{
|
||||||
kpanic(NULL, "Failed to allocate single virtual page");
|
kpanic(NULL, "Failed to allocate single virtual page");
|
||||||
|
@ -106,6 +105,8 @@ void emk_entry(void)
|
||||||
|
|
||||||
*b = 32;
|
*b = 32;
|
||||||
log_early("Allocated 1 virtual page: %llx", (uint64_t)b);
|
log_early("Allocated 1 virtual page: %llx", (uint64_t)b);
|
||||||
|
vfree(kvm_ctx, b);
|
||||||
|
log_early("Initialized virtual page manager");
|
||||||
|
|
||||||
hlt();
|
hlt();
|
||||||
}
|
}
|
|
@ -5,90 +5,144 @@
|
||||||
#include <util/align.h>
|
#include <util/align.h>
|
||||||
#include <boot/emk.h>
|
#include <boot/emk.h>
|
||||||
#include <arch/paging.h>
|
#include <arch/paging.h>
|
||||||
|
#include <lib/string.h>
|
||||||
|
|
||||||
vpm_ctx_t *vmm_init(uint64_t *pm)
|
vctx_t *vinit(uint64_t *pm, uint64_t start)
|
||||||
{
|
{
|
||||||
if (!pm || !IS_PAGE_ALIGNED(PHYSICAL(pm)))
|
vctx_t *ctx = (vctx_t *)palloc(1, true);
|
||||||
return NULL;
|
|
||||||
|
|
||||||
vpm_ctx_t *ctx = (vpm_ctx_t *)palloc(1, true);
|
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
memset(ctx, 0, sizeof(vctx_t));
|
||||||
|
ctx->root = (vregion_t *)palloc(1, true);
|
||||||
|
if (!ctx->root)
|
||||||
|
{
|
||||||
|
pfree(ctx, 1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->pagemap = pm;
|
ctx->pagemap = pm;
|
||||||
ctx->root = NULL; /* valloc creates the root if not present */
|
ctx->root->start = start;
|
||||||
|
ctx->root->pages = 0;
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *valloc(vpm_ctx_t *ctx, size_t pages, uint64_t flags)
|
void vdestroy(vctx_t *ctx)
|
||||||
{
|
{
|
||||||
if (!ctx || !pages)
|
if (ctx->root == NULL || ctx->pagemap == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vregion_t *region = ctx->root;
|
||||||
|
while (region != NULL)
|
||||||
|
{
|
||||||
|
vregion_t *next = region->next;
|
||||||
|
pfree(region, 1);
|
||||||
|
region = next;
|
||||||
|
}
|
||||||
|
pfree(ctx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *valloc(vctx_t *ctx, size_t pages, uint64_t flags)
|
||||||
|
{
|
||||||
|
if (ctx == NULL || ctx->root == NULL || ctx->pagemap == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Allocate physical pages */
|
vregion_t *region = ctx->root;
|
||||||
void *phys = palloc(pages, true);
|
vregion_t *new = NULL;
|
||||||
if (!phys)
|
vregion_t *last = ctx->root;
|
||||||
|
|
||||||
|
while (region)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (region->next == NULL || region->start + region->pages < region->next->start)
|
||||||
|
{
|
||||||
|
new = (vregion_t *)palloc(1, true);
|
||||||
|
if (!new)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
uint64_t virt = VPM_MIN_ADDR;
|
memset(new, 0, sizeof(vregion_t));
|
||||||
vm_region_t *prev = NULL;
|
new->pages = pages;
|
||||||
vm_region_t *curr = ctx->root;
|
new->flags = VFLAGS_TO_PFLAGS(flags);
|
||||||
|
new->start = region->start + (region->pages * PAGE_SIZE);
|
||||||
|
new->next = region->next;
|
||||||
|
new->prev = region;
|
||||||
|
region->next = new;
|
||||||
|
for (uint64_t i = 0; i < pages; i++)
|
||||||
|
{
|
||||||
|
uint64_t page = (uint64_t)palloc(1, false);
|
||||||
|
if (page == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
while (curr)
|
vmap(ctx->pagemap, new->start + i * PAGE_SIZE, page, new->flags);
|
||||||
|
}
|
||||||
|
return (void *)new->start;
|
||||||
|
}
|
||||||
|
region = region->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
new = (vregion_t *)palloc(1, true);
|
||||||
|
if (!new)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(new, 0, sizeof(vregion_t));
|
||||||
|
last->next = new;
|
||||||
|
new->prev = last;
|
||||||
|
new->start = last->start + (last->pages * PAGE_SIZE);
|
||||||
|
new->pages = pages;
|
||||||
|
new->flags = VFLAGS_TO_PFLAGS(flags);
|
||||||
|
new->next = NULL;
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < pages; i++)
|
||||||
{
|
{
|
||||||
uint64_t curr_end = curr->start + (curr->pages * PAGE_SIZE);
|
uint64_t page = (uint64_t)palloc(1, false);
|
||||||
if (virt + (pages * PAGE_SIZE) <= curr->start)
|
if (page == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
vmap(ctx->pagemap, new->start + i * PAGE_SIZE, page, new->flags);
|
||||||
|
}
|
||||||
|
return (void *)new->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vfree(vctx_t *ctx, void *ptr)
|
||||||
|
{
|
||||||
|
if (ctx == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vregion_t *region = ctx->root;
|
||||||
|
while (region != NULL)
|
||||||
|
{
|
||||||
|
if (region->start == (uint64_t)ptr)
|
||||||
{
|
{
|
||||||
/* Found a gap */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
virt = curr_end;
|
region = region->next;
|
||||||
prev = curr;
|
|
||||||
curr = curr->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Map the virtual to physical pages */
|
if (region == NULL)
|
||||||
for (size_t i = 0; i < pages; i++)
|
return;
|
||||||
|
|
||||||
|
vregion_t *prev = region->prev;
|
||||||
|
vregion_t *next = region->next;
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < region->pages; i++)
|
||||||
{
|
{
|
||||||
uint64_t vaddr = virt + (i * PAGE_SIZE);
|
uint64_t virt = region->start + i * PAGE_SIZE;
|
||||||
uint64_t paddr = (uint64_t)phys + (i * PAGE_SIZE);
|
uint64_t phys = virt_to_phys(kernel_pagemap, virt);
|
||||||
if (vmap(ctx->pagemap, vaddr, paddr, flags) != 0)
|
|
||||||
|
if (phys != 0)
|
||||||
{
|
{
|
||||||
/* Mapping failed, unmap any mapped pages and free physical memory */
|
pfree((void *)phys, 1);
|
||||||
for (size_t j = 0; j < i; j++)
|
vunmap(ctx->pagemap, virt);
|
||||||
{
|
|
||||||
vunmap(ctx->pagemap, virt + (j * PAGE_SIZE));
|
|
||||||
}
|
|
||||||
pfree(phys, pages);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create new region */
|
if (prev != NULL)
|
||||||
vm_region_t *region = (vm_region_t *)palloc(1, true);
|
prev->next = next;
|
||||||
if (!region)
|
|
||||||
{
|
|
||||||
/* Region allocation failed, clean up */
|
|
||||||
for (size_t i = 0; i < pages; i++)
|
|
||||||
{
|
|
||||||
vunmap(ctx->pagemap, virt + (i * PAGE_SIZE));
|
|
||||||
}
|
|
||||||
pfree(phys, pages);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
region->start = virt;
|
if (next != NULL)
|
||||||
region->pages = pages;
|
next->prev = prev;
|
||||||
region->next = curr;
|
|
||||||
|
|
||||||
if (prev)
|
if (region == ctx->root)
|
||||||
{
|
ctx->root = next;
|
||||||
prev->next = region;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ctx->root = region;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (void *)virt;
|
pfree(region, 1);
|
||||||
}
|
}
|
|
@ -9,21 +9,35 @@
|
||||||
#define VPM_MIN_ADDR 0x1000
|
#define VPM_MIN_ADDR 0x1000
|
||||||
#endif // VPM_MIN_ADDR
|
#endif // VPM_MIN_ADDR
|
||||||
|
|
||||||
typedef struct vm_region
|
#define VALLOC_NONE 0x0
|
||||||
|
#define VALLOC_READ (1 << 0)
|
||||||
|
#define VALLOC_WRITE (1 << 1)
|
||||||
|
#define VALLOC_EXEC (1 << 2)
|
||||||
|
#define VALLOC_USER (1 << 3)
|
||||||
|
|
||||||
|
#define VALLOC_RW (VALLOC_READ | VALLOC_WRITE)
|
||||||
|
#define VALLOC_RX (VALLOC_READ | VALLOC_EXEC)
|
||||||
|
#define VALLOC_RWX (VALLOC_READ | VALLOC_WRITE | VALLOC_EXEC)
|
||||||
|
|
||||||
|
typedef struct vregion
|
||||||
{
|
{
|
||||||
uint64_t start;
|
uint64_t start;
|
||||||
uint64_t pages;
|
uint64_t pages;
|
||||||
struct vm_region *next;
|
uint64_t flags;
|
||||||
/* TOOD: Maybe store flags */
|
struct vregion *next;
|
||||||
} vm_region_t;
|
struct vregion *prev;
|
||||||
|
} vregion_t;
|
||||||
|
|
||||||
typedef struct vpm_ctx
|
typedef struct vctx
|
||||||
{
|
{
|
||||||
vm_region_t *root;
|
vregion_t *root;
|
||||||
uint64_t *pagemap;
|
uint64_t *pagemap;
|
||||||
} vpm_ctx_t;
|
uint64_t start;
|
||||||
|
} vctx_t;
|
||||||
|
|
||||||
vpm_ctx_t *vmm_init(uint64_t *pm);
|
vctx_t *vinit(uint64_t *pm, uint64_t start);
|
||||||
void *valloc(vpm_ctx_t *ctx, size_t pages, uint64_t flags);
|
void vdestroy(vctx_t *ctx);
|
||||||
|
void *valloc(vctx_t *ctx, size_t pages, uint64_t flags);
|
||||||
|
void vfree(vctx_t *ctx, void *ptr);
|
||||||
|
|
||||||
#endif // VMM_H
|
#endif // VMM_H
|
Loading…
Add table
Add a link
Reference in a new issue