summaryrefslogtreecommitdiff
path: root/kernel/cow.c
diff options
context:
space:
mode:
authorMole Shang <[email protected]>2024-02-19 14:10:32 +0800
committerMole Shang <[email protected]>2024-02-19 14:36:21 +0800
commitd86118fc80267649b4791c8c0c72ebd60edf1ef2 (patch)
treeb792b617b4df80a5803a9c1164d0e3fdfe9cfe31 /kernel/cow.c
parentb20ef9d0210fd7d9403acde1857eed1b9880c0b2 (diff)
parent0cf897cbe05fd8485162619db4244f4159d0eb52 (diff)
downloadxv6-labs-d86118fc80267649b4791c8c0c72ebd60edf1ef2.tar.gz
xv6-labs-d86118fc80267649b4791c8c0c72ebd60edf1ef2.tar.bz2
xv6-labs-d86118fc80267649b4791c8c0c72ebd60edf1ef2.zip
Merge branch 'fs' into mmap
Conflicts: .gitignore Makefile conf/lab.mk kernel/defs.h user/user.h
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;
+}