summaryrefslogtreecommitdiff
path: root/src/memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/memory.c')
-rw-r--r--src/memory.c60
1 files changed, 55 insertions, 5 deletions
diff --git a/src/memory.c b/src/memory.c
index bc65311..e5e215c 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -4,19 +4,29 @@
#include <stddef.h>
#include "memory.h"
#include "multiboot.h"
+#include "bees.h"
+#include "misc.h"
#include "printf.h"
struct memory_area {
uint32_t len;
struct memory_area *next;
+ struct memory_area *prev;
};
-struct memory_area *first = NULL;
-
uint32_t memory_available = 0;
+uint32_t total_memory = 0;
+struct memory_area *first_area = NULL;
+
+struct cell *first_free = NULL;
+
+extern mem_t __kernel_start;
+extern mem_t __kernel_end;
void init_memory(multiboot_info_t *mb) {
struct memory_area *prev = NULL;
+ struct cell *prev_cell = NULL;
+
for (
multiboot_memory_map_t *e = (multiboot_memory_map_t *) mb->mmap_addr;
(unsigned int) e < mb->mmap_addr + mb->mmap_length;
@@ -24,7 +34,7 @@ void init_memory(multiboot_info_t *mb) {
) {
if (e->type != MULTIBOOT_MEMORY_AVAILABLE) continue;
// memory below 1MB is not safe to use.
- if (e->addr < 1000000) continue;
+ if (e->addr < __kernel_start) continue;
// memory above UINT_MAX is unusable.
if (e->addr > UINT_MAX) continue;
@@ -34,14 +44,54 @@ void init_memory(multiboot_info_t *mb) {
length = UINT_MAX - e->addr;
else length = e->len;
- memory_available += length;
+ // free memory comes after the kernel
+ uint32_t addr = e->addr;
+ if (addr < (uint32_t) __kernel_end) {
+ addr = (uint32_t) __kernel_end;
+ length -= addr - e->addr;
+ }
+
+ memory_available += length - sizeof(struct memory_area);
- struct memory_area *cur = (struct memory_area *) e->addr;
+ // join memory area to linked list
+ struct memory_area *cur = (struct memory_area *) addr;
cur->len = length;
+ cur->next = NULL;
+ cur->prev = prev;
if (prev != NULL)
prev->next = (struct memory_area *) e->addr;
prev = cur;
+
+ if (first_area == NULL) first_area = cur;
+
+ unsigned char *after = (unsigned char*) (cur + 1);
+
+ // link memory into free list
+ for (
+ // cells start after memory area struct; they must be aligned.
+ struct cell *c = (struct cell *)
+ (after + ((uint32_t) after % sizeof(struct cell)));
+ // no part of the cell can be outside of the memory area
+ (uint32_t) (c + 1) < (uint32_t) cur + cur->len;
+ c++
+ ) {
+ if (first_free == NULL) first_free = c;
+ c->type = FREE_CELL;
+ set_cdr(c, 0);
+ if (prev_cell != NULL) set_cdr(prev_cell, (uint32_t) c);
+ prev_cell = c;
+ }
}
+ total_memory = memory_available;
+}
+
+struct cell *alloc_cell(enum cell_type t) {
+ if (first_free == NULL) return NULL; // GC should be invoked here somehow
+ if (first_free->type != FREE_CELL) bees("heap corruption has occurred");
+ first_free = cdr_cell(first_free);
+ first_free->type = t;
+ memory_available -= sizeof(struct cell);
+ return first_free;
}