summaryrefslogtreecommitdiff
path: root/kernel/kalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kalloc.c')
-rw-r--r--kernel/kalloc.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/kernel/kalloc.c b/kernel/kalloc.c
new file mode 100644
index 0000000..ae3863b
--- /dev/null
+++ b/kernel/kalloc.c
@@ -0,0 +1,83 @@
+// Physical memory allocator, for user processes,
+// kernel stacks, page-table pages,
+// and pipe buffers. Allocates whole 4096-byte pages.
+
+#include "types.h"
+#include "param.h"
+#include "memlayout.h"
+#include "spinlock.h"
+#include "riscv.h"
+#include "defs.h"
+
+void freerange(void *pa_start, void *pa_end);
+
+extern char end[]; // first address after kernel.
+ // defined by kernel.ld.
+
+struct run {
+ struct run *next;
+};
+
+struct {
+ struct spinlock lock;
+ struct run *freelist;
+} kmem;
+
+void
+kinit()
+{
+ initlock(&kmem.lock, "kmem");
+ freerange(end, (void*)PHYSTOP);
+}
+
+void
+freerange(void *pa_start, void *pa_end)
+{
+ char *p;
+ p = (char*)PGROUNDUP((uint64)pa_start);
+ p += 4096; // XXX I can't get kernel.ld to place end beyond the last bss symbol.
+ for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
+ kfree(p);
+}
+
+// Free the page of physical memory pointed at by v,
+// which normally should have been returned by a
+// call to kalloc(). (The exception is when
+// initializing the allocator; see kinit above.)
+void
+kfree(void *pa)
+{
+ struct run *r;
+
+ if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
+ panic("kfree");
+
+ // Fill with junk to catch dangling refs.
+ memset(pa, 1, PGSIZE);
+
+ r = (struct run*)pa;
+
+ acquire(&kmem.lock);
+ r->next = kmem.freelist;
+ kmem.freelist = r;
+ release(&kmem.lock);
+}
+
+// Allocate one 4096-byte page of physical memory.
+// Returns a pointer that the kernel can use.
+// Returns 0 if the memory cannot be allocated.
+void *
+kalloc(void)
+{
+ struct run *r;
+
+ acquire(&kmem.lock);
+ r = kmem.freelist;
+ if(r)
+ kmem.freelist = r->next;
+ release(&kmem.lock);
+
+ if(r)
+ memset((char*)r, 5, PGSIZE); // fill with junk
+ return (void*)r;
+}