BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / d41a53cbc7d055b1c00cf0a339dbed6925f4f02c / mem / heap.c

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)
diff --git a/mem/heap.c b/mem/heap.c
new file mode 100644
index 0000000..9f9bbe2
--- /dev/null
+++ b/mem/heap.c
@@ -0,0 +1,125 @@
+/*
+ * This file contains the functions related to the Kernel's heap.  It uses a
+ * simple method of allocating and freeing blocks from a pool in the Kernel's
+ * memory space.  This heap will be present in every Page Directory, so can be
+ * used to store any Kernel data structures.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include "mem.h"
+#include "heap.h"
+#include "frame.h"
+#include "../vfs/cache.h"
+#include "../screen.h"
+#include "../spinlock.h"
+
+#define KHEAP_START 0x200000 /* 2 MB */
+#define KHEAP_END   0x800000 /* 8 MB */
+#define BLOCK_SIZE  16
+
+/* Structure for a Memory Header */
+typedef struct Header {
+	struct Header *next, *prev;
+	size_t size;
+	char magic[4];
+} Header; /* 16 bytes */
+
+size_t objectsAllocated = 0;
+size_t freeSpace = KHEAP_END - KHEAP_START;
+
+/* Allocate a region of the heap */
+void *
+kmalloc(size_t size)
+{
+	size_t blockSize, gapSize;
+	uintptr_t blockEnd;
+	Header *prev, *head, *next;
+	head = prev = (void *) KHEAP_START;
+	next = NULL;
+	objectsAllocated++;
+
+	/* Minimum allocation */
+	if (size % BLOCK_SIZE)
+		size += BLOCK_SIZE - (size % BLOCK_SIZE);
+	freeSpace -= size + sizeof(Header);
+
+	/* Low-memory VFS cache reaper */
+	if (freeSpace < 0x10000) /* 64 KB */
+		cache_reaper();
+
+	/* Block does not exist, create heap */
+	if (head->prev != head) {
+		head->prev = head;
+		head->next = NULL;
+		head->size = size;
+		memcpy(head->magic, "HEAP", 4);
+		memset((void *) (head + 1), 0, size);
+		return (void *) (head + 1);
+	}
+
+	/* Find gap */
+	while (head->next) {
+		next = head->next;
+		blockSize = sizeof(Header) + head->size;
+		blockEnd = (uintptr_t) head + blockSize;
+		gapSize = (size_t) next - blockEnd;
+		prev = head;
+
+		/* Fit in gap */
+		if (gapSize >= size + sizeof(Header)) {
+			head = (void *) blockEnd;
+			head->next = next;
+			head->prev = prev;
+			prev->next = head;
+			next->prev = head;
+			head->size = size;
+			memcpy(head->magic, "HEAP", 4);
+			memset((void *) (head + 1), 0, size);
+			return (void *) (head + 1);
+		}
+
+		head = head->next;
+	}
+
+	/* Add to end */
+	blockSize = sizeof(Header) + head->size;
+	blockEnd = (uintptr_t) head + blockSize;
+	gapSize = (size_t) KHEAP_END - blockEnd;
+	/* Fit in gap */
+	if (gapSize >= size + sizeof(Header)) {
+		prev = head;
+		head = (void *) blockEnd;
+		head->next = NULL;
+		head->prev = prev;
+		prev->next = head;
+		head->size = size;
+		memcpy(head->magic, "HEAP", 4);
+		memset((void *) (head + 1), 0, size);
+		return (void *) (head + 1);
+	}
+
+	panic("Kernel heap exhausted");
+}
+
+/* Free an allocated region of the heap */
+void
+_kfree(void *addr, char *file, int line)
+{
+	Header *prev, *head, *next;
+	head = (Header *) addr - 1;
+	objectsAllocated--;
+	freeSpace += head->size + sizeof(Header);
+
+	if (memcmp(head->magic, "HEAP", 4))
+		panic("Bad Kernel heap reference\n"
+		      "Invalid target @ %#.8x (%s:%d)", addr, file, line);
+	prev = head->prev;
+	next = head->next;
+	memset(head, 0, sizeof(Header));
+
+	if (prev != head)
+		prev->next = next;
+	if (next)
+		next->prev = prev;
+}