]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: selftests: Extend vmx_dirty_log_test to cover SVM
authorYosry Ahmed <yosry.ahmed@linux.dev>
Tue, 30 Dec 2025 23:01:47 +0000 (15:01 -0800)
committerSean Christopherson <seanjc@google.com>
Thu, 8 Jan 2026 20:02:16 +0000 (12:02 -0800)
Generalize the code in vmx_dirty_log_test.c by adding SVM-specific L1
code, doing some renaming (e.g. EPT -> TDP), and having setup code for
both SVM and VMX in test_dirty_log().

Signed-off-by: Yosry Ahmed <yosry.ahmed@linux.dev>
Link: https://patch.msgid.link/20251230230150.4150236-19-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
tools/testing/selftests/kvm/Makefile.kvm
tools/testing/selftests/kvm/x86/nested_dirty_log_test.c [moved from tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c with 71% similarity]

index 3789890421bdb10104f13cfef052dbbe21d82a0b..ffbf891b31d317fce544dc5835bb974180eb6677 100644 (file)
@@ -89,6 +89,7 @@ TEST_GEN_PROGS_x86 += x86/kvm_buslock_test
 TEST_GEN_PROGS_x86 += x86/monitor_mwait_test
 TEST_GEN_PROGS_x86 += x86/msrs_test
 TEST_GEN_PROGS_x86 += x86/nested_close_kvm_test
+TEST_GEN_PROGS_x86 += x86/nested_dirty_log_test
 TEST_GEN_PROGS_x86 += x86/nested_emulation_test
 TEST_GEN_PROGS_x86 += x86/nested_exceptions_test
 TEST_GEN_PROGS_x86 += x86/nested_invalid_cr3_test
@@ -115,7 +116,6 @@ TEST_GEN_PROGS_x86 += x86/ucna_injection_test
 TEST_GEN_PROGS_x86 += x86/userspace_io_test
 TEST_GEN_PROGS_x86 += x86/userspace_msr_exit_test
 TEST_GEN_PROGS_x86 += x86/vmx_apic_access_test
-TEST_GEN_PROGS_x86 += x86/vmx_dirty_log_test
 TEST_GEN_PROGS_x86 += x86/vmx_exception_with_invalid_guest_state
 TEST_GEN_PROGS_x86 += x86/vmx_msrs_test
 TEST_GEN_PROGS_x86 += x86/vmx_invalid_nested_guest_state
similarity index 71%
rename from tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c
rename to tools/testing/selftests/kvm/x86/nested_dirty_log_test.c
index 032ab8bf60a44ffe9a50d8f33f2e728c1efcc56d..89d2e86a0db9ecad255b011b57d68e97132196e7 100644 (file)
@@ -12,6 +12,7 @@
 #include "test_util.h"
 #include "kvm_util.h"
 #include "processor.h"
+#include "svm_util.h"
 #include "vmx.h"
 
 /* The memory slot index to track dirty pages */
@@ -25,6 +26,8 @@
 #define NESTED_TEST_MEM1               0xc0001000
 #define NESTED_TEST_MEM2               0xc0002000
 
+#define L2_GUEST_STACK_SIZE 64
+
 static void l2_guest_code(u64 *a, u64 *b)
 {
        READ_ONCE(*a);
@@ -42,20 +45,19 @@ static void l2_guest_code(u64 *a, u64 *b)
        vmcall();
 }
 
-static void l2_guest_code_ept_enabled(void)
+static void l2_guest_code_tdp_enabled(void)
 {
        l2_guest_code((u64 *)NESTED_TEST_MEM1, (u64 *)NESTED_TEST_MEM2);
 }
 
-static void l2_guest_code_ept_disabled(void)
+static void l2_guest_code_tdp_disabled(void)
 {
-       /* Access the same L1 GPAs as l2_guest_code_ept_enabled() */
+       /* Access the same L1 GPAs as l2_guest_code_tdp_enabled() */
        l2_guest_code((u64 *)GUEST_TEST_MEM, (u64 *)GUEST_TEST_MEM);
 }
 
