From: Jack Thomson <jackabt.amazon@gmail.com>
To: maz@kernel.org, oupton@kernel.org, pbonzini@redhat.com
Cc: joey.gouly@arm.com, seiden@linux.ibm.com, suzuki.poulose@arm.com,
yuzenghui@huawei.com, catalin.marinas@arm.com, will@kernel.org,
shuah@kernel.org, corbet@lwn.net, vladimir.murzin@arm.com,
linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org,
isaku.yamahata@intel.com, Jack Thomson <jackabt@amazon.com>
Subject: [PATCH v5 3/5] KVM: selftests: Enable pre_fault_memory_test for arm64
Date: Fri, 12 Jun 2026 17:23:51 +0100 [thread overview]
Message-ID: <20260612162354.73378-4-jackabt.amazon@gmail.com> (raw)
In-Reply-To: <20260612162354.73378-1-jackabt.amazon@gmail.com>
From: Jack Thomson <jackabt@amazon.com>
Enable the pre_fault_memory_test to run on arm64 by making it work with
different guest page sizes and testing multiple guest configurations.
Update the test_assert to compare against the UCALL_EXIT_REASON, for
portability, as arm64 exits with KVM_EXIT_MMIO while x86 uses
KVM_EXIT_IO.
Signed-off-by: Jack Thomson <jackabt@amazon.com>
---
tools/testing/selftests/kvm/Makefile.kvm | 1 +
.../selftests/kvm/pre_fault_memory_test.c | 115 ++++++++++++++----
2 files changed, 92 insertions(+), 24 deletions(-)
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 9118a5a51b89..4609d8f23e38 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -194,6 +194,7 @@ TEST_GEN_PROGS_arm64 += guest_memfd_test
TEST_GEN_PROGS_arm64 += mmu_stress_test
TEST_GEN_PROGS_arm64 += rseq_test
TEST_GEN_PROGS_arm64 += steal_time
+TEST_GEN_PROGS_arm64 += pre_fault_memory_test
TEST_GEN_PROGS_s390 = $(TEST_GEN_PROGS_COMMON)
TEST_GEN_PROGS_s390 += s390/memop
diff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/testing/selftests/kvm/pre_fault_memory_test.c
index fcb57fd034e6..9f5f0d1a5db1 100644
--- a/tools/testing/selftests/kvm/pre_fault_memory_test.c
+++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c
@@ -11,19 +11,29 @@
#include <kvm_util.h>
#include <processor.h>
#include <pthread.h>
+#include <guest_modes.h>
/* Arbitrarily chosen values */
-#define TEST_SIZE (SZ_2M + PAGE_SIZE)
-#define TEST_NPAGES (TEST_SIZE / PAGE_SIZE)
+#define TEST_BASE_SIZE SZ_2M
#define TEST_SLOT 10
+/* Storage of test info to share with guest code */
+struct test_config {
+ u64 page_size;
+ u64 test_size;
+ u64 test_num_pages;
+};
+
+static struct test_config test_config;
+
static void guest_code(u64 base_gva)
{
volatile u64 val __used;
+ struct test_config *config = &test_config;
int i;
- for (i = 0; i < TEST_NPAGES; i++) {
- u64 *src = (u64 *)(base_gva + i * PAGE_SIZE);
+ for (i = 0; i < config->test_num_pages; i++) {
+ u64 *src = (u64 *)(base_gva + i * config->page_size);
val = *src;
}
@@ -56,7 +66,7 @@ static void *delete_slot_worker(void *__data)
cpu_relax();
vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, data->gpa,
- TEST_SLOT, TEST_NPAGES, data->flags);
+ TEST_SLOT, test_config.test_num_pages, data->flags);
return NULL;
}
@@ -149,8 +159,8 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 base_gpa, u64 offset,
/*
* Assert success if prefaulting the entire range should succeed, i.e.
* complete with no bytes remaining. Otherwise prefaulting should have
- * failed due to ENOENT (due to RET_PF_EMULATE for emulated MMIO when
- * no memslot exists).
+ * failed due to ENOENT (no memslot exists for the GPA; on x86 this
+ * surfaces via RET_PF_EMULATE).
*/
if (!expected_left)
TEST_ASSERT_VM_VCPU_IOCTL(!ret, KVM_PRE_FAULT_MEMORY, ret, vcpu->vm);
@@ -159,43 +169,70 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 base_gpa, u64 offset,
KVM_PRE_FAULT_MEMORY, ret, vcpu->vm);
}
-static void __test_pre_fault_memory(unsigned long vm_type, bool private)
+struct test_params {
+ unsigned long vm_type;
+ bool private;
+};
+
+static void __test_pre_fault_memory(enum vm_guest_mode guest_mode, void *arg)
{
- gpa_t gpa, gva, alignment, guest_page_size;
+ gpa_t gpa, gva, alignment, guest_page_size, host_page_size;
+ struct test_params *p = arg;
const struct vm_shape shape = {
- .mode = VM_MODE_DEFAULT,
- .type = vm_type,
+ .mode = guest_mode,
+ .type = p->vm_type,
};
struct kvm_vcpu *vcpu;
struct kvm_run *run;
struct kvm_vm *vm;
struct ucall uc;
+ pr_info("Testing guest mode: %s\n", vm_guest_mode_string(guest_mode));
+
vm = vm_create_shape_with_one_vcpu(shape, &vcpu, guest_code);
- alignment = guest_page_size = vm_guest_mode_params[VM_MODE_DEFAULT].page_size;
- gpa = (vm->max_gfn - TEST_NPAGES) * guest_page_size;
+ guest_page_size = vm_guest_mode_params[guest_mode].page_size;
+ host_page_size = getpagesize();
+
+ test_config.page_size = guest_page_size;
+ test_config.test_size = align_up(TEST_BASE_SIZE + test_config.page_size,
+ host_page_size);
+ test_config.test_num_pages = vm_calc_num_guest_pages(vm->mode, test_config.test_size);
+
+ gpa = (vm->max_gfn - test_config.test_num_pages) * test_config.page_size;
alignment = SZ_2M;
+ alignment = max(alignment, host_page_size);
gpa = align_down(gpa, alignment);
gva = gpa & ((1ULL << (vm->va_bits - 1)) - 1);
- vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, gpa, TEST_SLOT,
- TEST_NPAGES, private ? KVM_MEM_GUEST_MEMFD : 0);
- virt_map(vm, gva, gpa, TEST_NPAGES);
+ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+ gpa, TEST_SLOT, test_config.test_num_pages,
+ p->private ? KVM_MEM_GUEST_MEMFD : 0);
+ virt_map(vm, gva, gpa, test_config.test_num_pages);
- if (private)
- vm_mem_set_private(vm, gpa, TEST_SIZE);
+ if (p->private)
+ vm_mem_set_private(vm, gpa, test_config.test_size);
- pre_fault_memory(vcpu, gpa, 0, SZ_2M, 0, private);
- pre_fault_memory(vcpu, gpa, SZ_2M, PAGE_SIZE * 2, PAGE_SIZE, private);
- pre_fault_memory(vcpu, gpa, TEST_SIZE, PAGE_SIZE, PAGE_SIZE, private);
+ pre_fault_memory(vcpu, gpa, 0, test_config.test_size, 0, p->private);
+ /* Retry the same range after the first prefault attempt. */
+ pre_fault_memory(vcpu, gpa, 0, test_config.test_size, 0, p->private);
+ pre_fault_memory(vcpu, gpa,
+ test_config.test_size - host_page_size,
+ host_page_size * 2, host_page_size, p->private);
+ pre_fault_memory(vcpu, gpa, test_config.test_size,
+ host_page_size, host_page_size, p->private);
vcpu_args_set(vcpu, 1, gva);
+
+ /* Export the shared variables to the guest. */
+ sync_global_to_guest(vm, test_config);
+
vcpu_run(vcpu);
run = vcpu->run;
- TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
- "Wanted KVM_EXIT_IO, got exit reason: %u (%s)",
+ TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
+ "Wanted %s, got exit reason: %u (%s)",
+ exit_reason_str(UCALL_EXIT_REASON),
run->exit_reason, exit_reason_str(run->exit_reason));
switch (get_ucall(vcpu, &uc)) {
@@ -214,16 +251,46 @@ static void __test_pre_fault_memory(unsigned long vm_type, bool private)
static void test_pre_fault_memory(unsigned long vm_type, bool private)
{
+ struct test_params p = {
+ .vm_type = vm_type,
+ .private = private,
+ };
+
if (vm_type && !(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(vm_type))) {
pr_info("Skipping tests for vm_type 0x%lx\n", vm_type);
return;
}
- __test_pre_fault_memory(vm_type, private);
+ for_each_guest_mode(__test_pre_fault_memory, &p);
+}
+
+static void help(char *name)
+{
+ puts("");
+ printf("usage: %s [-h] [-m mode]\n", name);
+ puts("");
+ guest_modes_help();
+ puts("");
}
int main(int argc, char *argv[])
{
+ int opt;
+
+ guest_modes_append_default();
+
+ while ((opt = getopt(argc, argv, "hm:")) != -1) {
+ switch (opt) {
+ case 'm':
+ guest_modes_cmdline(optarg);
+ break;
+ case 'h':
+ default:
+ help(argv[0]);
+ exit(0);
+ }
+ }
+
TEST_REQUIRE(kvm_check_cap(KVM_CAP_PRE_FAULT_MEMORY));
test_pre_fault_memory(0, false);
--
2.43.0
next prev parent reply other threads:[~2026-06-12 16:24 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-12 16:23 [PATCH v5 0/5] KVM: arm64: Add KVM_PRE_FAULT_MEMORY support Jack Thomson
2026-06-12 16:23 ` [PATCH v5 1/5] KVM: arm64: Pass walk flags to kvm_pgtable_get_leaf() Jack Thomson
2026-06-12 16:23 ` [PATCH v5 2/5] KVM: arm64: Add pre_fault_memory implementation Jack Thomson
2026-07-08 15:25 ` Alexandru Elisei
2026-07-10 16:00 ` Alexandru Elisei
2026-07-10 16:03 ` Alexandru Elisei
2026-06-12 16:23 ` Jack Thomson [this message]
2026-06-12 16:23 ` [PATCH v5 4/5] KVM: selftests: Add option for different backing in pre-fault tests Jack Thomson
2026-06-12 16:23 ` [PATCH v5 5/5] KVM: selftests: Add nested pre-fault test for arm64 Jack Thomson
2026-06-12 16:35 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260612162354.73378-4-jackabt.amazon@gmail.com \
--to=jackabt.amazon@gmail.com \
--cc=catalin.marinas@arm.com \
--cc=corbet@lwn.net \
--cc=isaku.yamahata@intel.com \
--cc=jackabt@amazon.com \
--cc=joey.gouly@arm.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=maz@kernel.org \
--cc=oupton@kernel.org \
--cc=pbonzini@redhat.com \
--cc=seiden@linux.ibm.com \
--cc=shuah@kernel.org \
--cc=suzuki.poulose@arm.com \
--cc=vladimir.murzin@arm.com \
--cc=will@kernel.org \
--cc=yuzenghui@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.