From: Jan Kiszka <[email protected]> Refactor page_alloc to page_alloc_internal which accepts an additional constraint for its allocation: align_mask. The allocated region will now have its start page chosen so that page_number & align_mask is zero. If no alignment is required, align_mask just needs to be set to 0. This is what page_alloc exploits.
However, the new function page_alloc_aligned is introduces to return page regions aligned according to their size (num pages will be aligned by num * PAGE_SIZE). This implied that num needs to be a power of two. This will be used on the AArch64 port of Jailhouse to support physical address ranges from 40 to 44 bits: in these configurations, the initial page table level may take up multiple consecutive pages. Based on patch by Antonios Motakis. Signed-off-by: Jan Kiszka <[email protected]> --- hypervisor/arch/arm/include/asm/paging.h | 3 +- hypervisor/arch/x86/include/asm/paging.h | 3 +- hypervisor/include/jailhouse/paging.h | 1 + hypervisor/paging.c | 60 ++++++++++++++++++++++++++------ 4 files changed, 55 insertions(+), 12 deletions(-) diff --git a/hypervisor/arch/arm/include/asm/paging.h b/hypervisor/arch/arm/include/asm/paging.h index 0372b2c..28ba3e0 100644 --- a/hypervisor/arch/arm/include/asm/paging.h +++ b/hypervisor/arch/arm/include/asm/paging.h @@ -18,7 +18,8 @@ #include <asm/processor.h> #include <asm/sysregs.h> -#define PAGE_SIZE 4096 +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) #define PAGE_MASK ~(PAGE_SIZE - 1) #define PAGE_OFFS_MASK (PAGE_SIZE - 1) diff --git a/hypervisor/arch/x86/include/asm/paging.h b/hypervisor/arch/x86/include/asm/paging.h index e90077b..064790c 100644 --- a/hypervisor/arch/x86/include/asm/paging.h +++ b/hypervisor/arch/x86/include/asm/paging.h @@ -16,7 +16,8 @@ #include <jailhouse/types.h> #include <asm/processor.h> -#define PAGE_SIZE 4096 +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) #define PAGE_MASK ~(PAGE_SIZE - 1) #define PAGE_OFFS_MASK (PAGE_SIZE - 1) diff --git a/hypervisor/include/jailhouse/paging.h b/hypervisor/include/jailhouse/paging.h index 27286f0..6c2555f 100644 --- a/hypervisor/include/jailhouse/paging.h +++ b/hypervisor/include/jailhouse/paging.h @@ -183,6 +183,7 @@ extern struct paging_structures hv_paging_structs; unsigned long paging_get_phys_invalid(pt_entry_t pte, unsigned long virt); void *page_alloc(struct page_pool *pool, unsigned int num); +void *page_alloc_aligned(struct page_pool *pool, unsigned int num); void page_free(struct page_pool *pool, void *first_page, unsigned int num); /** diff --git a/hypervisor/paging.c b/hypervisor/paging.c index f24d56c..1f22887 100644 --- a/hypervisor/paging.c +++ b/hypervisor/paging.c @@ -89,32 +89,44 @@ static unsigned long find_next_free_page(struct page_pool *pool, /** * Allocate consecutive pages from the specified pool. - * @param pool Page pool to allocate from. - * @param num Number of pages. + * @param pool Page pool to allocate from. + * @param num Number of pages. + * @param align_mask Choose start so that start_page_no & align_mask == 0. * * @return Pointer to first page or NULL if allocation failed. * * @see page_free */ -void *page_alloc(struct page_pool *pool, unsigned int num) +static void *page_alloc_internal(struct page_pool *pool, unsigned int num, + unsigned long align_mask) { - unsigned long start, last, next; + /* The pool itself might not be aligned as required. */ + unsigned long aligned_start = + ((unsigned long)pool->base_address >> PAGE_SHIFT) & align_mask; + unsigned long next = aligned_start; + unsigned long start, last; unsigned int allocated; - start = find_next_free_page(pool, 0); +restart: + /* Forward the search start to the next aligned page. */ + if ((next - aligned_start) & align_mask) + next += num - ((next - aligned_start) & align_mask); + + start = next = find_next_free_page(pool, next); if (start == INVALID_PAGE_NR || num == 0) return NULL; -restart: + /* Enforce alignment (none of align_mask is 0). */ + if ((start - aligned_start) & align_mask) + goto restart; + for (allocated = 1, last = start; allocated < num; allocated++, last = next) { next = find_next_free_page(pool, last + 1); if (next == INVALID_PAGE_NR) return NULL; - if (next != last + 1) { - start = next; - goto restart; - } + if (next != last + 1) + goto restart; /* not consecutive */ } for (allocated = 0; allocated < num; allocated++) @@ -126,6 +138,34 @@ restart: } /** + * Allocate consecutive pages from the specified pool. + * @param pool Page pool to allocate from. + * @param num Number of pages. + * + * @return Pointer to first page or NULL if allocation failed. + * + * @see page_free + */ +void *page_alloc(struct page_pool *pool, unsigned int num) +{ + return page_alloc_internal(pool, num, 0); +} + +/** + * Allocate aligned consecutive pages from the specified pool. + * @param pool Page pool to allocate from. + * @param num Number of pages. Num needs to be a power of 2. + * + * @return Pointer to first page or NULL if allocation failed. + * + * @see page_free + */ +void *page_alloc_aligned(struct page_pool *pool, unsigned int num) +{ + return page_alloc_internal(pool, num, num - 1); +} + +/** * Release pages to the specified pool. * @param pool Page pool to release to. * @param page Address of first page. -- 2.8.0.rc3 -- You received this message because you are subscribed to the Google Groups "Jailhouse" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
