From 72f55421fb61b750512f324d284b30e3e67e36e0 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Wed, 13 Mar 2024 22:33:38 +0100
Subject: kernel/malloc: slight rework (it's still bad), store more metadata

---
 src/kernel/arch/amd64/boot.c          |   2 +-
 src/kernel/arch/amd64/driver/fsroot.c |   2 +-
 src/kernel/handle.c                   |   2 +-
 src/kernel/malloc.c                   | 142 +++++++++++++++++++++++-----------
 src/kernel/malloc.h                   |   9 +--
 src/kernel/proc.c                     |  12 +--
 src/kernel/syscalls.c                 |  10 +--
 src/kernel/vfs/mount.c                |   4 +-
 src/kernel/vfs/procfs.c               |   4 +-
 src/kernel/vfs/request.c              |   4 +-
 10 files changed, 119 insertions(+), 72 deletions(-)

(limited to 'src')

diff --git a/src/kernel/arch/amd64/boot.c b/src/kernel/arch/amd64/boot.c
index 76bc864..19f249a 100644
--- a/src/kernel/arch/amd64/boot.c
+++ b/src/kernel/arch/amd64/boot.c
@@ -86,7 +86,7 @@ void kmain_early(void *mbi) {
 }
 
 void shutdown(void) {
-	kprintf("shutting off\n");
+	kprintf("[kern] shutting off\n");
 	mem_debugprint();
 	cpu_shutdown();
 }
diff --git a/src/kernel/arch/amd64/driver/fsroot.c b/src/kernel/arch/amd64/driver/fsroot.c
index 2684b72..228232e 100644
--- a/src/kernel/arch/amd64/driver/fsroot.c
+++ b/src/kernel/arch/amd64/driver/fsroot.c
@@ -53,7 +53,7 @@ handle(VfsReq *req)
 		case Hdev:
 			if (!dev) {
 				dev_len = get_dev(NULL);
-				dev = kmalloc(dev_len);
+				dev = kmalloc(dev_len, "/ cache");
 				get_dev(dev);
 			}
 			lst = dev;
diff --git a/src/kernel/handle.c b/src/kernel/handle.c
index 51a95be..ca4c4c4 100644
--- a/src/kernel/handle.c
+++ b/src/kernel/handle.c
@@ -7,7 +7,7 @@
 #include <shared/mem.h>
 
 Handle *handle_init(enum handle_type type) {
-	Handle *h = kzalloc(sizeof *h);
+	Handle *h = kzalloc(sizeof *h, "handle");
 	h->type = type;
 	h->refcount = 1;
 	return h;
diff --git a/src/kernel/malloc.c b/src/kernel/malloc.c
index 7efd5a5..8ba00dc 100644
--- a/src/kernel/malloc.c
+++ b/src/kernel/malloc.c
@@ -6,23 +6,28 @@
 #include <stdbool.h>
 #include <stdint.h>
 
-#define MALLOC_MAGIC 0xA770C666
-
-struct malloc_hdr {
-	uint32_t magic;
-	uint32_t page_amt;
-	struct malloc_hdr *next, *prev;
+#define MALLOC_MAGIC 0x616c6c6f63686472
+#define DESCLEN 8
+
+typedef struct Allocation Allocation;
+struct Allocation {
+	uint64_t magic;
+	uint64_t len;
+	Allocation *next, *prev;
 	void *stacktrace[4];
+	char desc[DESCLEN];
 };
 
-struct malloc_hdr *malloc_last = NULL;
+Allocation *malloc_last = NULL;
 
 extern uint8_t pbitmap[]; /* linker.ld */
 static size_t pbitmap_len; /* in bytes */
 static size_t pbitmap_firstfree = 0;
 
 
-static bool bitmap_get(long i) {
+static
+bool bitmap_get(long i)
+{
 	assert(i >= 0);
 	size_t b = i / 8;
 	uint8_t m = 1 << (i&7);
@@ -30,7 +35,9 @@ static bool bitmap_get(long i) {
 	return (pbitmap[b]&m) != 0;
 }
 
-static bool bitmap_set(long i, bool v) {
+static
+bool bitmap_set(long i, bool v)
+{
 	assert(i >= 0);
 	size_t b = i / 8;
 	uint8_t m = 1 << (i&7);
@@ -41,18 +48,30 @@ static bool bitmap_set(long i, bool v) {
 	return prev;
 }
 
-static long toindex(void *p) {
+static
+long toindex(void *p)
+{
 	return ((long)p - (long)pbitmap) / PAGE_SIZE;
 }
 
-void mem_init(void *memtop) {
+static
+size_t page_amt(size_t bytes)
+{
+	return (bytes + PAGE_SIZE - 1) / PAGE_SIZE;
+}
+
+void
+mem_init(void *memtop)
+{
 	kprintf("memory   %8x -> %8x\n", &_bss_end, memtop);
 	pbitmap_len = toindex(memtop) / 8;
 	memset(pbitmap, 0, pbitmap_len);
 	mem_reserve(pbitmap, pbitmap_len);
 }
 
-void mem_reserve(void *addr, size_t len) {
+void
+mem_reserve(void *addr, size_t len)
+{
 	kprintf("reserved %8x -> %8x\n", addr, addr + len);
 
 	/* align to the previous page */
@@ -67,21 +86,36 @@ void mem_reserve(void *addr, size_t len) {
 	}
 }
 
-void mem_debugprint(void) {
-	size_t total = 0;
-	kprintf("current kmallocs:\n");
-	kprintf("addr      pages\n");
-	for (struct malloc_hdr *iter = malloc_last; iter; iter = iter->prev) {
-		kprintf("%08x  %05x", iter, iter->page_amt);
-		for (size_t i = 0; i < 4; i++)
-			kprintf("  k/%08x", iter->stacktrace[i]);
-		kprintf("\n    peek 0x%x\n", *(uint32_t*)(&iter[1]));
-		total++;
+void
+mem_debugprint(void)
+{
+	size_t count = 0, bytes = 0, pages = 0;
+	kprintf("[kern] current allocations:\n");
+	for (Allocation *iter = malloc_last; iter; iter = iter->prev) {
+		kprintf(
+			"%08p %6dB %.8s ",
+			((void*)iter) + sizeof(Allocation),
+			iter->len - sizeof(Allocation),
+			iter->desc
+		);
+		for (size_t i = 0; i < 4; i++) {
+			kprintf(" k/%08x", iter->stacktrace[i]);
+		}
+		kprintf("\n");
+
+		count++;
+		bytes += iter->len;
+		pages += page_amt(iter->len);
 	}
-	kprintf("  total 0x%x\n", total);
+	kprintf(
+		"%d in total, %d bytes, %d pages = %dB used\n",
+		count, bytes, pages, pages*PAGE_SIZE
+	);
 }
 
-void *page_alloc(size_t pages) {
+void
+*page_alloc(size_t pages)
+{
 	/* i do realize how painfully slow this is */
 	size_t streak = 0;
 	for (size_t i = pbitmap_firstfree; i < pbitmap_len * 8; i++) {
@@ -102,14 +136,18 @@ void *page_alloc(size_t pages) {
 	panic_unimplemented();
 }
 
-void *page_zalloc(size_t pages) {
+void
+*page_zalloc(size_t pages)
+{
 	void *p = page_alloc(pages);
 	memset(p, 0, pages * PAGE_SIZE);
 	return p;
 }
 
-// frees `pages` consecutive pages starting from *first
-void page_free(void *addr, size_t pages) {
+/* frees `pages` consecutive pages starting from *first */
+void
+page_free(void *addr, size_t pages)
+{
 	assert(addr >= (void*)pbitmap);
 	size_t first = toindex(addr);
 	for (size_t i = 0; i < pages; i++) {
@@ -122,27 +160,35 @@ void page_free(void *addr, size_t pages) {
 	}
 }
 
-void kmalloc_sanity(const void *addr) {
+void
+kmalloc_sanity(const void *addr)
+{
 	assert(addr);
-	const struct malloc_hdr *hdr = addr - sizeof(struct malloc_hdr);
+	const Allocation *hdr = addr - sizeof(Allocation);
 	assert(hdr->magic == MALLOC_MAGIC);
 	if (hdr->next) assert(hdr->next->prev == hdr);
 	if (hdr->prev) assert(hdr->prev->next == hdr);
 }
 
-void *kmalloc(size_t len) {
-	// TODO better kmalloc
-
-	struct malloc_hdr *hdr;
+// TODO better kmalloc
+void
+*kmalloc(size_t len, const char *desc)
+{
+	Allocation *hdr;
 	void *addr;
-	uint32_t pages;
-
-	len += sizeof(struct malloc_hdr);
-	pages = len / PAGE_SIZE + 1;
 
-	hdr = page_alloc(pages);
+	len += sizeof(Allocation);
+	hdr = page_alloc(page_amt(len));
 	hdr->magic = MALLOC_MAGIC;
-	hdr->page_amt = pages;
+	hdr->len = len;
+
+	memset(hdr->desc, ' ', DESCLEN);
+	if (desc) {
+		for (int i = 0; i < DESCLEN; i++) {
+			if (desc[i] == '\0') break;
+			hdr->desc[i] = desc[i];
+		}
+	}
 
 	hdr->next = NULL;
 	hdr->prev = malloc_last;
@@ -156,7 +202,7 @@ void *kmalloc(size_t len) {
 
 	malloc_last = hdr;
 
-	addr = (void*)hdr + sizeof(struct malloc_hdr);
+	addr = (void*)hdr + sizeof(Allocation);
 #ifndef NDEBUG
 	memset(addr, 0xCC, len);
 #endif
@@ -164,13 +210,16 @@ void *kmalloc(size_t len) {
 	return addr;
 }
 
-void kfree(void *ptr) {
-	struct malloc_hdr *hdr;
-	uint32_t page_amt;
+void
+kfree(void *ptr)
+{
+	Allocation *hdr;
+	size_t pages;
 	if (ptr == NULL) return;
 
-	hdr = ptr - sizeof(struct malloc_hdr);
+	hdr = ptr - sizeof(Allocation);
 	kmalloc_sanity(ptr);
+	pages = page_amt(hdr->len);
 
 	hdr->magic = ~MALLOC_MAGIC; // (hopefully) detect double frees
 	if (hdr->next)
@@ -179,9 +228,8 @@ void kfree(void *ptr) {
 		hdr->prev->next = hdr->next;
 	if (malloc_last == hdr)
 		malloc_last = hdr->prev;
-	page_amt = hdr->page_amt;
 #ifndef NDEBUG
-	memset(hdr, 0xC0, page_amt * PAGE_SIZE);
+	memset(hdr, 0xC0, pages * PAGE_SIZE);
 #endif
-	page_free(hdr, page_amt);
+	page_free(hdr, pages);
 }
diff --git a/src/kernel/malloc.h b/src/kernel/malloc.h
index 671a468..03934de 100644
--- a/src/kernel/malloc.h
+++ b/src/kernel/malloc.h
@@ -3,8 +3,6 @@
 #include <shared/mem.h>
 #include <stddef.h>
 
-extern struct malloc_hdr *malloc_last;
-
 void mem_init(void *memtop);
 void mem_reserve(void *addr, size_t len);
 void mem_debugprint(void);
@@ -19,11 +17,12 @@ void *page_zalloc(size_t pages);
 void page_free(void *first, size_t pages);
 
 void kmalloc_sanity(const void *addr);
-void *kmalloc(size_t len);
+void *kmalloc(size_t len, const char *desc);
 void kfree(void *ptr);
 
-static inline void *kzalloc(size_t len) {
-	void *b = kmalloc(len);
+// TODO calloc
+static inline void *kzalloc(size_t len, const char *desc) {
+	void *b = kmalloc(len, desc);
 	memset(b, 0, len);
 	return b;
 }
diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index 26b9e3a..8182a54 100644
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -19,12 +19,12 @@ static void proc_prune_leaves(void);
 
 Proc *proc_seed(void *data, size_t datalen) {
 	assert(!proc_first);
-	proc_first = kzalloc(sizeof *proc_first);
+	proc_first = kzalloc(sizeof *proc_first, "init");
 	proc_first->state = PS_RUNNING;
 	proc_first->pages = pagedir_new();
 	proc_first->mount = vfs_mount_seed();
 	proc_first->globalid = next_pid++;
-	proc_first->_handles = kzalloc(sizeof(Handle) * HANDLE_MAX);
+	proc_first->_handles = kzalloc(sizeof(Handle) * HANDLE_MAX, "init fds");
 
 	proc_first->pns = proc_first;
 	proc_first->localid = 1;
@@ -47,11 +47,11 @@ Proc *proc_seed(void *data, size_t datalen) {
 }
 
 Proc *proc_fork(Proc *parent, int flags) {
-	Proc *child = kzalloc(sizeof *child);
+	Proc *child = kzalloc(sizeof *child, "proc");
 
 	if (flags & FORK_SHAREMEM) {
 		if (!parent->pages_refcount) {
-			parent->pages_refcount = kmalloc(sizeof *parent->pages_refcount);
+			parent->pages_refcount = kmalloc(sizeof *parent->pages_refcount, "pagerefs");
 			*parent->pages_refcount = 1;
 		}
 		*parent->pages_refcount += 1;
@@ -96,14 +96,14 @@ Proc *proc_fork(Proc *parent, int flags) {
 
 	if (flags & FORK_SHAREHANDLE) {
 		if (!parent->handles_refcount) {
-			parent->handles_refcount = kmalloc(sizeof *parent->handles_refcount);
+			parent->handles_refcount = kmalloc(sizeof *parent->handles_refcount, "fd refs");
 			*parent->handles_refcount = 1;
 		}
 		*parent->handles_refcount += 1;
 		child->handles_refcount = parent->handles_refcount;
 		child->_handles = parent->_handles;
 	} else {
-		child->_handles = kzalloc(sizeof(Handle) * HANDLE_MAX);
+		child->_handles = kzalloc(sizeof(Handle) * HANDLE_MAX, "handles");
 		for (hid_t h = 0; h < HANDLE_MAX; h++) {
 			child->_handles[h] = parent->_handles[h];
 			if (child->_handles[h])
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index 5cec6c4..2a9a7b5 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -38,7 +38,7 @@ long _sys_fork(int flags, hid_t __user *fs_front) {
 			SYSCALL_RETURN(-EMFILE);
 		}
 
-		h->backend = kzalloc(sizeof *h->backend);
+		h->backend = kzalloc(sizeof *h->backend, "user fs");
 		h->backend->is_user = true;
 		h->backend->provhcnt = 1; /* child */
 		h->backend->usehcnt = 1; /* handle */
@@ -67,7 +67,7 @@ hid_t _sys_open(const char __user *path, long len, int flags) {
 	/* Doesn't check for free handles. Another thread could use up all
 	 * handles in the meantime anyways, or free some up. */
 
-	path_buf = kmalloc(len);
+	path_buf = kmalloc(len, "path opn");
 	if (pcpy_from(proc_cur, path_buf, path, len) < (size_t)len) {
 		goto fail;
 	}
@@ -110,7 +110,7 @@ long _sys_mount(hid_t hid, const char __user *path, long len) {
 	if (PATH_MAX < len)
 		SYSCALL_RETURN(-1);
 
-	path_buf = kmalloc(len);
+	path_buf = kmalloc(len, "path mnt");
 	if (pcpy_from(proc_cur, path_buf, path, len) < (size_t)len) {
 		goto fail;
 	}
@@ -135,7 +135,7 @@ long _sys_mount(hid_t hid, const char __user *path, long len) {
 
 	// append to mount list
 	// TODO move to kernel/vfs/mount.c
-	mount = kmalloc(sizeof *mount);
+	mount = kmalloc(sizeof *mount, "user mnt");
 	mount->prev = proc_cur->mount;
 	mount->prefix = path_buf;
 	mount->prefix_owned = true;
@@ -458,7 +458,7 @@ long _sys_execbuf(void __user *ubuf, size_t len) {
 		SYSCALL_RETURN(-1);
 	// TODO consider supporting nesting execbufs
 
-	char *kbuf = kmalloc(len);
+	char *kbuf = kmalloc(len, "execbuf");
 	if (pcpy_from(proc_cur, kbuf, ubuf, len) < len) {
 		kfree(kbuf);
 		SYSCALL_RETURN(-1);
diff --git a/src/kernel/vfs/mount.c b/src/kernel/vfs/mount.c
index c153c69..adf9b8c 100644
--- a/src/kernel/vfs/mount.c
+++ b/src/kernel/vfs/mount.c
@@ -10,8 +10,8 @@ VfsMount *vfs_mount_seed(void) {
 }
 
 void vfs_root_register(const char *path, void (*accept)(VfsReq *)) {
-	VfsBackend *backend = kmalloc(sizeof *backend);
-	VfsMount *mount = kmalloc(sizeof *mount);
+	VfsBackend *backend = kmalloc(sizeof *backend, "root bck");
+	VfsMount *mount = kmalloc(sizeof *mount, "root mnt");
 	*backend = (VfsBackend) {
 		.is_user = false,
 		.usehcnt = 1,
diff --git a/src/kernel/vfs/procfs.c b/src/kernel/vfs/procfs.c
index 4bacaf7..79dfdc0 100644
--- a/src/kernel/vfs/procfs.c
+++ b/src/kernel/vfs/procfs.c
@@ -73,7 +73,7 @@ openpath(const char *path, size_t len, Proc *root)
 		return NULL;
 	}
 
-	h = kmalloc(sizeof *h);
+	h = kmalloc(sizeof *h, "proc fd");
 	h->gid = gid;
 	h->type = type;
 	return h;
@@ -182,7 +182,7 @@ isdigit(int c) {
 VfsBackend *
 procfs_backend(Proc *proc)
 {
-	VfsBackend *be = kzalloc(sizeof(VfsBackend));
+	VfsBackend *be = kzalloc(sizeof(VfsBackend), "kern fs");
 	*be = (VfsBackend) {
 		.is_user = false,
 		.provhcnt = 1,
diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c
index 3a42c2a..21eecb8 100644
--- a/src/kernel/vfs/request.c
+++ b/src/kernel/vfs/request.c
@@ -13,11 +13,11 @@ void vfsreq_create(VfsReq req_) {
 	if (req_.caller) {
 		proc_setstate(req_.caller, PS_WAITS4FS);
 		if (!req_.caller->reqslot)
-			req_.caller->reqslot = kmalloc(sizeof *req);
+			req_.caller->reqslot = kmalloc(sizeof *req, "reqslot");
 		req = req_.caller->reqslot;
 		/* (re)using a single allocation for all request a process makes */
 	} else {
-		req = kmalloc(sizeof *req);
+		req = kmalloc(sizeof *req, "reqanon");
 	}
 	memcpy(req, &req_, sizeof *req);
 	if (req->backend) {
-- 
cgit v1.2.3