[PATCH v2 22/23] KVM: selftests: Hack in support for aligned page allocations

From: Oliver Upton
Date: Tue Feb 13 2024 - 04:50:59 EST


Many of the memory allocations handed off to a GIC ITS require 64K
alignment. One would think that requesting 64K of pages would follow
natural alignment in selftests (much like alloc_pages() in the kernel),
however that is unfortunately not the case.

Add a new helper to allow a caller to decide if they want
naturally-aligned page allocations. Deliberately avoid making this the
default in case this subtly breaks assumptions or memory overheads in
other selftests.

Signed-off-by: Oliver Upton <oliver.upton@xxxxxxxxx>
---
.../selftests/kvm/include/kvm_util_base.h | 2 ++
tools/testing/selftests/kvm/lib/kvm_util.c | 27 ++++++++++++++++---
2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h
index 9e5afc472c14..750638cfa849 100644
--- a/tools/testing/selftests/kvm/include/kvm_util_base.h
+++ b/tools/testing/selftests/kvm/include/kvm_util_base.h
@@ -830,6 +830,8 @@ vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min,
vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
vm_paddr_t paddr_min, uint32_t memslot);
vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm);
+vm_paddr_t vm_phy_pages_alloc_aligned(struct kvm_vm *vm, size_t num,
+ vm_paddr_t paddr_min, uint32_t memslot);

/*
* ____vm_create() does KVM_CREATE_VM and little else. __vm_create() also
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index e066d584c656..60948a004012 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1984,8 +1984,9 @@ const char *exit_reason_str(unsigned int exit_reason)
* and their base address is returned. A TEST_ASSERT failure occurs if
* not enough pages are available at or above paddr_min.
*/
-vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
- vm_paddr_t paddr_min, uint32_t memslot)
+static vm_paddr_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
+ vm_paddr_t paddr_min, uint32_t memslot,
+ bool aligned)
{
struct userspace_mem_region *region;
sparsebit_idx_t pg, base;
@@ -1997,14 +1998,20 @@ vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
" paddr_min: 0x%lx page_size: 0x%x",
paddr_min, vm->page_size);

+ TEST_ASSERT(!aligned || (paddr_min % vm->page_size * num) == 0,
+ "Min physical address isn't naturally aligned.\n"
+ " paddr_min: 0x%lx page_size: 0x%x num: %lu",
+ paddr_min, vm->page_size, num);
+
region = memslot2region(vm, memslot);
base = pg = paddr_min >> vm->page_shift;

do {
for (; pg < base + num; ++pg) {
if (!sparsebit_is_set(region->unused_phy_pages, pg)) {
- base = pg = sparsebit_next_set(region->unused_phy_pages, pg);
- break;
+ do {
+ base = pg = sparsebit_next_set(region->unused_phy_pages, pg);
+ } while (aligned && ((pg % num) != 0));
}
}
} while (pg && pg != base + num);
@@ -2024,6 +2031,12 @@ vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
return base * vm->page_size;
}

+vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
+ vm_paddr_t paddr_min, uint32_t memslot)
+{
+ return __vm_phy_pages_alloc(vm, num, paddr_min, memslot, false);
+}
+
vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min,
uint32_t memslot)
{
@@ -2036,6 +2049,12 @@ vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm)
vm->memslots[MEM_REGION_PT]);
}

+vm_paddr_t vm_phy_pages_alloc_aligned(struct kvm_vm *vm, size_t num,
+ vm_paddr_t paddr_min, uint32_t memslot)
+{
+ return __vm_phy_pages_alloc(vm, num, paddr_min, memslot, true);
+}
+
/*
* Address Guest Virtual to Host Virtual
*
--
2.43.0.687.g38aa6559b0-goog