Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions arch/x86/pagetables.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,106 @@ int vunmap_user(void *va, mfn_t *mfn, unsigned int *order) {
return err;
}

static int get_va_mfn_order(const cr3_t *cr3_ptr, const void *va, mfn_t *mfn,
unsigned int *order) {
unsigned int _order;
mfn_t _mfn;
pgentry_t *tab;

ASSERT(mfn || order);
if (mfn_invalid(cr3_ptr->mfn))
return -EINVAL;

tab = tmp_map_mfn(cr3_ptr->mfn);
#if defined(__x86_64__)
pml4_t *l4e = l4_table_entry((pml4_t *) tab, va);
if (mfn_invalid(l4e->mfn) || !l4e->P)
return -ENOENT;

tab = tmp_map_mfn(l4e->mfn);
#endif
pdpe_t *l3e = l3_table_entry((pdpe_t *) tab, va);
if (mfn_invalid(l3e->mfn) || !l3e->P)
return -ENOENT;

if (l3e->PS) {
_mfn = l3e->mfn;
_order = PAGE_ORDER_1G;
goto done;
}

tab = tmp_map_mfn(l3e->mfn);
pde_t *l2e = l2_table_entry((pde_t *) tab, va);
if (mfn_invalid(l2e->mfn) || !l2e->P)
return -ENOENT;

if (l2e->PS) {
_mfn = l2e->mfn;
_order = PAGE_ORDER_2M;
goto done;
}

tab = tmp_map_mfn(l2e->mfn);
pte_t *l1e = l1_table_entry((pte_t *) tab, va);
if (mfn_invalid(l1e->mfn) || !l1e->P)
return -ENOENT;

_mfn = l1e->mfn;
_order = PAGE_ORDER_4K;

done:
if (mfn)
*mfn = _mfn;
if (order)
*order = _order;

return 0;
}

int get_kern_va_mfn_order(void *va, mfn_t *mfn, unsigned int *order) {
int err;

dprintk("%s: va: 0x%p (cr3: 0x%p)\n", __func__, va, &cr3);

spin_lock(&vmap_lock);
err = get_va_mfn_order(&cr3, va, mfn, order);
spin_unlock(&vmap_lock);

return err;
}

int get_user_va_mfn_order(void *va, mfn_t *mfn, unsigned int *order) {
int err;

dprintk("%s: va: 0x%p (cr3: 0x%p)\n", __func__, va, &user_cr3);

spin_lock(&vmap_lock);
err = get_va_mfn_order(&user_cr3, va, mfn, order);
spin_unlock(&vmap_lock);

return err;
}

static frame_t *find_va_frame(const cr3_t *cr3_ptr, const void *va) {
unsigned int order;
mfn_t mfn;
int err;

spin_lock(&vmap_lock);
err = get_va_mfn_order(cr3_ptr, va, &mfn, &order);
spin_unlock(&vmap_lock);

return err ? NULL : find_mfn_frame(mfn, order);
}

frame_t *find_kern_va_frame(const void *va) {
return find_va_frame(&cr3, va);
}

frame_t *find_user_va_frame(const void *va) {
return find_va_frame(&user_cr3, va);
}

static inline void init_cr3(cr3_t *cr3_ptr) {
memset(cr3_ptr, 0, sizeof(*cr3_ptr));
cr3_ptr->mfn = MFN_INVALID;
Expand Down
6 changes: 6 additions & 0 deletions include/arch/x86/pagetable.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,12 @@ extern void dump_pagetables(cr3_t *cr3_ptr);
extern void dump_kern_pagetable_va(void *va);
extern void dump_user_pagetable_va(void *va);

extern int get_kern_va_mfn_order(void *va, mfn_t *mfn, unsigned int *order);
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);

#endif /* __ASSEMBLY__ */

#endif /* KTF_PAGETABLE_H */
17 changes: 17 additions & 0 deletions include/mm/pmm.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ extern frame_t *get_free_frames(unsigned int order);
extern void put_free_frames(mfn_t mfn, unsigned int order);
extern void reclaim_frame(mfn_t mfn, unsigned int order);

extern frame_t *find_free_mfn_frame(mfn_t mfn, unsigned int order);
extern frame_t *find_busy_mfn_frame(mfn_t mfn, unsigned int order);
extern frame_t *find_mfn_frame(mfn_t mfn, unsigned int order);
extern frame_t *find_free_paddr_frame(paddr_t paddr);
extern frame_t *find_busy_paddr_frame(paddr_t paddr);
extern frame_t *find_paddr_frame(paddr_t paddr);

extern void map_used_memory(void);
extern void map_frames_array(void);

Expand All @@ -100,6 +107,16 @@ static inline frame_t *get_first_frame(list_head_t *frames, unsigned int order)
return list_first_entry(&frames[order], frame_t, list);
}

static inline bool frame_has_paddr(const frame_t *frame, paddr_t pa) {
if (!frame)
return false;

paddr_t start_pa = mfn_to_paddr(frame->mfn);
paddr_t end_pa = start_pa + ORDER_TO_SIZE(frame->order) - 1;

return pa >= start_pa && pa <= end_pa;
}