-void l1_guest_code(struct vmx_pages *vmx)
+void l1_vmx_code(struct vmx_pages *vmx)
 {
-#define L2_GUEST_STACK_SIZE 64
        unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
        void *l2_rip;
 
@@ -64,22 +66,49 @@ void l1_guest_code(struct vmx_pages *vmx)
        GUEST_ASSERT(load_vmcs(vmx));
 
        if (vmx->eptp_gpa)
-               l2_rip = l2_guest_code_ept_enabled;
+               l2_rip = l2_guest_code_tdp_enabled;
        else
-               l2_rip = l2_guest_code_ept_disabled;
+               l2_rip = l2_guest_code_tdp_disabled;
 
        prepare_vmcs(vmx, l2_rip, &l2_guest_stack[L2_GUEST_STACK_SIZE]);
 
        GUEST_SYNC(false);
        GUEST_ASSERT(!vmlaunch());
        GUEST_SYNC(false);
-       GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
+       GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_VMCALL);
        GUEST_DONE();
 }
 
-static void test_vmx_dirty_log(bool enable_ept)
+static void l1_svm_code(struct svm_test_data *svm)
 {
-       vm_vaddr_t vmx_pages_gva = 0;
+       unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
+       void *l2_rip;
+
+       if (svm->ncr3_gpa)
+               l2_rip = l2_guest_code_tdp_enabled;
+       else
+               l2_rip = l2_guest_code_tdp_disabled;
+
+       generic_svm_setup(svm, l2_rip, &l2_guest_stack[L2_GUEST_STACK_SIZE]);
+
+       GUEST_SYNC(false);
+       run_guest(svm->vmcb, svm->vmcb_gpa);
+       GUEST_SYNC(false);
+       GUEST_ASSERT_EQ(svm->vmcb->control.exit_code, SVM_EXIT_VMMCALL);
+       GUEST_DONE();
+}
+
+static void l1_guest_code(void *data)
+{
+       if (this_cpu_has(X86_FEATURE_VMX))
+               l1_vmx_code(data);
+       else
+               l1_svm_code(data);
+}
+
+static void test_dirty_log(bool nested_tdp)
+{
+       vm_vaddr_t nested_gva = 0;
        unsigned long *bmap;
        uint64_t *host_test_mem;
 
@@ -88,15 +117,19 @@ static void test_vmx_dirty_log(bool enable_ept)
        struct ucall uc;
        bool done = false;
 
-       pr_info("Nested EPT: %s\n", enable_ept ? "enabled" : "disabled");
+       pr_info("Nested TDP: %s\n", nested_tdp ? "enabled" : "disabled");
 
        /* Create VM */
        vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
-       if (enable_ept)
+       if (nested_tdp)
                vm_enable_tdp(vm);
 
-       vcpu_alloc_vmx(vm, &vmx_pages_gva);
-       vcpu_args_set(vcpu, 1, vmx_pages_gva);
+       if (kvm_cpu_has(X86_FEATURE_VMX))
+               vcpu_alloc_vmx(vm, &nested_gva);
+       else
+               vcpu_alloc_svm(vm, &nested_gva);
+
+       vcpu_args_set(vcpu, 1, nested_gva);
 
        /* Add an extra memory slot for testing dirty logging */
        vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
@@ -115,10 +148,10 @@ static void test_vmx_dirty_log(bool enable_ept)
         * ... pages in the L2 GPA range [0xc0001000, 0xc0003000) will map to
         * 0xc0000000.
         *
-        * When EPT is disabled, the L2 guest code will still access the same L1
-        * GPAs as the EPT enabled case.
+        * When TDP is disabled, the L2 guest code will still access the same L1
+        * GPAs as the TDP enabled case.
         */
-       if (enable_ept) {
+       if (nested_tdp) {
                tdp_identity_map_default_memslots(vm);
                tdp_map(vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, PAGE_SIZE);
                tdp_map(vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, PAGE_SIZE);
@@ -166,12 +199,12 @@ static void test_vmx_dirty_log(bool enable_ept)
 
 int main(int argc, char *argv[])
 {
-       TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
+       TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || kvm_cpu_has(X86_FEATURE_SVM));
 
-       test_vmx_dirty_log(/*enable_ept=*/false);
+       test_dirty_log(/*nested_tdp=*/false);
 
        if (kvm_cpu_has_tdp())
-               test_vmx_dirty_log(/*enable_ept=*/true);
+               test_dirty_log(/*nested_tdp=*/true);
 
        return 0;
 }