From d2e29bf598cca70553ddf54e6f9506b49f5ce420 Mon Sep 17 00:00:00 2001 From: NAKAMURA Gou Date: Mon, 23 Jun 2014 18:04:24 +0900 Subject: [PATCH] add visit_pte_range() refs #21 refs #22 --- arch/x86/kernel/memory.c | 150 +++++++++++++++++++++++++++++++++++++++ lib/include/ihk/mm.h | 11 +++ 2 files changed, 161 insertions(+) diff --git a/arch/x86/kernel/memory.c b/arch/x86/kernel/memory.c index dfacf1a6..97f02658 100644 --- a/arch/x86/kernel/memory.c +++ b/arch/x86/kernel/memory.c @@ -833,6 +833,156 @@ static int split_large_page(pte_t *ptep) return 0; } +struct visit_pte_args { + page_table_t pt; + enum visit_pte_flag flags; + int padding; + pte_visitor_t *funcp; + void *arg; +}; + +static int visit_pte_l1(void *arg0, pte_t *ptep, uintptr_t base, + uintptr_t start, uintptr_t end) +{ + struct visit_pte_args *args = arg0; + + if ((*ptep == PTE_NULL) && (args->flags & VPTEF_SKIP_NULL)) { + return 0; + } + + return (*args->funcp)(args->arg, args->pt, ptep, (void *)base, + PTL1_SIZE); +} + +static int visit_pte_l2(void *arg0, pte_t *ptep, uintptr_t base, + uintptr_t start, uintptr_t end) +{ + int error; + struct visit_pte_args *args = arg0; + struct page_table *pt; + + if ((*ptep == PTE_NULL) && (args->flags & VPTEF_SKIP_NULL)) { + return 0; + } + +#ifdef USE_LARGE_PAGES + if (((*ptep == PTE_NULL) || (*ptep & PFL2_SIZE)) + && (start <= base) + && (((base + PTL2_SIZE) <= end) + || (end == 0))) { + error = (*args->funcp)(args->arg, args->pt, ptep, + (void *)base, PTL2_SIZE); + if (error != -E2BIG) { + return error; + } + } + + if (*ptep & PFL2_SIZE) { + ekprintf("visit_pte_l2:split large page\n"); + return -ENOMEM; + } +#endif + + if (*ptep == PTE_NULL) { + pt = __alloc_new_pt(IHK_MC_AP_NOWAIT); + if (!pt) { + return -ENOMEM; + } + *ptep = virt_to_phys(pt) | PFL2_PDIR_ATTR; + } + else { + pt = phys_to_virt(*ptep & PT_PHYSMASK); + } + + error = walk_pte_l1(pt, base, start, end, &visit_pte_l1, arg0); + return error; +} + +static int visit_pte_l3(void *arg0, pte_t *ptep, uintptr_t base, + uintptr_t start, uintptr_t end) +{ + int error; + struct visit_pte_args *args = arg0; + struct page_table *pt; + + if ((*ptep == PTE_NULL) && (args->flags & VPTEF_SKIP_NULL)) { + return 0; + } + +#ifdef USE_LARGE_PAGES + if (((*ptep == PTE_NULL) || (*ptep & PFL3_SIZE)) + && (start <= base) + && (((base + PTL3_SIZE) <= end) + || (end == 0))) { + error = (*args->funcp)(args->arg, args->pt, ptep, + (void *)base, PTL3_SIZE); + if (error != -E2BIG) { + return error; + } + } + + if (*ptep & PFL3_SIZE) { + ekprintf("visit_pte_l3:split large page\n"); + return -ENOMEM; + } +#endif + + if (*ptep == PTE_NULL) { + pt = __alloc_new_pt(IHK_MC_AP_NOWAIT); + if (!pt) { + return -ENOMEM; + } + *ptep = virt_to_phys(pt) | PFL3_PDIR_ATTR; + } + else { + pt = phys_to_virt(*ptep & PT_PHYSMASK); + } + + error = walk_pte_l2(pt, base, start, end, &visit_pte_l2, arg0); + return error; +} + +static int visit_pte_l4(void *arg0, pte_t *ptep, uintptr_t base, + uintptr_t start, uintptr_t end) +{ + int error; + struct visit_pte_args *args = arg0; + struct page_table *pt; + + if ((*ptep == PTE_NULL) && (args->flags & VPTEF_SKIP_NULL)) { + return 0; + } + + if (*ptep == PTE_NULL) { + pt = __alloc_new_pt(IHK_MC_AP_NOWAIT); + if (!pt) { + return -ENOMEM; + } + *ptep = virt_to_phys(pt) | PFL4_PDIR_ATTR; + } + else { + pt = phys_to_virt(*ptep & PT_PHYSMASK); + } + + error = walk_pte_l3(pt, base, start, end, &visit_pte_l3, arg0); + return error; +} + +int visit_pte_range(page_table_t pt, void *start0, void *end0, + enum visit_pte_flag flags, pte_visitor_t *funcp, void *arg) +{ + const uintptr_t start = (uintptr_t)start0; + const uintptr_t end = (uintptr_t)end0; + struct visit_pte_args args; + + args.pt = pt; + args.flags = flags; + args.funcp = funcp; + args.arg = arg; + + return walk_pte_l4(pt, 0, start, end, &visit_pte_l4, &args); +} + struct clear_range_args { int free_physical; uint8_t padding[4]; diff --git a/lib/include/ihk/mm.h b/lib/include/ihk/mm.h index a5bb214a..c8970f5a 100644 --- a/lib/include/ihk/mm.h +++ b/lib/include/ihk/mm.h @@ -47,6 +47,12 @@ enum ihk_mc_pt_prepare_flag { IHK_MC_PT_LAST_LEVEL, }; +enum visit_pte_flag { + VPTEF_SKIP_NULL = 0x0001, /* skip null PTEs */ + + VPTEF_DEFAULT = 0, +}; + struct ihk_mc_memory_area { unsigned long start; unsigned long size; @@ -123,6 +129,11 @@ int ihk_mc_pt_set_pte(page_table_t pt, pte_t *ptep, size_t pgsize, uintptr_t phy int ihk_mc_pt_prepare_map(page_table_t pt, void *virt, unsigned long size, enum ihk_mc_pt_prepare_flag); +typedef int pte_visitor_t(void *arg, page_table_t pt, pte_t *ptep, + void *pgaddr, size_t pgsize); +int visit_pte_range(page_table_t pt, void *start, void *end, + enum visit_pte_flag flags, pte_visitor_t *funcp, void *arg); + struct page_table *ihk_mc_pt_create(enum ihk_mc_ap_flag ap_flag); /* XXX: proper use of struct page_table and page_table_t is unknown */ void ihk_mc_pt_destroy(struct page_table *pt);