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.

Reply via email to