cowtest fixed and try to finish usertests
This commit is contained in:
@ -9,6 +9,12 @@
|
|||||||
#include "riscv.h"
|
#include "riscv.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
|
||||||
|
#define NPAGE ((PHYSTOP - KERNBASE) / PGSIZE)
|
||||||
|
static int refcnt[NPAGE];
|
||||||
|
static inline int pa2idx(void *pa) {
|
||||||
|
return ((uint64)pa - KERNBASE) / PGSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
void freerange(void *pa_start, void *pa_end);
|
void freerange(void *pa_start, void *pa_end);
|
||||||
|
|
||||||
extern char end[]; // first address after kernel.
|
extern char end[]; // first address after kernel.
|
||||||
@ -23,10 +29,25 @@ struct {
|
|||||||
struct run *freelist;
|
struct run *freelist;
|
||||||
} kmem;
|
} kmem;
|
||||||
|
|
||||||
|
void incref(void *pa) {
|
||||||
|
int idx = pa2idx(pa);
|
||||||
|
refcnt[idx]++;
|
||||||
|
}
|
||||||
|
void decref(void *pa) {
|
||||||
|
int idx = pa2idx(pa);
|
||||||
|
refcnt[idx]--;
|
||||||
|
}
|
||||||
|
int getref(void *pa) {
|
||||||
|
int idx = pa2idx(pa);
|
||||||
|
return refcnt[idx];
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kinit()
|
kinit()
|
||||||
{
|
{
|
||||||
initlock(&kmem.lock, "kmem");
|
initlock(&kmem.lock, "kmem");
|
||||||
|
for(int i = 0; i < NPAGE; i++)
|
||||||
|
refcnt[i] = 0;
|
||||||
freerange(end, (void*)PHYSTOP);
|
freerange(end, (void*)PHYSTOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +72,16 @@ kfree(void *pa)
|
|||||||
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
|
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
|
||||||
panic("kfree");
|
panic("kfree");
|
||||||
|
|
||||||
|
int idx = pa2idx(pa);
|
||||||
|
acquire(&kmem.lock);
|
||||||
|
if(refcnt[idx] > 1) {
|
||||||
|
refcnt[idx]--;
|
||||||
|
release(&kmem.lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
refcnt[idx] = 0;
|
||||||
|
release(&kmem.lock);
|
||||||
|
|
||||||
// Fill with junk to catch dangling refs.
|
// Fill with junk to catch dangling refs.
|
||||||
memset(pa, 1, PGSIZE);
|
memset(pa, 1, PGSIZE);
|
||||||
|
|
||||||
@ -76,7 +107,10 @@ kalloc(void)
|
|||||||
kmem.freelist = r->next;
|
kmem.freelist = r->next;
|
||||||
release(&kmem.lock);
|
release(&kmem.lock);
|
||||||
|
|
||||||
if(r)
|
if(r) {
|
||||||
memset((char*)r, 5, PGSIZE); // fill with junk
|
memset((char*)r, 5, PGSIZE); // fill with junk
|
||||||
|
int idx = pa2idx((void*)r);
|
||||||
|
refcnt[idx] = 1;
|
||||||
|
}
|
||||||
return (void*)r;
|
return (void*)r;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -362,6 +362,7 @@ typedef uint64 *pagetable_t; // 512 PTEs
|
|||||||
#define PTE_W (1L << 2)
|
#define PTE_W (1L << 2)
|
||||||
#define PTE_X (1L << 3)
|
#define PTE_X (1L << 3)
|
||||||
#define PTE_U (1L << 4) // user can access
|
#define PTE_U (1L << 4) // user can access
|
||||||
|
#define PTE_COW (1L << 8) // 使用RSW位标记COW
|
||||||
|
|
||||||
// shift a physical address to the right place for a PTE.
|
// shift a physical address to the right place for a PTE.
|
||||||
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
|
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
|
||||||
|
|||||||
@ -16,6 +16,9 @@ void kernelvec();
|
|||||||
|
|
||||||
extern int devintr();
|
extern int devintr();
|
||||||
|
|
||||||
|
typedef uint64 pte_t;
|
||||||
|
pte_t *walk(pagetable_t pagetable, uint64 va, int alloc);
|
||||||
|
|
||||||
void
|
void
|
||||||
trapinit(void)
|
trapinit(void)
|
||||||
{
|
{
|
||||||
@ -50,7 +53,10 @@ usertrap(void)
|
|||||||
// save user program counter.
|
// save user program counter.
|
||||||
p->trapframe->epc = r_sepc();
|
p->trapframe->epc = r_sepc();
|
||||||
|
|
||||||
if(r_scause() == 8){
|
uint64 scause = r_scause();
|
||||||
|
uint64 stval = r_stval();
|
||||||
|
|
||||||
|
if(scause == 8){
|
||||||
// system call
|
// system call
|
||||||
|
|
||||||
if(killed(p))
|
if(killed(p))
|
||||||
@ -67,6 +73,23 @@ usertrap(void)
|
|||||||
syscall();
|
syscall();
|
||||||
} else if((which_dev = devintr()) != 0){
|
} else if((which_dev = devintr()) != 0){
|
||||||
// ok
|
// ok
|
||||||
|
} else if((scause == 15 || scause == 13)) { // store/load page fault
|
||||||
|
pte_t *pte = walk(p->pagetable, stval, 0);
|
||||||
|
if(pte && (*pte & PTE_V) && (*pte & PTE_U) && (*pte & PTE_COW)) {
|
||||||
|
uint64 pa = PTE2PA(*pte);
|
||||||
|
char *mem = kalloc();
|
||||||
|
if(mem == 0) {
|
||||||
|
setkilled(p);
|
||||||
|
} else {
|
||||||
|
memmove(mem, (void*)pa, PGSIZE);
|
||||||
|
*pte = PA2PTE(mem) | (PTE_FLAGS(*pte) & ~PTE_COW) | PTE_W;
|
||||||
|
kfree((void*)pa);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("usertrap(): unexpected scause 0x%lx pid=%d\n", scause, p->pid);
|
||||||
|
printf(" sepc=0x%lx stval=0x%lx\n", r_sepc(), r_stval());
|
||||||
|
setkilled(p);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("usertrap(): unexpected scause 0x%lx pid=%d\n", r_scause(), p->pid);
|
printf("usertrap(): unexpected scause 0x%lx pid=%d\n", r_scause(), p->pid);
|
||||||
printf(" sepc=0x%lx stval=0x%lx\n", r_sepc(), r_stval());
|
printf(" sepc=0x%lx stval=0x%lx\n", r_sepc(), r_stval());
|
||||||
@ -216,3 +239,6 @@ devintr()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kfree(void *pa);
|
||||||
|
void *kalloc(void);
|
||||||
|
|
||||||
|
|||||||
48
kernel/vm.c
48
kernel/vm.c
@ -6,6 +6,10 @@
|
|||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
|
||||||
|
void incref(void *pa);
|
||||||
|
void kfree(void *pa);
|
||||||
|
void *kalloc(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the kernel's page table.
|
* the kernel's page table.
|
||||||
*/
|
*/
|
||||||
@ -315,7 +319,7 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
|||||||
pte_t *pte;
|
pte_t *pte;
|
||||||
uint64 pa, i;
|
uint64 pa, i;
|
||||||
uint flags;
|
uint flags;
|
||||||
char *mem;
|
// char *mem;
|
||||||
|
|
||||||
for(i = 0; i < sz; i += PGSIZE){
|
for(i = 0; i < sz; i += PGSIZE){
|
||||||
if((pte = walk(old, i, 0)) == 0)
|
if((pte = walk(old, i, 0)) == 0)
|
||||||
@ -324,19 +328,21 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
|
|||||||
panic("uvmcopy: page not present");
|
panic("uvmcopy: page not present");
|
||||||
pa = PTE2PA(*pte);
|
pa = PTE2PA(*pte);
|
||||||
flags = PTE_FLAGS(*pte);
|
flags = PTE_FLAGS(*pte);
|
||||||
if((mem = kalloc()) == 0)
|
// 如果是可写页,去掉PTE_W,设置PTE_COW
|
||||||
goto err;
|
if(flags & PTE_W) {
|
||||||
memmove(mem, (char*)pa, PGSIZE);
|
flags = (flags & ~PTE_W) | PTE_COW;
|
||||||
if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
|
*pte = PA2PTE(pa) | flags;
|
||||||
kfree(mem);
|
|
||||||
goto err;
|
|
||||||
}
|
}
|
||||||
|
// 子页表同样映射,权限同上
|
||||||
|
if(mappages(new, i, PGSIZE, pa, flags) != 0){
|
||||||
|
// kfree(mem); // 不再分配新页
|
||||||
|
uvmunmap(new, 0, i / PGSIZE, 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// 增加物理页引用计数
|
||||||
|
incref((void*)pa);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
|
||||||
uvmunmap(new, 0, i / PGSIZE, 1);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark a PTE invalid for user access.
|
// mark a PTE invalid for user access.
|
||||||
@ -366,9 +372,25 @@ copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
|
|||||||
if(va0 >= MAXVA)
|
if(va0 >= MAXVA)
|
||||||
return -1;
|
return -1;
|
||||||
pte = walk(pagetable, va0, 0);
|
pte = walk(pagetable, va0, 0);
|
||||||
if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0 ||
|
if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
|
||||||
(*pte & PTE_W) == 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
if((*pte & PTE_W) == 0) {
|
||||||
|
// COW处理
|
||||||
|
if((*pte & PTE_COW) != 0) {
|
||||||
|
pa0 = PTE2PA(*pte);
|
||||||
|
char *mem = kalloc();
|
||||||
|
if(mem == 0)
|
||||||
|
return -1;
|
||||||
|
memmove(mem, (void*)pa0, PGSIZE);
|
||||||
|
// 更新PTE为新物理页,可写,去掉COW
|
||||||
|
*pte = PA2PTE(mem) | PTE_FLAGS(*pte) | PTE_W;
|
||||||
|
*pte &= ~PTE_COW;
|
||||||
|
// 原物理页引用计数减一
|
||||||
|
kfree((void*)pa0);
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
pa0 = PTE2PA(*pte);
|
pa0 = PTE2PA(*pte);
|
||||||
n = PGSIZE - (dstva - va0);
|
n = PGSIZE - (dstva - va0);
|
||||||
if(n > len)
|
if(n > len)
|
||||||
|
|||||||
Reference in New Issue
Block a user