summaryrefslogtreecommitdiff
path: root/kernel/kalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kalloc.c')
-rw-r--r--kernel/kalloc.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/kernel/kalloc.c b/kernel/kalloc.c
new file mode 100644
index 0000000..1ed1c49
--- /dev/null
+++ b/kernel/kalloc.c
@@ -0,0 +1,80 @@
+// Physical memory allocator, intended to allocate
+// memory for user processes, kernel stacks, page table pages,
+// and pipe buffers. Allocates 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 loaded from ELF file
+ // defined by the kernel linker script in 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);
+ for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
+ kfree(p);
+}
+//PAGEBREAK: 21
+// 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);
+
+ acquire(&kmem.lock);
+ r = (struct run*)pa;
+ 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;
+}