1f5527388Srsc // Physical memory allocator, intended to allocate 27d7dc933SRobert Morris // memory for user processes, kernel stacks, page table pages, 37d7dc933SRobert Morris // and pipe buffers. Allocates 4096-byte pages. 455e95b16Srtm 555e95b16Srtm #include "types.h" 655e95b16Srtm #include "defs.h" 78148b6eeSrtm #include "param.h" 89aa0337dSFrans Kaashoek #include "memlayout.h" 940889627SFrans Kaashoek #include "mmu.h" 104e8f237bSrtm #include "spinlock.h" 114e8f237bSrtm 12*c092540eSRobert Morris void freerange(void *vstart, void *vend); 13*c092540eSRobert Morris extern char end[]; // first address after kernel loaded from ELF file 14*c092540eSRobert Morris 1555e95b16Srtm struct run { 1655e95b16Srtm struct run *next; 1755e95b16Srtm }; 1834295f46Srsc 1934295f46Srsc struct { 2034295f46Srsc struct spinlock lock; 21*c092540eSRobert Morris int use_lock; 2255e95b16Srtm struct run *freelist; 2334295f46Srsc } kmem; 2455e95b16Srtm 25*c092540eSRobert Morris // Initialization happens in two phases. 26*c092540eSRobert Morris // 1. main() calls kinit1() while still using entrypgdir to place just 27*c092540eSRobert Morris // the pages mapped by entrypgdir on free list. 28*c092540eSRobert Morris // 2. main() calls kinit2() with the rest of the physical pages 29*c092540eSRobert Morris // after installing a full page table that maps them on all cores. 30*c092540eSRobert Morris void 31*c092540eSRobert Morris kinit1(void *vstart, void *vend) 329aa0337dSFrans Kaashoek { 33*c092540eSRobert Morris initlock(&kmem.lock, "kmem"); 34*c092540eSRobert Morris kmem.use_lock = 0; 35*c092540eSRobert Morris freerange(vstart, vend); 369aa0337dSFrans Kaashoek } 374587b358SRobert Morris 3855e95b16Srtm void 39*c092540eSRobert Morris kinit2(void *vstart, void *vend) 40*c092540eSRobert Morris { 41*c092540eSRobert Morris freerange(vstart, vend); 42*c092540eSRobert Morris kmem.use_lock = 1; 43*c092540eSRobert Morris } 44*c092540eSRobert Morris 45*c092540eSRobert Morris void 46*c092540eSRobert Morris freerange(void *vstart, void *vend) 4755e95b16Srtm { 481a81e38bSRuss Cox char *p; 49*c092540eSRobert Morris p = (char*)PGROUNDUP((uint)vstart); 50*c092540eSRobert Morris for(; p + PGSIZE <= (char*)vend; p += PGSIZE) 513597d5dcSRobert Morris kfree(p); 5255e95b16Srtm } 5355e95b16Srtm 545048762cSAustin Clements //PAGEBREAK: 21 557d7dc933SRobert Morris // Free the page of physical memory pointed at by v, 5631085bb4Srsc // which normally should have been returned by a 577d7dc933SRobert Morris // call to kalloc(). (The exception is when 5831085bb4Srsc // initializing the allocator; see kinit above.) 5955e95b16Srtm void 607d7dc933SRobert Morris kfree(char *v) 6155e95b16Srtm { 627d7dc933SRobert Morris struct run *r; 6355e95b16Srtm 645f069dcfSFrans Kaashoek if((uint)v % PGSIZE || v < end || v2p(v) >= PHYSTOP) 6555e95b16Srtm panic("kfree"); 6655e95b16Srtm 67d4c64e5dSrsc // Fill with junk to catch dangling refs. 687d7dc933SRobert Morris memset(v, 1, PGSIZE); 698b4e2a08Srtm 70*c092540eSRobert Morris if(kmem.use_lock) 7134295f46Srsc acquire(&kmem.lock); 727d7dc933SRobert Morris r = (struct run*)v; 737d7dc933SRobert Morris r->next = kmem.freelist; 747d7dc933SRobert Morris kmem.freelist = r; 75*c092540eSRobert Morris if(kmem.use_lock) 7634295f46Srsc release(&kmem.lock); 7755e95b16Srtm } 7855e95b16Srtm 797d7dc933SRobert Morris // Allocate one 4096-byte page of physical memory. 807d7dc933SRobert Morris // Returns a pointer that the kernel can use. 81f5527388Srsc // Returns 0 if the memory cannot be allocated. 8255e95b16Srtm char* 831a81e38bSRuss Cox kalloc(void) 8455e95b16Srtm { 857d7dc933SRobert Morris struct run *r; 8655e95b16Srtm 87*c092540eSRobert Morris if(kmem.use_lock) 8834295f46Srsc acquire(&kmem.lock); 897d7dc933SRobert Morris r = kmem.freelist; 907d7dc933SRobert Morris if(r) 917d7dc933SRobert Morris kmem.freelist = r->next; 92*c092540eSRobert Morris if(kmem.use_lock) 9334295f46Srsc release(&kmem.lock); 947d7dc933SRobert Morris return (char*)r; 9555e95b16Srtm } 9640889627SFrans Kaashoek 97