Skip to content

Commit

Permalink
arch,pt: add page tables map/unmap functions
Browse files Browse the repository at this point in the history
The map_pagetables() function maps all page tables specified in
its second parameter into the address space specified by its
first parameter. If second parameter is NULL, the current address
space page tables are mapped. Only page table frames are being
mapped.
After mapping a helper function family: get_pte(), get_pde(),
... can be used without causing exceptions.

The unmap_pagetables() function unmaps all page tables specified
in its second parameter from address space indicated by its first
parameter. If second parameter is NULL, the current address space
page tables are being unmapped.

Signed-off-by: Pawel Wieczorkiewicz <[email protected]>
  • Loading branch information
wipawel committed Nov 21, 2023
1 parent 53163e2 commit 629d05c
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 0 deletions.
92 changes: 92 additions & 0 deletions arch/x86/pagetables.c
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,98 @@ static inline void init_cr3(cr3_t *cr3_ptr) {
cr3_ptr->mfn = MFN_INVALID;
}

static inline bool is_huge_page_level(int level) {
if (level == 2)
return true;
#if defined(__i386__)
return false;
#else
return level == 3;
#endif
}

static void map_pagetable(cr3_t *cr3_ptr, mfn_t table, int level) {
void *va = mfn_to_virt_kern(table);
pte_t *pt;

pt = _vmap(cr3_ptr, va, table, PAGE_ORDER_4K, L4_PROT, L3_PROT, L2_PROT, L1_PROT);
BUG_ON(!pt);

for (int i = 0; i < level_to_entries(level) && level > 1; i++) {
if (mfn_invalid(pt[i].mfn))
continue;

/* Do not map 2MB/1GB large pages */
if (!is_huge_page_level(level) || !is_pgentry_huge(pt[i].entry))
map_pagetable(cr3_ptr, pt[i].mfn, level - 1);
}
}

void map_pagetables(cr3_t *to_cr3, cr3_t *from_cr3) {
ASSERT(to_cr3);
if (mfn_invalid(to_cr3->mfn)) {
warning("Target CR3: 0x%lx is invalid", to_cr3->paddr);
return;
}

if (!from_cr3)
from_cr3 = to_cr3;
else if (mfn_invalid(from_cr3->mfn)) {
warning("Source CR3: 0x%lx is invalid", from_cr3->paddr);
return;
}

dprintk("Mapping all page tables of CR3: 0x%lx to CR3: 0x%lx\n", from_cr3->paddr,
to_cr3->paddr);

spin_lock(&vmap_lock);
/* Assume PML4 is not mapped */
map_pagetable(to_cr3, from_cr3->mfn, PT_LEVELS);
spin_unlock(&vmap_lock);
}

static void unmap_pagetable(cr3_t *cr3_ptr, mfn_t table, int level) {
mfn_t tmp_entry_mfn = virt_to_mfn(_tmp_mapping_entry);
pte_t *pt = mfn_to_virt_kern(table);

for (int i = 0; i < level_to_entries(level) && level > 1; i++) {
if (mfn_invalid(pt[i].mfn))
continue;

/* Do not touch the tmp_mapping entry! */
if (pt[i].mfn == tmp_entry_mfn)
continue;

/* Do not touch 2MB/1GB large pages */
if (!is_huge_page_level(level) || !is_pgentry_huge(pt[i].entry))
unmap_pagetable(cr3_ptr, pt[i].mfn, level - 1);
}
_vunmap(cr3_ptr, pt, NULL, NULL);
}

void unmap_pagetables(cr3_t *from_cr3, cr3_t *of_cr3) {
ASSERT(from_cr3);
if (mfn_invalid(from_cr3->mfn)) {
warning("Target CR3: 0x%lx is invalid", from_cr3->paddr);
return;
}

if (!of_cr3)
of_cr3 = from_cr3;
else if (mfn_invalid(of_cr3->mfn)) {
warning("Source CR3: 0x%lx is invalid", of_cr3->paddr);
return;
}

dprintk("Unmapping all page tables of CR3: 0x%lx from CR3: 0x%lx\n", of_cr3->paddr,
from_cr3->paddr);

spin_lock(&vmap_lock);
/* Assume PML4 is mapped */
unmap_pagetable(from_cr3, of_cr3->mfn, PT_LEVELS);
spin_unlock(&vmap_lock);
}

void init_pagetables(void) {
init_cr3(&cr3);
init_cr3(&user_cr3);
Expand Down
11 changes: 11 additions & 0 deletions include/arch/x86/pagetable.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,14 @@ static inline void set_pgentry(pgentry_t *e, mfn_t mfn, unsigned long flags) {
barrier();
}

static inline bool is_pgentry_huge(pgentry_t e) {
return !!(e & _PAGE_PSE);
}

static inline bool is_pgentry_present(pgentry_t e) {
return !!(e & _PAGE_PRESENT);
}

/* External declarations */

extern pte_t l1_pt_entries1[L1_PT_ENTRIES];
Expand All @@ -307,6 +315,9 @@ extern int get_user_va_mfn_order(void *va, mfn_t *mfn, unsigned int *order);
extern frame_t *find_kern_va_frame(const void *va);
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);

#endif /* __ASSEMBLY__ */

#endif /* KTF_PAGETABLE_H */
7 changes: 7 additions & 0 deletions tests/unittests.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,13 @@ int unit_tests(void *_unused) {
cpu_freq_expect("Prototyp Amazing Foo One @ 1GHz", 1000000000);
cpu_freq_expect("Prototyp Amazing Foo Two @ 1.00GHz", 1000000000);

map_pagetables(&cr3, NULL);
map_pagetables(&cr3, &user_cr3);
pte_t *pte = get_pte(unit_tests);
printk("PTE: 0x%lx\n", pte->entry);
unmap_pagetables(&cr3, NULL);
unmap_pagetables(&cr3, &user_cr3);

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

Expand Down

0 comments on commit 629d05c

Please sign in to comment.