diff --git a/arch/x86_64/pmap.c b/arch/x86_64/pmap.c index 9b50eb5..ae6a052 100644 --- a/arch/x86_64/pmap.c +++ b/arch/x86_64/pmap.c @@ -136,6 +136,81 @@ static void delete_pdir(phys_addr_t pd) kfree(pdir); } +kern_status_t pmap_get( + pmap_t pmap, + virt_addr_t pv, + pfn_t *out_pfn, + vm_prot_t *out_prot) +{ + unsigned int pml4t_index = BAD_INDEX, pdpt_index = BAD_INDEX, + pd_index = BAD_INDEX, pt_index = BAD_INDEX; + + pml4t_index = (pv >> 39) & 0x1FF; + pdpt_index = (pv >> 30) & 0x1FF; + pd_index = (pv >> 21) & 0x1FF; + pt_index = (pv >> 12) & 0x1FF; + + /* 1. get PML4T (mandatory) */ + struct pml4t *pml4t = vm_phys_to_virt(ENTRY_TO_PTR(pmap)); + if (!pml4t) { + return KERN_INVALID_ARGUMENT; + } + + /* 2. traverse PML4T, get PDPT (mandatory) */ + struct pdpt *pdpt = NULL; + if (!pml4t->p_entries[pml4t_index]) { + return KERN_NO_ENTRY; + } else { + pdpt = vm_phys_to_virt( + ENTRY_TO_PTR(pml4t->p_entries[pml4t_index])); + } + + /* 3. traverse PDPT, get PDIR (optional, 4K and 2M only) */ + struct pdir *pdir = NULL; + if (!pdpt->p_entries[pdpt_index] + || pdpt->p_pages[pdpt_index] & PTE_PAGESIZE) { + return KERN_NO_ENTRY; + } else { + pdir = vm_phys_to_virt( + ENTRY_TO_PTR(pdpt->p_entries[pdpt_index])); + } + + /* 4. traverse PDIR, get PTAB (optional, 4K only) */ + struct ptab *ptab = NULL; + if (!pdir->p_entries[pd_index] + || pdir->p_pages[pd_index] & PTE_PAGESIZE) { + /* entry is null, or points to a hugepage */ + return KERN_NO_ENTRY; + } else { + ptab = vm_phys_to_virt(ENTRY_TO_PTR(pdir->p_entries[pd_index])); + } + + uint64_t pte = ptab->p_pages[pt_index]; + if (out_pfn) { + *out_pfn = PFN(pte); + } + + if (out_prot) { + if (pte & PTE_PRESENT) { + *out_prot |= VM_PROT_USER; + } + + if (pte & PTE_RW) { + *out_pfn |= (VM_PROT_READ | VM_PROT_WRITE); + } + + if (pte & PTE_USR) { + *out_pfn |= VM_PROT_USER; + } + + if (!(pte & PTE_NX)) { + *out_pfn |= VM_PROT_EXEC; + } + } + + return KERN_OK; +} + static kern_status_t do_pmap_add( pmap_t pmap, virt_addr_t pv, diff --git a/include/kernel/pmap.h b/include/kernel/pmap.h index 7a6137c..f9c46bc 100644 --- a/include/kernel/pmap.h +++ b/include/kernel/pmap.h @@ -56,6 +56,11 @@ extern kern_status_t pmap_handle_fault( virt_addr_t fault_addr, enum pmap_fault_flags flags); +extern kern_status_t pmap_get( + pmap_t pmap, + virt_addr_t p, + pfn_t *out_pfn, + vm_prot_t *out_prot); extern kern_status_t pmap_add( pmap_t pmap, virt_addr_t p,