static inline frame_t *get_free_frame(void) {
return get_free_frames(PAGE_ORDER_4K);
}
Expand Down
85 changes: 81 additions & 4 deletions mm/pmm.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ static inline bool return_frame(frame_t *frame) {
return false;
}

static frame_t *find_mfn_frame(list_head_t *list, mfn_t mfn, unsigned int order) {
static frame_t *_find_mfn_frame(list_head_t *list, mfn_t mfn, unsigned int order) {
frame_t *frame;

if (!has_frames(list, order))
Expand All @@ -421,6 +421,83 @@ static frame_t *find_mfn_frame(list_head_t *list, mfn_t mfn, unsigned int order)
return NULL;
}

frame_t *find_free_mfn_frame(mfn_t mfn, unsigned int order) {
frame_t *frame;

spin_lock(&lock);
frame = _find_mfn_frame(free_frames, mfn, order);
spin_unlock(&lock);

return frame;
}

frame_t *find_busy_mfn_frame(mfn_t mfn, unsigned int order) {
frame_t *frame;

spin_lock(&lock);
frame = _find_mfn_frame(busy_frames, mfn, order);
spin_unlock(&lock);

return frame;
}

frame_t *find_mfn_frame(mfn_t mfn, unsigned int order) {
frame_t *frame;

spin_lock(&lock);
frame = _find_mfn_frame(busy_frames, mfn, order);
if (!frame)
frame = _find_mfn_frame(free_frames, mfn, order);
spin_unlock(&lock);

return frame;
}

static frame_t *_find_paddr_frame(list_head_t *list, paddr_t paddr) {
frame_t *frame;

for_each_order (order) {
list_for_each_entry (frame, &list[order], list) {
if (frame_has_paddr(frame, paddr))
return frame;
}
}

return NULL;
}

frame_t *find_free_paddr_frame(paddr_t paddr) {
frame_t *frame;

spin_lock(&lock);
frame = _find_paddr_frame(free_frames, paddr);
spin_unlock(&lock);

return frame;
}

frame_t *find_busy_paddr_frame(paddr_t paddr) {
frame_t *frame;

spin_lock(&lock);
frame = _find_paddr_frame(busy_frames, paddr);
spin_unlock(&lock);

return frame;
}

frame_t *find_paddr_frame(paddr_t paddr) {
frame_t *frame;

spin_lock(&lock);
frame = _find_paddr_frame(busy_frames, paddr);
if (!frame)
frame = _find_paddr_frame(free_frames, paddr);
spin_unlock(&lock);

return frame;
}

static frame_t *find_larger_frame(list_head_t *list, unsigned int order) {
while (++order <= MAX_PAGE_ORDER) {
frame_t *frame = get_first_frame(list, order);
Expand Down Expand Up @@ -491,13 +568,13 @@ static void merge_frames(frame_t *first) {

if (FIRST_FRAME_SIBLING(first->mfn, first->order + 1)) {
mfn_t next_mfn = NEXT_MFN(first->mfn, first->order);
second = find_mfn_frame(free_frames, next_mfn, first->order);
second = _find_mfn_frame(free_frames, next_mfn, first->order);
}
else {
/* Second frame sibling */
mfn_t prev_mfn = PREV_MFN(first->mfn, first->order);
second = first;
first = find_mfn_frame(free_frames, prev_mfn, first->order);
first = _find_mfn_frame(free_frames, prev_mfn, first->order);
}

if (!first || !second)
Expand Down Expand Up @@ -547,7 +624,7 @@ void put_free_frames(mfn_t mfn, unsigned int order) {
ASSERT(order <= MAX_PAGE_ORDER);

spin_lock(&lock);
frame = find_mfn_frame(busy_frames, mfn, order);
frame = _find_mfn_frame(busy_frames, mfn, order);
if (!frame) {
warning("PMM: unable to find frame: %lx, order: %u among busy frames", mfn,
order);
Expand Down
8 changes: 6 additions & 2 deletions tests/unittests.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <console.h>
#include <cpuid.h>
#include <ktf.h>
#include <pagetable.h>
#include <real_mode.h>
#include <sched.h>
#include <string.h>
Expand Down Expand Up @@ -203,13 +204,16 @@ int unit_tests(void *_unused) {
task_user3 = new_user_task("test3 user", test_user_task_func3, NULL);
task_user4 = new_user_task("test4 user", test_user_task_func4, NULL);

vmap_4k(HIGH_USER_PTR + 0x1000, get_free_frame()->mfn, L1_PROT);
frame_t *frame = get_free_frame();
vmap_4k(HIGH_USER_PTR + 0x1000, frame->mfn, L1_PROT);
memset(HIGH_USER_PTR + 0x1000, 0, 0x1000);
vmap_user_4k(HIGH_USER_PTR, get_free_frame()->mfn, L1_PROT_USER);
vmap_user_4k(HIGH_USER_PTR, frame->mfn, L1_PROT_USER);

/* Be sure that we can still touch this vmap despite the user vmap. */
BUG_ON(*(unsigned long *) (HIGH_USER_PTR + 0x1000) != 0);

BUG_ON(frame != find_kern_va_frame(HIGH_USER_PTR + 0x1000));

set_task_repeat(task1, 10);
schedule_task(task1, get_bsp_cpu());
schedule_task(task2, get_cpu(1));
Expand Down