diff options
author | Mole Shang <[email protected]> | 2024-02-11 17:51:28 +0800 |
---|---|---|
committer | Mole Shang <[email protected]> | 2024-02-11 17:51:28 +0800 |
commit | 4a6593f1a6f666c618d303a4858c4c6d31b41c63 (patch) | |
tree | 29d5302aec4e0f3c34a70baa9fb83c0bb35dbf7c /kernel/cow.c | |
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/cow.c')
-rw-r--r-- | kernel/cow.c | 30 |
1 files changed, 30 insertions, 0 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; +} |