summaryrefslogtreecommitdiff
path: root/vm.c
diff options
context:
space:
mode:
authorRobert Morris <[email protected]>2019-06-11 09:57:14 -0400
committerRobert Morris <[email protected]>2019-06-11 09:57:14 -0400
commit5753553213df8f9de851adb68377db43faecb91f (patch)
tree3b629ff54897fca414146677532cb459a2ed11ba /vm.c
parent91ba81110acd3163f7de3580b677eece0c57f5e7 (diff)
downloadxv6-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.c389
1 files changed, 0 insertions, 389 deletions
diff --git a/vm.c b/vm.c
deleted file mode 100644
index 0ea6bca..0000000
--- a/vm.c
+++ /dev/null
@@ -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;
- }
-}