diff --git a/arch/x86/pagetables.c b/arch/x86/pagetables.c index 3c0bd2b9..ed2af3bf 100644 --- a/arch/x86/pagetables.c +++ b/arch/x86/pagetables.c @@ -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; diff --git a/include/arch/x86/pagetable.h b/include/arch/x86/pagetable.h index 0ca155cb..405d7973 100644 --- a/include/arch/x86/pagetable.h +++ b/include/arch/x86/pagetable.h @@ -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 */ diff --git a/include/mm/pmm.h b/include/mm/pmm.h index ae62f955..79f193d9 100644 --- a/include/mm/pmm.h +++ b/include/mm/pmm.h @@ -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); @@ -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); } diff --git a/mm/pmm.c b/mm/pmm.c index 10f0c605..6158614a 100644 --- a/mm/pmm.c +++ b/mm/pmm.c @@ -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)) @@ -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); @@ -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) @@ -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); diff --git a/tests/unittests.c b/tests/unittests.c index 82d114b8..28e9b3cf 100644 --- a/tests/unittests.c +++ b/tests/unittests.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -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));