summaryrefslogtreecommitdiff
path: root/kernel/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/vm.c')
-rw-r--r--kernel/vm.c27
1 files changed, 20 insertions, 7 deletions
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;