aboutsummaryrefslogtreecommitdiff
path: root/kernel/vm/pagefault.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/vm/pagefault.c')
-rw-r--r--kernel/vm/pagefault.c75
1 files changed, 74 insertions, 1 deletions
diff --git a/kernel/vm/pagefault.c b/kernel/vm/pagefault.c
index 764ce85..2e0c92d 100644
--- a/kernel/vm/pagefault.c
+++ b/kernel/vm/pagefault.c
@@ -49,5 +49,78 @@ void handle_pagefault(uintptr_t vaddr, uintptr_t cause)
{
dbg(DBG_VM, "vaddr = 0x%p (0x%p), cause = %lu\n", (void *)vaddr,
PAGE_ALIGN_DOWN(vaddr), cause);
- NOT_YET_IMPLEMENTED("VM: handle_pagefault");
+ // NOT_YET_IMPLEMENTED("VM: handle_pagefault");
+
+ // 1) Find the vmarea that contains vaddr, if it exists.
+ // check that the vaddr is valid
+ if (vaddr < USER_MEM_LOW || vaddr > USER_MEM_HIGH)
+ {
+ do_exit(EFAULT);
+ }
+ // lookup the vmarea for this addr
+ vmarea_t *vma = vmmap_lookup(curproc->p_vmmap, ADDR_TO_PN(vaddr));
+ if (vma == NULL)
+ {
+ do_exit(EFAULT);
+ }
+
+ // 2) Check the vmarea's protections (see the vmarea_t struct) against the 'cause'
+ // error out if the fault has cause write and we don't have write permission in the area
+ if ((cause & FAULT_WRITE) && !(vma->vma_prot & PROT_WRITE))
+ {
+ do_exit(EFAULT);
+ }
+ // error out if the fault has cause exec and we don't have exec permission in the area
+ if ((cause & FAULT_EXEC) && !(vma->vma_prot & PROT_EXEC))
+ {
+ do_exit(EFAULT);
+ }
+ // error out if we don't have read permission in the area
+ if (!(vma->vma_prot & PROT_READ))
+ {
+ do_exit(EFAULT);
+ }
+ // error our if we don't have any permission in the area
+ if (vma->vma_prot == PROT_NONE)
+ {
+ do_exit(EFAULT);
+ }
+
+ // 3) Obtain the corresponding pframe from the vmarea's mobj.
+ pframe_t *pf;
+ mobj_lock(vma->vma_obj);
+ int ret = mobj_get_pframe(
+ vma->vma_obj,
+ vma->vma_off + (ADDR_TO_PN(vaddr) - vma->vma_start),
+ cause & FAULT_WRITE ? 1 : 0,
+ &pf
+ );
+ mobj_unlock(vma->vma_obj);
+ if (ret < 0)
+ {
+ do_exit(EFAULT);
+ }
+
+ // 4) Finally, set up a call to pt_map to insert a new mapping into the appropriate pagetable
+ int pdflags = PT_PRESENT | PT_WRITE | PT_USER;
+ int ptflags = PT_PRESENT | PT_USER;
+ if (cause & FAULT_WRITE)
+ {
+ ptflags |= PT_WRITE;
+ }
+
+ int err = pt_map(
+ curproc->p_pml4,
+ pt_virt_to_phys((uintptr_t) pf->pf_addr),
+ (uintptr_t) PAGE_ALIGN_DOWN(vaddr),
+ pdflags,
+ ptflags
+ );
+ if (err < 0)
+ {
+ do_exit(EFAULT);
+ }
+
+ // 5) Flush the TLB
+ tlb_flush((uintptr_t) PAGE_ALIGN_DOWN(vaddr));
}