diff options
Diffstat (limited to 'kernel/kalloc.c')
-rw-r--r-- | kernel/kalloc.c | 80 |
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; +} |