summaryrefslogtreecommitdiff
path: root/kernel/memory
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-04-15 22:20:59 -0400
committerFreya Murphy <freya@freyacat.org>2025-04-15 22:20:59 -0400
commit2dbf529c33aa3e24beff944758d586bb0608c1be (patch)
tree5b3381c3c8d9a74ccb988c8945fe0681c3ee7301 /kernel/memory
parentfix %n (diff)
downloadcomus-2dbf529c33aa3e24beff944758d586bb0608c1be.tar.gz
comus-2dbf529c33aa3e24beff944758d586bb0608c1be.tar.bz2
comus-2dbf529c33aa3e24beff944758d586bb0608c1be.zip
expand memory manager work with userspace (more then one ctx)
Diffstat (limited to 'kernel/memory')
-rw-r--r--kernel/memory/memory.c48
-rw-r--r--kernel/memory/memory.h8
-rw-r--r--kernel/memory/paging.c81
-rw-r--r--kernel/memory/paging.h10
-rw-r--r--kernel/memory/physalloc.c5
-rw-r--r--kernel/memory/virtalloc.c124
-rw-r--r--kernel/memory/virtalloc.h44
7 files changed, 210 insertions, 110 deletions
diff --git a/kernel/memory/memory.c b/kernel/memory/memory.c
index 145ce2b..b4ecb0d 100644
--- a/kernel/memory/memory.c
+++ b/kernel/memory/memory.c
@@ -1,21 +1,67 @@
+#include "lib/klib.h"
#include <comus/memory.h>
#include <comus/asm.h>
#include <comus/mboot.h>
#include <lib.h>
+#include "memory.h"
#include "paging.h"
#include "virtalloc.h"
#include "physalloc.h"
+mem_ctx_t kernel_mem_ctx;
+struct mem_ctx_s _kernel_mem_ctx;
+extern volatile char kernel_pml4[];
+extern struct virt_ctx kernel_virt_ctx;
+
+void *kmapaddr(void *phys, void *virt, size_t len, unsigned int flags)
+{
+ return mem_mapaddr(kernel_mem_ctx, phys, virt, len, flags);
+}
+
+void kunmapaddr(void *virt)
+{
+ mem_unmapaddr(kernel_mem_ctx, virt);
+}
+
+void *kalloc_page(void)
+{
+ return mem_alloc_page(kernel_mem_ctx);
+}
+
+void *kalloc_pages(size_t count)
+{
+ return mem_alloc_pages(kernel_mem_ctx, count);
+}
+
+void kfree_pages(void *ptr)
+{
+ mem_free_pages(kernel_mem_ctx, ptr);
+}
+
+int kload_page(void *virt)
+{
+ return mem_load_page(kernel_mem_ctx, virt);
+}
+
+mem_ctx_t alloc_mem_ctx(void)
+{
+ panic("alloc_mem_ctx not yet implemented");
+}
+
void memory_init(void)
{
struct memory_map mmap;
if (mboot_get_mmap(&mmap))
panic("failed to load memory map");
+ kernel_mem_ctx = &_kernel_mem_ctx;
+ kernel_mem_ctx->pml4 = kernel_pml4;
+ kernel_mem_ctx->virtctx = &kernel_virt_ctx;
+
cli();
paging_init();
- virtaddr_init();
+ virtaddr_init(kernel_mem_ctx->virtctx);
physalloc_init(&mmap);
sti();
}
diff --git a/kernel/memory/memory.h b/kernel/memory/memory.h
new file mode 100644
index 0000000..c39656d
--- /dev/null
+++ b/kernel/memory/memory.h
@@ -0,0 +1,8 @@
+
+#include <comus/memory.h>
+#include "virtalloc.h"
+
+struct mem_ctx_s {
+ struct virt_ctx *virtctx;
+ volatile char *pml4;
+};
diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c
index 5c4fa5c..2671cc2 100644
--- a/kernel/memory/paging.c
+++ b/kernel/memory/paging.c
@@ -1,9 +1,13 @@
#include <lib.h>
#include <comus/memory.h>
+#include <stddef.h>
+#include <stdint.h>
+
#include "virtalloc.h"
#include "physalloc.h"
#include "paging.h"
+#include "memory.h"
// PAGE MAP LEVEL 4 ENTRY
struct pml4e {
@@ -514,34 +518,56 @@ static inline void *page_align(void *addr)
return (void *)a;
}
-void *kmapaddr(void *addr, size_t len)
+void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len,
+ unsigned int flags)
{
- void *phys = page_align(addr);
- ptrdiff_t error = (char *)addr - (char *)phys;
+ TRACE("PHYS %16p VIRT %16p LEN %zu FLAGS %08x \n", phys, virt, len, flags);
+
+ long pages;
+ ptrdiff_t error;
+ void *aligned_phys;
+
+ // get length and physical page aligned address
+ aligned_phys = page_align(phys);
+ error = (char *)phys - (char *)aligned_phys;
len += error;
- long pages = len / PAGE_SIZE + 1;
- void *virt = virtaddr_alloc(pages);
- if (virt == NULL) {
+ pages = len / PAGE_SIZE + 1;
+
+ // get page aligned (or allocate) vitural address
+ if (virt == NULL)
+ virt = virtaddr_alloc(ctx->virtctx, pages);
+ if (virt == NULL)
return NULL;
- }
- if (map_pages(kernel_pml4, virt, phys, F_WRITEABLE, pages)) {
- virtaddr_free(virt);
+
+ if (map_pages((volatile struct pml4e *)ctx->pml4, virt, aligned_phys,
+ F_WRITEABLE | flags, pages)) {
+ virtaddr_free(ctx->virtctx, virt);
return NULL;
}
+
return (char *)virt + error;
}
-void kunmapaddr(void *addr)
+void mem_unmapaddr(mem_ctx_t ctx, void *virt)
{
- long pages = virtaddr_free(addr);
+ TRACE("VIRT %16p\n", virt);
+
+ long pages = virtaddr_free(ctx->virtctx, virt);
if (pages < 1)
return;
- unmap_pages(kernel_pml4, addr, pages);
+ unmap_pages(kernel_pml4, virt, pages);
}
-void *kalloc_pages(size_t count)
+void *mem_alloc_page(mem_ctx_t ctx)
{
- void *virt = virtaddr_alloc(count);
+ return mem_alloc_pages(ctx, 1);
+}
+
+void *mem_alloc_pages(mem_ctx_t ctx, size_t count)
+{
+ TRACE("COUNT %zu\n", count);
+
+ void *virt = virtaddr_alloc(ctx->virtctx, count);
if (virt == NULL)
return NULL;
//void *phys = alloc_phys_pages(count);
@@ -549,32 +575,33 @@ void *kalloc_pages(size_t count)
// virtaddr_free(virt);
// return NULL;
//}
- if (map_pages(kernel_pml4, virt,
+ if (map_pages((volatile struct pml4e *)ctx->pml4, virt,
//phys,
//F_WRITEABLE,
NULL, F_WRITEABLE, count)) {
- virtaddr_free(virt);
+ virtaddr_free(ctx->virtctx, virt);
return NULL;
}
return virt;
}
-void *kalloc_page(void)
+void mem_free_pages(mem_ctx_t ctx, void *virt)
{
- return kalloc_pages(1);
-}
+ TRACE("VIRT %16p\n", virt);
-void kfree_pages(void *virt)
-{
- long pages = virtaddr_free(virt);
- if (pages < 1)
- return;
- unmap_pages(kernel_pml4, virt, pages);
+ long pages = virtaddr_free(ctx->virtctx, virt);
+ if (pages == 1)
+ unmap_page((volatile struct pml4e *)ctx->pml4, virt);
+ else if (pages > 1)
+ unmap_pages((volatile struct pml4e *)ctx->pml4, virt, pages);
}
-int kload_page(void *virt_addr)
+int mem_load_page(mem_ctx_t ctx, void *virt_addr)
{
- volatile struct pte *page = get_page(kernel_pml4, virt_addr);
+ TRACE("VIRT %16p\n", virt_addr);
+
+ volatile struct pte *page =
+ get_page((volatile struct pml4e *)ctx->pml4, virt_addr);
if (page == NULL)
return -1;
if (page->loaded)
diff --git a/kernel/memory/paging.h b/kernel/memory/paging.h
index be6fd06..b54d422 100644
--- a/kernel/memory/paging.h
+++ b/kernel/memory/paging.h
@@ -9,16 +9,6 @@
#ifndef PAGING_H_
#define PAGING_H_
-#define F_PRESENT 0x001
-#define F_WRITEABLE 0x002
-#define F_UNPRIVILEGED 0x004
-#define F_WRITETHROUGH 0x008
-#define F_CACHEDISABLE 0x010
-#define F_ACCESSED 0x020
-#define F_DIRTY 0x040
-#define F_MEGABYTE 0x080
-#define F_GLOBAL 0x100
-
void paging_init(void);
#endif /* paging.h */
diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c
index a907077..7083c21 100644
--- a/kernel/memory/physalloc.c
+++ b/kernel/memory/physalloc.c
@@ -185,9 +185,10 @@ void physalloc_init(struct memory_map *map)
memory_start = page_align((uintptr_t)page_area_addr + page_area_size);
- bitmap = kmapaddr(bitmap, bitmap_size);
+ bitmap = kmapaddr(bitmap, NULL, bitmap_size, F_WRITEABLE);
memset(bitmap, 0, bitmap_size);
- page_area_addr = kmapaddr(page_area_addr, page_area_size);
+ page_area_addr =
+ kmapaddr(page_area_addr, NULL, page_area_size, F_WRITEABLE);
memset(page_area_addr, 0, page_area_size);
page_start = (struct memory_segment *)page_area_addr;
diff --git a/kernel/memory/virtalloc.c b/kernel/memory/virtalloc.c
index 6b7fd20..1c83427 100644
--- a/kernel/memory/virtalloc.c
+++ b/kernel/memory/virtalloc.c
@@ -3,45 +3,29 @@
#include "virtalloc.h"
-struct addr_node {
- uintptr_t start;
- uintptr_t end;
- struct addr_node *next;
- struct addr_node *prev;
- uint8_t is_alloc; // if node is storing allocated data
- uint8_t is_used; // if node is in use by virtalloc
-};
+struct virt_ctx kernel_virt_ctx;
-#define BSS_NODES 64
-static struct addr_node bootstrap_nodes[BSS_NODES];
-static struct addr_node *alloc_nodes = NULL;
-static size_t free_node_start = 0;
-static size_t alloc_node_count = 0;
-static size_t used_node_count = 0;
-static bool is_allocating = false;
-
-static struct addr_node *start_node = NULL;
-
-static struct addr_node *get_node_idx(int idx)
+static struct virt_addr_node *get_node_idx(struct virt_ctx *ctx, int idx)
{
- if (idx < BSS_NODES) {
- return &bootstrap_nodes[idx];
+ if (idx < BOOTSTRAP_VIRT_ALLOC_NODES) {
+ return &ctx->bootstrap_nodes[idx];
} else {
- return &alloc_nodes[idx - BSS_NODES];
+ return &ctx->alloc_nodes[idx - BOOTSTRAP_VIRT_ALLOC_NODES];
}
}
-static void update_node_ptrs(struct addr_node *old, struct addr_node *new,
- int old_len, int new_len)
+static void update_node_ptrs(struct virt_addr_node *old,
+ struct virt_addr_node *new, int old_len,
+ int new_len)
{
if (old == NULL)
return;
int idx = 0;
for (int i = 0; i < old_len; i++) {
- struct addr_node *o = &old[i];
+ struct virt_addr_node *o = &old[i];
if (o && !o->is_used)
continue;
- struct addr_node *n = &new[idx++];
+ struct virt_addr_node *n = &new[idx++];
*n = *o;
if (n->prev != NULL)
n->prev->next = n;
@@ -49,37 +33,38 @@ static void update_node_ptrs(struct addr_node *old, struct addr_node *new,
n->next->prev = n;
}
for (int i = idx; i < new_len; i++) {
- struct addr_node *n = &new[idx++];
+ struct virt_addr_node *n = &new[idx++];
n->is_used = false;
}
}
-static struct addr_node *get_node(void)
+static struct virt_addr_node *get_node(struct virt_ctx *ctx)
{
- size_t count = BSS_NODES + alloc_node_count;
+ size_t count = BOOTSTRAP_VIRT_ALLOC_NODES + ctx->alloc_node_count;
- if (!is_allocating && used_node_count + 16 >= count) {
- is_allocating = true;
- int new_alloc = alloc_node_count * 2;
+ if (!ctx->is_allocating && ctx->used_node_count + 16 >= count) {
+ ctx->is_allocating = true;
+ int new_alloc = ctx->alloc_node_count * 2;
if (new_alloc < 8)
new_alloc = 8;
- struct addr_node *new_nodes;
- new_nodes = kalloc(sizeof(struct addr_node) * new_alloc);
+ struct virt_addr_node *new_nodes;
+ new_nodes = kalloc(sizeof(struct virt_addr_node) * new_alloc);
if (new_nodes == NULL)
panic("virt addr alloc nodes is null");
- update_node_ptrs(alloc_nodes, new_nodes, alloc_node_count, new_alloc);
- kfree(alloc_nodes);
- alloc_nodes = new_nodes;
- alloc_node_count = new_alloc;
- is_allocating = false;
- count = BSS_NODES + alloc_node_count;
+ update_node_ptrs(ctx->alloc_nodes, new_nodes, ctx->alloc_node_count,
+ new_alloc);
+ kfree(ctx->alloc_nodes);
+ ctx->alloc_nodes = new_nodes;
+ ctx->alloc_node_count = new_alloc;
+ ctx->is_allocating = false;
+ count = BOOTSTRAP_VIRT_ALLOC_NODES + ctx->alloc_node_count;
}
- size_t idx = free_node_start;
+ size_t idx = ctx->free_node_start;
for (; idx < count; idx++) {
- struct addr_node *node = get_node_idx(idx);
+ struct virt_addr_node *node = get_node_idx(ctx, idx);
if (!node->is_used) {
- used_node_count++;
+ ctx->used_node_count++;
return node;
}
}
@@ -87,15 +72,15 @@ static struct addr_node *get_node(void)
panic("could not get virtaddr node");
}
-static void free_node(struct addr_node *node)
+static void free_node(struct virt_ctx *ctx, struct virt_addr_node *node)
{
node->is_used = false;
- used_node_count--;
+ ctx->used_node_count--;
}
-void virtaddr_init(void)
+void virtaddr_init(struct virt_ctx *ctx)
{
- struct addr_node init = {
+ struct virt_addr_node init = {
.start = 0x400000, // third page table
.end = 0x1000000000000, // 48bit memory address max
.next = NULL,
@@ -103,48 +88,53 @@ void virtaddr_init(void)
.is_alloc = false,
.is_used = true,
};
- memsetv(bootstrap_nodes, 0, sizeof(bootstrap_nodes));
- bootstrap_nodes[0] = init;
- start_node = &bootstrap_nodes[0];
+ memsetv(ctx->bootstrap_nodes, 0, sizeof(ctx->bootstrap_nodes));
+ ctx->bootstrap_nodes[0] = init;
+ ctx->alloc_nodes = NULL;
+ ctx->start_node = &ctx->bootstrap_nodes[0];
+ ctx->free_node_start = 0;
+ ctx->alloc_node_count = 0;
+ ctx->used_node_count = 0;
+ ctx->is_allocating = false;
}
-static void merge_back(struct addr_node *node)
+static void merge_back(struct virt_ctx *ctx, struct virt_addr_node *node)
{
while (node->prev) {
if (node->is_alloc != node->prev->is_alloc)
break;
- struct addr_node *temp = node->prev;
+ struct virt_addr_node *temp = node->prev;
node->start = temp->start;
node->prev = temp->prev;
if (temp->prev)
temp->prev->next = node;
- free_node(temp);
+ free_node(ctx, temp);
}
if (node->prev == NULL) {
- start_node = node;
+ ctx->start_node = node;
}
}
-static void merge_forward(struct addr_node *node)
+static void merge_forward(struct virt_ctx *ctx, struct virt_addr_node *node)
{
while (node->next) {
if (node->is_alloc != node->next->is_alloc)
break;
- struct addr_node *temp = node->next;
+ struct virt_addr_node *temp = node->next;
node->end = temp->end;
node->next = temp->next;
if (temp->next)
temp->next->prev = node;
- free_node(temp);
+ free_node(ctx, temp);
}
}
-void *virtaddr_alloc(int n_pages)
+void *virtaddr_alloc(struct virt_ctx *ctx, int n_pages)
{
if (n_pages < 1)
return NULL;
long n_length = n_pages * PAGE_SIZE;
- struct addr_node *node = start_node;
+ struct virt_addr_node *node = ctx->start_node;
for (; node != NULL; node = node->next) {
long length = node->end - node->start;
@@ -152,11 +142,11 @@ void *virtaddr_alloc(int n_pages)
continue;
if (length >= n_length) {
- struct addr_node *new = get_node();
+ struct virt_addr_node *new = get_node(ctx);
if (node->prev != NULL) {
node->prev->next = new;
} else {
- start_node = new;
+ ctx->start_node = new;
}
new->next = node;
new->prev = node->prev;
@@ -168,8 +158,8 @@ void *virtaddr_alloc(int n_pages)
new->is_used = true;
new->next = node;
void *mem = (void *)new->start;
- merge_back(new);
- merge_forward(new);
+ merge_back(ctx, new);
+ merge_forward(ctx, new);
return mem;
}
}
@@ -177,21 +167,21 @@ void *virtaddr_alloc(int n_pages)
return NULL;
}
-long virtaddr_free(void *virtaddr)
+long virtaddr_free(struct virt_ctx *ctx, void *virtaddr)
{
uintptr_t virt = (uintptr_t)virtaddr;
if (virt % PAGE_SIZE)
return -1; // not page aligned, we did not give this out!!!
- struct addr_node *node = start_node;
+ struct virt_addr_node *node = ctx->start_node;
for (; node != NULL; node = node->next) {
if (node->start == virt) {
int length = node->end - node->start;
int pages = length / PAGE_SIZE;
- merge_back(node);
- merge_forward(node);
+ merge_back(ctx, node);
+ merge_forward(ctx, node);
return pages;
}
}
diff --git a/kernel/memory/virtalloc.h b/kernel/memory/virtalloc.h
index a5ca840..9f974c5 100644
--- a/kernel/memory/virtalloc.h
+++ b/kernel/memory/virtalloc.h
@@ -9,23 +9,61 @@
#ifndef VIRTALLOC_H_
#define VIRTALLOC_H_
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#define BOOTSTRAP_VIRT_ALLOC_NODES 64
+
+struct virt_addr_node {
+ /// first virtural address
+ uintptr_t start;
+ /// last virtural address
+ uintptr_t end;
+ /// next node in linked list
+ struct virt_addr_node *next;
+ /// prev node in linked list
+ struct virt_addr_node *prev;
+ /// if this node is storing any allocated data
+ uint8_t is_alloc;
+ /// if this node is in use by virtalloc
+ uint8_t is_used;
+};
+
+struct virt_ctx {
+ /// bootstrap nodes for the context (not in heap)
+ struct virt_addr_node bootstrap_nodes[BOOTSTRAP_VIRT_ALLOC_NODES];
+ /// heap allocated nodes
+ struct virt_addr_node *alloc_nodes;
+ /// start node
+ struct virt_addr_node *start_node;
+ /// index of first free node
+ size_t free_node_start;
+ /// number of heap allocated nodes
+ size_t alloc_node_count;
+ /// number of used nodes
+ size_t used_node_count;
+ /// if we are currently allocating (recursion check)
+ bool is_allocating;
+};
+
/**
* Initalizes the virtual address allocator
*/
-void virtaddr_init(void);
+void virtaddr_init(struct virt_ctx *ctx);
/**
* Allocate a virtual address of length x pages
* @param pages - x pages
* @returns virt addr
*/
-void *virtaddr_alloc(int pages);
+void *virtaddr_alloc(struct virt_ctx *ctx, int pages);
/**
* Free the virtual address from virtaddr_alloc
* @param virtaddr - the addr to free
* @returns number of pages used for virtaddr
*/
-long virtaddr_free(void *virtaddr);
+long virtaddr_free(struct virt_ctx *ctx, void *virtaddr);
#endif /* virtalloc.h */