diff options
| author | Mole Shang <135e2@135e2.dev> | 2024-02-11 17:51:28 +0800 | 
|---|---|---|
| committer | Mole Shang <135e2@135e2.dev> | 2024-02-11 17:51:28 +0800 | 
| commit | 4a6593f1a6f666c618d303a4858c4c6d31b41c63 (patch) | |
| tree | 29d5302aec4e0f3c34a70baa9fb83c0bb35dbf7c /kernel | |
| parent | 2fe04bc8faa4bf737a86c36a8017473e84814f3b (diff) | |
| download | xv6-labs-4a6593f1a6f666c618d303a4858c4c6d31b41c63.tar.gz xv6-labs-4a6593f1a6f666c618d303a4858c4c6d31b41c63.tar.bz2 xv6-labs-4a6593f1a6f666c618d303a4858c4c6d31b41c63.zip | |
lab cow: finishcow
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/cow.c | 30 | ||||
| -rw-r--r-- | kernel/defs.h | 5 | ||||
| -rw-r--r-- | kernel/kalloc.c | 43 | ||||
| -rw-r--r-- | kernel/riscv.h | 1 | ||||
| -rw-r--r-- | kernel/sysproc.c | 2 | ||||
| -rw-r--r-- | kernel/trap.c | 7 | ||||
| -rw-r--r-- | kernel/vm.c | 27 | 
7 files changed, 106 insertions, 9 deletions
| diff --git a/kernel/cow.c b/kernel/cow.c new file mode 100644 index 0000000..b3634fc --- /dev/null +++ b/kernel/cow.c @@ -0,0 +1,30 @@ +// COW pagefault handler +#include "types.h" +#include "riscv.h" +#include "defs.h" + +int +cow_handler(pagetable_t pagetable, uint64 va) +{ +  // you can't really write to rediculous pointers +  if(va >= MAXVA || PGROUNDDOWN(va) == 0) +    return -1; +  pte_t *pte = walk(pagetable, va, 0); +  if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0) +    return -1; +  if(*pte & PTE_C){ +    uint64 pa_orig = PTE2PA(*pte); +    uint64 pa_new = (uint64)kalloc(); +    if(pa_new == 0){ +      printf("cow pagefault: kalloc failed\n"); +      return -1; +    } +    // copy the page and add write permission +    memmove((void*)pa_new, (void*)pa_orig, PGSIZE); +    uint64 flags = (PTE_FLAGS(*pte) | PTE_W) & ~PTE_C; +    *pte = PA2PTE(pa_new) | flags; +    kfree((void*)pa_orig); +  } else if ((*pte & PTE_W) == 0) +    return -1; +  return 0; +} diff --git a/kernel/defs.h b/kernel/defs.h index 04a0276..870c984 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -23,6 +23,9 @@ void            consoleinit(void);  void            consoleintr(int);  void            consputc(int); +// cow.c +int             cow_handler(pagetable_t, uint64); +  // exec.c  int             exec(char*, char**); @@ -61,6 +64,8 @@ void            ramdiskintr(void);  void            ramdiskrw(struct buf*);  // kalloc.c +int             refcnt_inc(uint64); +int             refcnt_dec(uint64);  void*           kalloc(void);  void            kfree(void *);  void            kinit(void); diff --git a/kernel/kalloc.c b/kernel/kalloc.c index c2fdb86..581f0f6 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.c @@ -23,10 +23,41 @@ struct {    struct run *freelist;  } kmem; +int phypg_refcnt[PHYSTOP/PGSIZE]; + +// Increase the refcnt +int +refcnt_inc(uint64 pa) +{ +  acquire(&kmem.lock); +  int *prefcnt = &phypg_refcnt[pa/PGSIZE]; +  if(pa > PHYSTOP || *prefcnt < 1) +    panic("increase refcnt"); +  (*prefcnt)++; +  release(&kmem.lock); +  return *prefcnt; +} + +// Decrease the refcnt +int +refcnt_dec(uint64 pa) +{ +  acquire(&kmem.lock); +  int *prefcnt = &phypg_refcnt[pa/PGSIZE]; +  if(pa > PHYSTOP || *prefcnt < 1) +    panic("decrease refcnt"); +  (*prefcnt)--; +  release(&kmem.lock); +  return *prefcnt; +} +  void  kinit()  {    initlock(&kmem.lock, "kmem"); +  // init all refcnt to 1, which would later be freed to 0 by kfree() +  for(uint64 p = PGROUNDUP((uint64)end); p + PGSIZE <= PHYSTOP; p += PGSIZE) +    phypg_refcnt[p/PGSIZE] = 1;    freerange(end, (void*)PHYSTOP);  } @@ -51,6 +82,12 @@ kfree(void *pa)    if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)      panic("kfree"); +  refcnt_dec((uint64)pa); + +  if(phypg_refcnt[(uint64)pa/PGSIZE] > 0) +    // We still have refs to this phy page, do not actually free it +    return; +    // Fill with junk to catch dangling refs.    memset(pa, 1, PGSIZE); @@ -72,8 +109,12 @@ kalloc(void)    acquire(&kmem.lock);    r = kmem.freelist; -  if(r) +  if(r){ +    if(phypg_refcnt[(uint64)r/PGSIZE]) +      panic("kalloc: invalid refcnt"); +    phypg_refcnt[(uint64)r/PGSIZE] = 1;      kmem.freelist = r->next; +  }    release(&kmem.lock);    if(r) diff --git a/kernel/riscv.h b/kernel/riscv.h index 5ede50a..7d6eb6e 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -353,6 +353,7 @@ typedef uint64 *pagetable_t; // 512 PTEs  #define PTE_X (1L << 3)  #define PTE_U (1L << 4) // user can access  #define PTE_A (1L << 6) // riscv access bit                       +#define PTE_C (1L << 8) // RSW low bit, use it to mark whether a page is COW  // shift a physical address to the right place for a PTE.  #define PA2PTE(pa) ((((uint64)pa) >> 12) << 10) diff --git a/kernel/sysproc.c b/kernel/sysproc.c index fac1d83..715a511 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -66,7 +66,7 @@ sys_sleep(void)      sleep(&ticks, &tickslock);    } -  backtrace(); +  // backtrace();    release(&tickslock);    return 0; diff --git a/kernel/trap.c b/kernel/trap.c index eb8009f..bd3b100 100644 --- a/kernel/trap.c +++ b/kernel/trap.c @@ -73,9 +73,16 @@ usertrap(void)      syscall();    } else if((which_dev = devintr()) != 0){      // ok +  } else if(r_scause() == 13 || r_scause() == 15){ +    // deal with page fault +    uint64 va = r_stval(); +    if(cow_handler(p->pagetable, va) < 0) +      goto err;    } else {      printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);      printf("            sepc=%p stval=%p\n", r_sepc(), r_stval()); +  err: +    printf("killing the process...\n");      setkilled(p);    } diff --git a/kernel/vm.c b/kernel/vm.c index 9c17fe7..11f9e0a 100644 --- a/kernel/vm.c +++ b/kernel/vm.c @@ -315,20 +315,26 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)    pte_t *pte;    uint64 pa, i;    uint flags; -  char *mem; +  // char *mem;    for(i = 0; i < sz; i += PGSIZE){      if((pte = walk(old, i, 0)) == 0)        panic("uvmcopy: pte should exist");      if((*pte & PTE_V) == 0)        panic("uvmcopy: page not present"); -    pa = PTE2PA(*pte); -    flags = PTE_FLAGS(*pte); +    // do not do the actual copy, just increase the refcnt and mark pages readonly COW +    /*      if((mem = kalloc()) == 0)        goto err;      memmove(mem, (char*)pa, PGSIZE); -    if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){ -      kfree(mem); +    */ +    *pte &= ~PTE_W; +    *pte |= PTE_C; +    pa = PTE2PA(*pte); +    refcnt_inc(pa); +    flags = PTE_FLAGS(*pte); +    if(mappages(new, i, PGSIZE, (uint64)pa, flags) != 0){ +      // kfree(mem);        goto err;      }    } @@ -359,17 +365,24 @@ int  copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)  {    uint64 n, va0, pa0; -  pte_t *pte; +  // pte_t *pte;    while(len > 0){      va0 = PGROUNDDOWN(dstva); -    if(va0 >= MAXVA) + +    if(cow_handler(pagetable, va0) < 0)        return -1; +     +    /*      pte = walk(pagetable, va0, 0);      if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0 ||         (*pte & PTE_W) == 0)        return -1;      pa0 = PTE2PA(*pte); +    */ +    pa0 = walkaddr(pagetable, va0); +    if(pa0 == 0) +      return -1;      n = PGSIZE - (dstva - va0);      if(n > len)        n = len; | 
