diff options
Diffstat (limited to 'src/kernel/mm/vm.cc')
| -rw-r--r-- | src/kernel/mm/vm.cc | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/src/kernel/mm/vm.cc b/src/kernel/mm/vm.cc index 29e9eb7..41d1aa1 100644 --- a/src/kernel/mm/vm.cc +++ b/src/kernel/mm/vm.cc @@ -261,6 +261,8 @@ namespace VM return 0; } + int handle_cow_fault(uint64 *pagetable, uint64 va); + int copyout(uint64 *pagetable, uint64 dstva, char *src, uint64 len) { uint64 n, va0, pa0; @@ -273,6 +275,17 @@ namespace VM if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0) return -1; + // Note: Maybe a bug + if (*pte & PTE_COW) + { + if (handle_cow_fault(pagetable, va0) < 0) + return -1; + // Re-walk because handle_cow_fault replaced the page mapping + pte = walk(pagetable, va0, 0); + if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0) + return -1; + } + pa0 = PTE2PA(*pte); n = PGSIZE - (dstva - va0); if (n > len) @@ -419,4 +432,20 @@ namespace VM sfence_vma(); Drivers::uart_puts("[Boot] MMU ENABLED! Using virtual addresses.\n"); } + + uint64 walkaddr(uint64 *pagetable, uint64 va) + { + uint64 *pte; + uint64 pa; + + if (va >= MAXVA) + return 0; + + pte = walk(pagetable, va, 0); + if (pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0) + return 0; + + pa = PTE2PA(*pte); + return pa; + } }
\ No newline at end of file |
