From 1494b3d17c958f00258ef6d6efa9d3a33d373db4 Mon Sep 17 00:00:00 2001 From: Yosry Ahmed Date: Tue, 28 Jul 2026 17:42:31 +0000 Subject: [PATCH] KVM: selftests: Support running stress save+restore and #PF test in L2 Extend the stress test to allow running the access+#PF code in L2 instead of L1 by adding proper L1 guest code to bootstrap L2. By default, the test runs in L2 after running in L1 if nested is supported. Assisted-by: Gemini:gemini-3.1-pro Signed-off-by: Yosry Ahmed Link: https://patch.msgid.link/20260728174232.2423257-13-yosry@kernel.org Signed-off-by: Sean Christopherson --- .../kvm/x86/save_restore_pf_stress_test.c | 56 ++++++++++++++++++- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/save_restore_pf_stress_test.c b/tools/testing/selftests/kvm/x86/save_restore_pf_stress_test.c index 4b5accec642c..7418e5fb879b 100644 --- a/tools/testing/selftests/kvm/x86/save_restore_pf_stress_test.c +++ b/tools/testing/selftests/kvm/x86/save_restore_pf_stress_test.c @@ -8,10 +8,13 @@ #include #include #include +#include #include "test_util.h" #include "kvm_util.h" #include "processor.h" +#include "svm_util.h" +#include "vmx.h" #define NR_ITERATIONS 500 @@ -81,6 +84,31 @@ static void guest_access_memory(void *arg) } } +static void l1_svm_code(struct svm_test_data *svm) +{ + generic_svm_setup(svm, guest_access_memory); + run_guest(svm->vmcb, svm->vmcb_gpa); + GUEST_ASSERT(false); +} + +static void l1_vmx_code(struct vmx_pages *vmx) +{ + GUEST_ASSERT(prepare_for_vmx_operation(vmx)); + GUEST_ASSERT(load_vmcs(vmx)); + prepare_vmcs(vmx, guest_access_memory); + + GUEST_ASSERT(!vmlaunch()); + GUEST_ASSERT(false); +} + +static void l1_guest_code(void *test_data) +{ + if (this_cpu_has(X86_FEATURE_SVM)) + l1_svm_code(test_data); + else + l1_vmx_code(test_data); +} + static void *sigusr_thread_fn(void *arg) { pthread_t vcpu_thread = (pthread_t)arg; @@ -108,7 +136,7 @@ static void vcpu_sigusr_ignore(void) sigaction(SIGUSR1, &sa, NULL); } -int main(int argc, char *argv[]) +static void run_test(bool nested) { struct kvm_x86_state *state; int r, i, level; @@ -121,9 +149,17 @@ int main(int argc, char *argv[]) gva_t gva; u64 pte; - vm = vm_create_with_one_vcpu(&vcpu, guest_access_memory); + vm = vm_create_with_one_vcpu(&vcpu, nested ? l1_guest_code : guest_access_memory); vm_install_exception_handler(vm, PF_VECTOR, guest_pf_handler); + if (nested) { + if (kvm_cpu_has(X86_FEATURE_SVM)) + vcpu_alloc_svm(vm, &gva); + else + vcpu_alloc_vmx(vm, &gva); + vcpu_args_set(vcpu, 1, gva); + } + /* Allocate a page and write the pattern to it */ gva = vm_alloc_page(vm); *(u64 *)addr_gva2hva(vm, gva) = PATTERN; @@ -193,10 +229,24 @@ int main(int argc, char *argv[]) sync_global_from_guest(vm, guest_faults); TEST_ASSERT(guest_faults, "No guest page faults triggered"); - pr_info("Guest page faults: %lu\n", guest_faults); + pr_info("Guest page faults%s: %lu\n", nested ? " (in L2)" : "", guest_faults); pthread_cancel(sigusr_thread); pthread_join(sigusr_thread, NULL); kvm_vm_free(vm); +} + +int main(int argc, char *argv[]) +{ + pr_info("Running save+restore stress test...\n"); + run_test(/*nested=*/false); + + if (!kvm_cpu_has(X86_FEATURE_SVM) && !kvm_cpu_has(X86_FEATURE_VMX)) { + pr_info("Nested virtualization not supported, skipping nested test\n"); + return 0; + } + + pr_info("Running save+restore stress test with a nested guest...\n"); + run_test(/*nested=*/true); return 0; }