diff options
author | Robert Morris <[email protected]> | 2019-06-11 09:57:14 -0400 |
---|---|---|
committer | Robert Morris <[email protected]> | 2019-06-11 09:57:14 -0400 |
commit | 5753553213df8f9de851adb68377db43faecb91f (patch) | |
tree | 3b629ff54897fca414146677532cb459a2ed11ba /vm.c | |
parent | 91ba81110acd3163f7de3580b677eece0c57f5e7 (diff) | |
download | xv6-labs-5753553213df8f9de851adb68377db43faecb91f.tar.gz xv6-labs-5753553213df8f9de851adb68377db43faecb91f.tar.bz2 xv6-labs-5753553213df8f9de851adb68377db43faecb91f.zip |
separate source into kernel/ user/ mkfs/
Diffstat (limited to 'vm.c')
-rw-r--r-- | vm.c | 389 |
1 files changed, 0 insertions, 389 deletions
@@ -1,389 +0,0 @@ -#include "param.h" -#include "types.h" -#include "memlayout.h" -#include "elf.h" -#include "riscv.h" -#include "defs.h" -#include "fs.h" - -/* - * the kernel's page table. - */ -pagetable_t kernel_pagetable; - -extern char etext[]; // kernel.ld sets this to end of kernel code. - -extern char trampout[]; // trampoline.S - -/* - * create a direct-map page table for the kernel and - * turn on paging. called early, in supervisor mode. - * the page allocator is already initialized. - */ -void -kvminit() -{ - kernel_pagetable = (pagetable_t) kalloc(); - memset(kernel_pagetable, 0, PGSIZE); - - // uart registers - mappages(kernel_pagetable, UART0, PGSIZE, - UART0, PTE_R | PTE_W); - - // CLINT - mappages(kernel_pagetable, CLINT, 0x10000, - CLINT, PTE_R | PTE_W); - - // PLIC - mappages(kernel_pagetable, PLIC, 0x4000000, - PLIC, PTE_R | PTE_W); - - // map kernel text executable and read-only. - mappages(kernel_pagetable, KERNBASE, (uint64)etext-KERNBASE, - KERNBASE, PTE_R | PTE_X); - - // map kernel data and the physical RAM we'll make use of. - mappages(kernel_pagetable, (uint64)etext, PHYSTOP-(uint64)etext, - (uint64)etext, PTE_R | PTE_W); - - // map the qemu -initrd fs.img ramdisk - mappages(kernel_pagetable, RAMDISK, FSSIZE * BSIZE, - RAMDISK, PTE_R | PTE_W); - - // map the trampoline for trap entry/exit to - // the highest virtual address in the kernel. - mappages(kernel_pagetable, TRAMPOLINE, PGSIZE, - (uint64)trampout, PTE_R | PTE_X); -} - -// Switch h/w page table register to the kernel's page table, -// and enable paging. -void -kvminithart() -{ - w_satp(MAKE_SATP(kernel_pagetable)); -} - -// Return the address of the PTE in page table pagetable -// that corresponds to virtual address va. If alloc!=0, -// create any required page table pages. -// -// The risc-v Sv39 scheme has three levels of page table -// pages. A page table page contains 512 64-bit PTEs. -// A 64-bit virtual address is split into five fields: -// 39..63 -- must be zero. -// 30..38 -- 9 bits of level-2 index. -// 21..39 -- 9 bits of level-1 index. -// 12..20 -- 9 bits of level-0 index. -// 0..12 -- 12 bits of byte offset within the page. -static pte_t * -walk(pagetable_t pagetable, uint64 va, int alloc) -{ - if(va >= MAXVA) - panic("walk"); - - for(int level = 2; level > 0; level--) { - pte_t *pte = &pagetable[PX(level, va)]; - if(*pte & PTE_V) { - pagetable = (pagetable_t)PTE2PA(*pte); - } else { - if(!alloc || (pagetable = (pde_t*)kalloc()) == 0) - return 0; - memset(pagetable, 0, PGSIZE); - *pte = PA2PTE(pagetable) | PTE_V; - } - } - return &pagetable[PX(0, va)]; -} - -// Look up a virtual address, return the physical address, -// Can only be used to look up user pages. -// or 0 if not mapped. -uint64 -walkaddr(pagetable_t pagetable, uint64 va) -{ - pte_t *pte; - uint64 pa; - - pte = walk(pagetable, va, 0); - if(pte == 0) - return 0; - if((*pte & PTE_V) == 0) - return 0; - if((*pte & PTE_U) == 0) - return 0; - pa = PTE2PA(*pte); - return pa; -} - - -// Create PTEs for virtual addresses starting at va that refer to -// physical addresses starting at pa. va and size might not -// be page-aligned. -void -mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm) -{ - uint64 a, last; - pte_t *pte; - - a = PGROUNDDOWN(va); - last = PGROUNDDOWN(va + size - 1); - for(;;){ - if((pte = walk(pagetable, a, 1)) == 0) - panic("mappages: walk"); - if(*pte & PTE_V) - panic("remap"); - *pte = PA2PTE(pa) | perm | PTE_V; - if(a == last) - break; - a += PGSIZE; - pa += PGSIZE; - } -} - -// Remove mappings from a page table. The mappings in -// the given range must exist. Optionally free the -// physical memory. -void -unmappages(pagetable_t pagetable, uint64 va, uint64 size, int do_free) -{ - uint64 a, last; - pte_t *pte; - uint64 pa; - - a = PGROUNDDOWN(va); - last = PGROUNDDOWN(va + size - 1); - for(;;){ - if((pte = walk(pagetable, a, 0)) == 0) - panic("unmappages: walk"); - if((*pte & PTE_V) == 0){ - printf("va=%p pte=%p\n", a, *pte); - panic("unmappages: not mapped"); - } - if(PTE_FLAGS(*pte) == PTE_V) - panic("unmappages: not a leaf"); - if(do_free){ - pa = PTE2PA(*pte); - kfree((void*)pa); - } - *pte = 0; - if(a == last) - break; - a += PGSIZE; - pa += PGSIZE; - } -} - -// create an empty user page table. -pagetable_t -uvmcreate() -{ - pagetable_t pagetable; - pagetable = (pagetable_t) kalloc(); - if(pagetable == 0) - panic("uvmcreate: out of memory"); - memset(pagetable, 0, PGSIZE); - return pagetable; -} - -// Load the user initcode into address 0 of pagetable, -// for the very first process. -// sz must be less than a page. -void -uvminit(pagetable_t pagetable, uchar *src, uint sz) -{ - char *mem; - - if(sz >= PGSIZE) - panic("inituvm: more than a page"); - mem = kalloc(); - memset(mem, 0, PGSIZE); - mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W|PTE_R|PTE_X|PTE_U); - memmove(mem, src, sz); -} - -// Allocate PTEs and physical memory to grow process from oldsz to -// newsz, which need not be page aligned. Returns new size or 0 on error. -uint64 -uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) -{ - char *mem; - uint64 a; - - if(newsz < oldsz) - return oldsz; - - oldsz = PGROUNDUP(oldsz); - a = oldsz; - for(; a < newsz; a += PGSIZE){ - mem = kalloc(); - if(mem == 0){ - uvmdealloc(pagetable, a, oldsz); - return 0; - } - memset(mem, 0, PGSIZE); - mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U); - } - return newsz; -} - -// Deallocate user pages to bring the process size from oldsz to -// newsz. oldsz and newsz need not be page-aligned, nor does newsz -// need to be less than oldsz. oldsz can be larger than the actual -// process size. Returns the new process size. -uint64 -uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) -{ - if(newsz >= oldsz) - return oldsz; - unmappages(pagetable, newsz, oldsz - newsz, 1); - return newsz; -} - -// Recursively free page table pages. -// All leaf mappings must already have been removed. -static void -freewalk(pagetable_t pagetable) -{ - // there are 2^9 = 512 PTEs in a page table. - for(int i = 0; i < 512; i++){ - pte_t pte = pagetable[i]; - if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){ - // this PTE points to a lower-level page table. - uint64 child = PTE2PA(pte); - freewalk((pagetable_t)child); - pagetable[i] = 0; - } else if(pte & PTE_V){ - panic("freewalk: leaf"); - } - } - kfree((void*)pagetable); -} - -// Free user memory pages, -// then free page table pages. -void -uvmfree(pagetable_t pagetable, uint64 sz) -{ - unmappages(pagetable, 0, sz, 1); - freewalk(pagetable); -} - -// Given a parent process's page table, copy -// its memory into a child's page table. -// Copies both the page table and the -// physical memory. -void -uvmcopy(pagetable_t old, pagetable_t new, uint64 sz) -{ - pte_t *pte; - uint64 pa, i; - uint flags; - char *mem; - - for(i = 0; i < sz; i += PGSIZE){ - if((pte = walk(old, i, 0)) == 0) - panic("copyuvm: pte should exist"); - if((*pte & PTE_V) == 0) - panic("copyuvm: page not present"); - pa = PTE2PA(*pte); - flags = PTE_FLAGS(*pte); - if((mem = kalloc()) == 0) - panic("uvmcopy: kalloc failed"); - memmove(mem, (char*)pa, PGSIZE); - mappages(new, i, PGSIZE, (uint64)mem, flags); - } -} - -// Copy from kernel to user. -// Copy len bytes from src to virtual address dstva in a given page table. -// Return 0 on success, -1 on error. -int -copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len) -{ - uint64 n, va0, pa0; - - while(len > 0){ - va0 = (uint)PGROUNDDOWN(dstva); - pa0 = walkaddr(pagetable, va0); - if(pa0 == 0) - return -1; - n = PGSIZE - (dstva - va0); - if(n > len) - n = len; - memmove((void *)(pa0 + (dstva - va0)), src, n); - - len -= n; - src += n; - dstva = va0 + PGSIZE; - } - return 0; -} - -// Copy from user to kernel. -// Copy len bytes to dst from virtual address srcva in a given page table. -// Return 0 on success, -1 on error. -int -copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len) -{ - uint64 n, va0, pa0; - - while(len > 0){ - va0 = (uint)PGROUNDDOWN(srcva); - pa0 = walkaddr(pagetable, va0); - if(pa0 == 0) - return -1; - n = PGSIZE - (srcva - va0); - if(n > len) - n = len; - memmove(dst, (void *)(pa0 + (srcva - va0)), n); - - len -= n; - dst += n; - srcva = va0 + PGSIZE; - } - return 0; -} - -// Copy a null-terminated string from user to kernel. -// Copy bytes to dst from virtual address srcva in a given page table, -// until a '\0', or max. -// Return 0 on success, -1 on error. -int -copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max) -{ - uint64 n, va0, pa0; - int got_null = 0; - - while(got_null == 0 && max > 0){ - va0 = (uint)PGROUNDDOWN(srcva); - pa0 = walkaddr(pagetable, va0); - if(pa0 == 0) - return -1; - n = PGSIZE - (srcva - va0); - if(n > max) - n = max; - - char *p = (char *) (pa0 + (srcva - va0)); - while(n > 0){ - if(*p == '\0'){ - *dst = '\0'; - got_null = 1; - break; - } else { - *dst = *p; - } - --n; - --max; - p++; - dst++; - } - - srcva = va0 + PGSIZE; - } - if(got_null){ - return 0; - } else { - return -1; - } -} |