Last active
February 9, 2019 20:53
-
-
Save yaodong/2c0857fc369e4462e28bfe1e28b4507c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 "defs.h" | |
#include "param.h" | |
#include "memlayout.h" | |
#include "mmu.h" | |
#include "spinlock.h" | |
void freerange(void *vstart, void *vend); | |
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; | |
int use_lock; | |
struct run *freelist; | |
} kmem; | |
// Initialization happens in two phases. | |
// 1. main() calls kinit1() while still using entrypgdir to place just | |
// the pages mapped by entrypgdir on free list. | |
// 2. main() calls kinit2() with the rest of the physical pages | |
// after installing a full page table that maps them on all cores. | |
void | |
kinit1(void *vstart, void *vend) | |
{ | |
initlock(&kmem.lock, "kmem"); | |
kmem.use_lock = 0; | |
freerange(vstart, vend); | |
} | |
void | |
kinit2(void *vstart, void *vend) | |
{ | |
freerange(vstart, vend); | |
kmem.use_lock = 1; | |
} | |
void | |
freerange(void *vstart, void *vend) | |
{ | |
char *p; | |
p = (char*)PGROUNDUP((uint)vstart); | |
for(; p + PGSIZE <= (char*)vend; 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(char *v) | |
{ | |
struct run *r; | |
if((uint)v % PGSIZE || v < end || V2P(v) >= PHYSTOP) | |
panic("kfree"); | |
// Fill with junk to catch dangling refs. | |
memset(v, 1, PGSIZE); | |
if(kmem.use_lock) | |
acquire(&kmem.lock); | |
r = (struct run*)v; | |
r->next = kmem.freelist; | |
kmem.freelist = r; | |
if(kmem.use_lock) | |
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. | |
char* | |
kalloc(void) | |
{ | |
struct run *r; | |
if(kmem.use_lock) | |
acquire(&kmem.lock); | |
r = kmem.freelist; | |
if(r) | |
kmem.freelist = r->next; | |
if(kmem.use_lock) | |
release(&kmem.lock); | |
return (char*)r; | |
} | |
int | |
kfreemem(void) | |
{ | |
struct run *r; | |
int p; | |
if(kmem.use_lock) | |
acquire(&kmem.lock); | |
r = kmem.freelist; | |
if (!r) | |
return 0; | |
p = 0; | |
while(1) { | |
p = p + 1; | |
r = r->next; | |
if (!r) | |
break; | |
} | |
if(kmem.use_lock) | |
release(&kmem.lock); | |
return p * PGSIZE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment