summaryrefslogtreecommitdiff
path: root/kernel/cow.c
blob: b3634fc106fe66ae942084d1d2494e4b103d32d5 (plain)
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
// 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;
}