1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| diff --git a/kernel/defs.h b/kernel/defs.h index 4b9bbc0..569839c 100644
@@ -171,6 +171,7 @@ uint64 walkaddr(pagetable_t, uint64); int copyout(pagetable_t, uint64, char *, uint64); int copyin(pagetable_t, char *, uint64, uint64); int copyinstr(pagetable_t, char *, uint64, uint64); +uint64 lazyalloc(struct proc *p, uint64 va); // plic.c void plicinit(void); diff --git a/kernel/sysproc.c b/kernel/sysproc.c index e8bcda9..51abbca 100644
@@ -47,8 +47,10 @@ sys_sbrk(void) if(argint(0, &n) < 0) return -1; addr = myproc()->sz; - if(growproc(n) < 0) - return -1; + myproc()->sz += n; + if(n < 0){ // decrease process's memory + uvmdealloc(myproc()->pagetable, addr, myproc()->sz); + } return addr; } diff --git a/kernel/trap.c b/kernel/trap.c index a63249e..4487ce5 100644
@@ -67,6 +67,11 @@ usertrap(void) syscall(); } else if((which_dev = devintr()) != 0){ // ok + } else if(r_scause() == 13 || r_scause() == 15){ // respond to a page fault from user space + uint64 va = r_stval(); + if(lazyalloc(p, PGROUNDDOWN(va)) == 0){ + p->killed = 1; + } } else { printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid); printf(" sepc=%p stval=%p\n", r_sepc(), r_stval()); diff --git a/kernel/vm.c b/kernel/vm.c index bccb405..87d0718 100644
@@ -5,6 +5,8 @@ #include "riscv.h" #include "defs.h" #include "fs.h" +#include "spinlock.h" +#include "proc.h" /* * the kernel's page table. @@ -101,12 +103,10 @@ walkaddr(pagetable_t pagetable, uint64 va) return 0; pte = walk(pagetable, va, 0); - if(pte == 0) - return 0; - if((*pte & PTE_V) == 0) - return 0; - if((*pte & PTE_U) == 0) - return 0; + if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0){ + if((pa = lazyalloc(myproc(), PGROUNDDOWN(va))) == 0) return 0; + return pa; + } pa = PTE2PA(*pte); return pa; } @@ -181,9 +181,9 @@ uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free) for(a = va; a < va + npages*PGSIZE; a += PGSIZE){ if((pte = walk(pagetable, a, 0)) == 0) - panic("uvmunmap: walk"); + continue; if((*pte & PTE_V) == 0) - panic("uvmunmap: not mapped"); + continue; if(PTE_FLAGS(*pte) == PTE_V) panic("uvmunmap: not a leaf"); if(do_free){ @@ -315,9 +315,9 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz) for(i = 0; i < sz; i += PGSIZE){ if((pte = walk(old, i, 0)) == 0) - panic("uvmcopy: pte should exist"); + continue; // if pte don't exist, no need panic if((*pte & PTE_V) == 0) - panic("uvmcopy: page not present"); + continue; // if page invalid, no need panic pa = PTE2PA(*pte); flags = PTE_FLAGS(*pte); if((mem = kalloc()) == 0) @@ -440,3 +440,24 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max) return -1; } } +uint64 +lazyalloc(struct proc *p, uint64 va) +{ + // 1. page-faults on a virtual memory address higher than any allocated, kill this process + // 2. faults on the invalid page below the user stack, kill this process + if(va >= p->sz || va < p->trapframe->sp){ + return 0; + } + char *mem = kalloc(); + if(mem == 0){ // no free physical page to allocate, kill the process + uvmdealloc(p->pagetable, va, va + PGSIZE); + return 0; + } + memset(mem, 0, PGSIZE); + if(mappages(p->pagetable, va, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0){ + kfree(mem); + uvmdealloc(p->pagetable, va, va + PGSIZE); + return 0; + } + return (uint64)mem; +}
|