summaryrefslogtreecommitdiff
path: root/kernel/cow.c
diff options
context:
space:
mode:
authorMole Shang <[email protected]>2024-02-11 17:51:28 +0800
committerMole Shang <[email protected]>2024-02-11 17:51:28 +0800
commit4a6593f1a6f666c618d303a4858c4c6d31b41c63 (patch)
tree29d5302aec4e0f3c34a70baa9fb83c0bb35dbf7c /kernel/cow.c
parent2fe04bc8faa4bf737a86c36a8017473e84814f3b (diff)
downloadxv6-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.c30
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;
+}