summaryrefslogtreecommitdiff
path: root/src/memory/virtalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/memory/virtalloc.c')
-rw-r--r--src/memory/virtalloc.c81
1 files changed, 54 insertions, 27 deletions
diff --git a/src/memory/virtalloc.c b/src/memory/virtalloc.c
index 781fc9b..2ab9fc2 100644
--- a/src/memory/virtalloc.c
+++ b/src/memory/virtalloc.c
@@ -1,6 +1,9 @@
+#include "lib.h"
+#include "panic.h"
#include <stdint.h>
#include <stddef.h>
#include <memory.h>
+#include <string.h>
#define MEMORY_INTERNAL
#include <memory/virtalloc.h>
@@ -10,34 +13,60 @@ struct addr_node {
uintptr_t end;
struct addr_node *next;
struct addr_node *prev;
- uint8_t is_alloc;
- uint8_t is_bss;
+ uint8_t is_alloc; // if node is storing allocated data
+ uint8_t is_used; // if node is in use by virtalloc
};
-#define BOOTSTRAP_BSS_NODES 16
-static uint8_t bss_nodes = 0;
-static struct addr_node nodes[BOOTSTRAP_BSS_NODES];
+#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;
+static struct addr_node *start_node = NULL;
-static struct addr_node *alloc_node(void) {
- struct addr_node *node = NULL;
- if (bss_nodes >= BOOTSTRAP_BSS_NODES) {
- node = kalloc(sizeof(struct addr_node));
- if (node == NULL)
- return NULL;
- node->is_bss = false;
+static struct addr_node *get_node_idx(int idx) {
+ if (idx < BSS_NODES) {
+ return &bootstrap_nodes[idx];
} else {
- node = &nodes[bss_nodes];
- bss_nodes += 1;
- node->is_bss = true;
+ return &alloc_nodes[idx - BSS_NODES];
}
- return node;
+}
+
+static struct addr_node *get_node(void) {
+ size_t count = BSS_NODES + alloc_node_count;
+
+ if (!is_allocating && used_node_count + 16 >= count) {
+ is_allocating = true;
+ int new_alloc = alloc_node_count * 2;
+ if (new_alloc < 8)
+ new_alloc = 8;
+ int allocated = new_alloc - alloc_node_count;
+ int old = new_alloc - allocated;
+ alloc_nodes = krealloc(alloc_nodes, sizeof(struct addr_node) * new_alloc);
+ memset(alloc_nodes + old, 0, sizeof(struct addr_node) + allocated);;
+ alloc_node_count = new_alloc;
+ is_allocating = false;
+ count = BSS_NODES + alloc_node_count;
+ }
+
+ size_t idx = free_node_start;
+ for (; idx < count; idx++) {
+ struct addr_node *node = get_node_idx(idx);
+ if (!node->is_used) {
+ used_node_count++;
+ return node;
+ }
+ }
+
+ panic("could not get virtaddr node");
}
static void free_node(struct addr_node *node) {
- if (!node->is_bss)
- kfree(node);
+ node->is_used = false;
+ used_node_count--;
}
void virtaddr_init(void) {
@@ -47,11 +76,11 @@ void virtaddr_init(void) {
.next = NULL,
.prev = NULL,
.is_alloc = false,
- .is_bss = true,
+ .is_used = true,
};
- nodes[0] = init;
- start_node = &nodes[0];
- bss_nodes++;
+ memset(bootstrap_nodes, 0, sizeof(bootstrap_nodes));
+ bootstrap_nodes[0] = init;
+ start_node = &bootstrap_nodes[0];
}
void *virtaddr_alloc(int n_pages) {
@@ -69,10 +98,7 @@ void *virtaddr_alloc(int n_pages) {
long length = node->end - node->start;
if (length >= n_length) {
- struct addr_node *new = alloc_node();
- if (node == NULL) {
- return NULL;
- }
+ struct addr_node *new = get_node();
if (node->prev != NULL) {
node->prev->next = new;
}
@@ -82,6 +108,7 @@ void *virtaddr_alloc(int n_pages) {
new->end = new->start + n_length;
node->start = new->end;
new->is_alloc = true;
+ new->is_used = true;
new->next = node;
return (void *) new->start;
}