pmap: add pmap_get to retrieve existing page table entries
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user