Skip to content

Commit

Permalink
arch, pt: add va specific page tables map/unmap functions
Browse files Browse the repository at this point in the history
The map_pagetables_va() function maps page tables pertinent to the
virtual address specified by its second parameter into the address
space indicated by its first parameter.
It is a fine-grained, lightweight version of the map_pagetables().

The unmap_pagetables_va() function unmaps page tables pertinent to
the virtual address specified by its second parameter into the
address space indicated by its first parameter.
It is a fine-grained, lightweight version of the unmap_pagetables().
The unmap_pagetables_va() performs the unmapping regardless of the
mapping status of any of the page tables levels.

Signed-off-by: Pawel Wieczorkiewicz <[email protected]>
  • Loading branch information
wipawel committed Nov 21, 2023
1 parent 629d05c commit 86cb29e
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 0 deletions.
146 changes: 146 additions & 0 deletions arch/x86/pagetables.c
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,152 @@ void unmap_pagetables(cr3_t *from_cr3, cr3_t *of_cr3) {
spin_unlock(&vmap_lock);
}

int map_pagetables_va(cr3_t *cr3_ptr, void *va) {
pgentry_t *tab;
int err = -EINVAL;

ASSERT(cr3_ptr);
if (mfn_invalid(cr3_ptr->mfn)) {
warning("CR3: 0x%lx is invalid", cr3_ptr->paddr);
return err;
}

if (!is_canon_va(va)) {
warning("Virtual address 0x%p is not canonical", va);
return err;
}

err = -EFAULT;
spin_lock(&vmap_lock);
tab = _vmap(cr3_ptr, mfn_to_virt_kern(cr3_ptr->mfn), cr3_ptr->mfn, PAGE_ORDER_4K,
L4_PROT, L3_PROT, L2_PROT, L1_PROT);
if (!tab)
goto unlock;

#if defined(__x86_64__)
pml4_t *l4e = l4_table_entry((pml4_t *) tab, va);
if (mfn_invalid(l4e->mfn)) {
err = -ENOENT;
goto unlock;
}

tab = _vmap(cr3_ptr, mfn_to_virt_kern(l4e->mfn), l4e->mfn, PAGE_ORDER_4K, L4_PROT,
L3_PROT, L2_PROT, L1_PROT);
if (!tab)
goto unlock;
#endif

pdpe_t *l3e = l3_table_entry((pdpe_t *) tab, va);
if (mfn_invalid(l3e->mfn)) {
err = -ENOENT;
goto unlock;
}

if (l3e->PS)
goto done;

tab = _vmap(cr3_ptr, mfn_to_virt_kern(l3e->mfn), l3e->mfn, PAGE_ORDER_4K, L4_PROT,
L3_PROT, L2_PROT, L1_PROT);
if (!tab)
goto unlock;

pde_t *l2e = l2_table_entry((pde_t *) tab, va);
if (mfn_invalid(l2e->mfn)) {
err = -ENOENT;
goto unlock;
}

if (l2e->PS)
goto done;

tab = _vmap(cr3_ptr, mfn_to_virt_kern(l2e->mfn), l2e->mfn, PAGE_ORDER_4K, L4_PROT,
L3_PROT, L2_PROT, L1_PROT);
if (!tab)
goto unlock;

done:
err = 0;
unlock:
spin_unlock(&vmap_lock);
return err;
}

int unmap_pagetables_va(cr3_t *cr3_ptr, void *va) {
mfn_t tmp_entry_mfn = virt_to_mfn(_tmp_mapping_entry);
pgentry_t *tab, *tables[PT_LEVELS] = {NULL};
int level = 0;
int err = -EINVAL;

ASSERT(cr3_ptr);
if (mfn_invalid(cr3_ptr->mfn)) {
warning("CR3: 0x%lx is invalid", cr3_ptr->paddr);
return err;
}

if (!is_canon_va(va)) {
warning("Virtual address 0x%p is not canonical", va);
return err;
}

err = -EFAULT;
spin_lock(&vmap_lock);
tab = _vmap(cr3_ptr, mfn_to_virt_kern(cr3_ptr->mfn), cr3_ptr->mfn, PAGE_ORDER_4K,
L4_PROT, L3_PROT, L2_PROT, L1_PROT);
if (!tab)
goto cleanup;
tables[level++] = tab;

#if defined(__x86_64__)
pml4_t *l4e = l4_table_entry((pml4_t *) tab, va);
if (mfn_invalid(l4e->mfn)) {
err = -ENOENT;
goto cleanup;
}

tab = _vmap(cr3_ptr, mfn_to_virt_kern(l4e->mfn), l4e->mfn, PAGE_ORDER_4K, L4_PROT,
L3_PROT, L2_PROT, L1_PROT);
if (!tab)
goto cleanup;
tables[level++] = tab;
#endif

pdpe_t *l3e = l3_table_entry((pdpe_t *) tab, va);
if (mfn_invalid(l3e->mfn)) {
err = -ENOENT;
goto cleanup;
}

if (l3e->PS)
goto done;

tab = _vmap(cr3_ptr, mfn_to_virt_kern(l3e->mfn), l3e->mfn, PAGE_ORDER_4K, L4_PROT,
L3_PROT, L2_PROT, L1_PROT);
if (!tab)
goto cleanup;
tables[level++] = tab;

pde_t *l2e = l2_table_entry((pde_t *) tab, va);
if (mfn_invalid(l2e->mfn)) {
err = -ENOENT;
goto cleanup;
}

if (l2e->PS)
goto done;

/* Do not touch the tmp_mapping entry! */
if (l2e->mfn != tmp_entry_mfn)
tables[level] = mfn_to_virt_kern(l2e->mfn);

done:
err = 0;
cleanup:
for (unsigned i = 0; i < ARRAY_SIZE(tables) && tables[i]; i++)
_vunmap(cr3_ptr, tables[i], NULL, NULL);
spin_unlock(&vmap_lock);
return err;
}

void init_pagetables(void) {
init_cr3(&cr3);
init_cr3(&user_cr3);
Expand Down
2 changes: 2 additions & 0 deletions include/arch/x86/pagetable.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,8 @@ extern frame_t *find_user_va_frame(const void *va);

extern void map_pagetables(cr3_t *to_cr3, cr3_t *from_cr3);
extern void unmap_pagetables(cr3_t *from_cr3, cr3_t *of_cr3);
extern int map_pagetables_va(cr3_t *cr3_ptr, void *va);
extern int unmap_pagetables_va(cr3_t *cr3_ptr, void *va);

#endif /* __ASSEMBLY__ */

Expand Down
5 changes: 5 additions & 0 deletions tests/unittests.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,11 @@ int unit_tests(void *_unused) {
unmap_pagetables(&cr3, NULL);
unmap_pagetables(&cr3, &user_cr3);

map_pagetables_va(&cr3, unit_tests);
pte_t *pte2 = get_pte(unit_tests);
printk("PTE: 0x%lx\n", pte2->entry);
unmap_pagetables_va(&cr3, unit_tests);

task_t *task1, *task2, *task_user1, *task_user1_se, *task_user1_int80, *task_user2,
*task_user3, *task_user4;

Expand Down

0 comments on commit 86cb29e

Please sign in to comment.