diff options
Diffstat (limited to 'src/memory/virtalloc.c')
-rw-r--r-- | src/memory/virtalloc.c | 81 |
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; } |