diff mbox series

[kvm-unit-tests,9/9] svm: add test for pause filter and threshold

Message ID 20220322205613.250925-10-mlevitsk@redhat.com (mailing list archive)
State New, archived
Headers show
Series KVM unit tests for SVM options features | expand

Commit Message

Maxim Levitsky March 22, 2022, 8:56 p.m. UTC
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
---
 lib/x86/processor.h |  3 +-
 x86/svm.c           | 11 +++++++
 x86/svm.h           |  5 +++-
 x86/svm_tests.c     | 70 +++++++++++++++++++++++++++++++++++++++++++++
 x86/unittests.cfg   |  7 ++++-
 5 files changed, 93 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index b3fe924..9a0dad6 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -190,10 +190,11 @@  static inline bool is_intel(void)
 #define	X86_FEATURE_LBRV		(CPUID(0x8000000A, 0, EDX, 1))
 #define	X86_FEATURE_NRIPS		(CPUID(0x8000000A, 0, EDX, 3))
 #define X86_FEATURE_TSCRATEMSR  (CPUID(0x8000000A, 0, EDX, 4))
+#define X86_FEATURE_PAUSEFILTER     (CPUID(0x8000000A, 0, EDX, 10))
+#define X86_FEATURE_PFTHRESHOLD     (CPUID(0x8000000A, 0, EDX, 12))
 #define	X86_FEATURE_VGIF		(CPUID(0x8000000A, 0, EDX, 16))
 
 
-
 static inline bool this_cpu_has(u64 feature)
 {
 	u32 input_eax = feature >> 32;
diff --git a/x86/svm.c b/x86/svm.c
index 460fc59..f6896f0 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -80,6 +80,17 @@  bool tsc_scale_supported(void)
     return this_cpu_has(X86_FEATURE_TSCRATEMSR);
 }
 
+bool pause_filter_supported(void)
+{
+    return this_cpu_has(X86_FEATURE_PAUSEFILTER);
+}
+
+bool pause_threshold_supported(void)
+{
+    return this_cpu_has(X86_FEATURE_PFTHRESHOLD);
+}
+
+
 void default_prepare(struct svm_test *test)
 {
 	vmcb_ident(vmcb);
diff --git a/x86/svm.h b/x86/svm.h
index d92c4f2..e93822b 100644
--- a/x86/svm.h
+++ b/x86/svm.h
@@ -75,7 +75,8 @@  struct __attribute__ ((__packed__)) vmcb_control_area {
 	u16 intercept_dr_write;
 	u32 intercept_exceptions;
 	u64 intercept;
-	u8 reserved_1[42];
+	u8 reserved_1[40];
+	u16 pause_filter_thresh;
 	u16 pause_filter_count;
 	u64 iopm_base_pa;
 	u64 msrpm_base_pa;
@@ -411,6 +412,8 @@  bool default_supported(void);
 bool vgif_supported(void);
 bool lbrv_supported(void);
 bool tsc_scale_supported(void);
+bool pause_filter_supported(void);
+bool pause_threshold_supported(void);
 void default_prepare(struct svm_test *test);
 void default_prepare_gif_clear(struct svm_test *test);
 bool default_finished(struct svm_test *test);
diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index e7bd788..6a9b03b 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -3030,6 +3030,75 @@  static bool vgif_check(struct svm_test *test)
     return get_test_stage(test) == 3;
 }
 
+
+static int pause_test_counter;
+static int wait_counter;
+
+static void pause_filter_test_guest_main(struct svm_test *test)
+{
+    int i;
+    for (i = 0 ; i < pause_test_counter ; i++)
+        pause();
+
+    if (!wait_counter)
+        return;
+
+    for (i = 0; i < wait_counter; i++)
+        ;
+
+    for (i = 0 ; i < pause_test_counter ; i++)
+        pause();
+
+}
+
+static void pause_filter_run_test(int pause_iterations, int filter_value, int wait_iterations, int threshold)
+{
+    test_set_guest(pause_filter_test_guest_main);
+
+    pause_test_counter = pause_iterations;
+    wait_counter = wait_iterations;
+
+    vmcb->control.pause_filter_count = filter_value;
+    vmcb->control.pause_filter_thresh = threshold;
+    svm_vmrun();
+
+    if (filter_value <= pause_iterations || wait_iterations < threshold)
+        report(vmcb->control.exit_code == SVM_EXIT_PAUSE, "expected PAUSE vmexit");
+    else
+        report(vmcb->control.exit_code == SVM_EXIT_VMMCALL, "no expected PAUSE vmexit");
+}
+
+static void pause_filter_test(void)
+{
+    if (!pause_filter_supported()) {
+            report_skip("PAUSE filter not supported in the guest");
+            return;
+    }
+
+    vmcb->control.intercept |= (1 << INTERCEPT_PAUSE);
+
+    // filter count more that pause count - no VMexit
+    pause_filter_run_test(10, 9, 0, 0);
+
+    // filter count smaller pause count - no VMexit
+    pause_filter_run_test(20, 21, 0, 0);
+
+
+    if (pause_threshold_supported()) {
+        // filter count smaller pause count - no VMexit +  large enough threshold
+        // so that filter counter resets
+        pause_filter_run_test(20, 21, 1000, 10);
+
+        // filter count smaller pause count - no VMexit +  small threshold
+        // so that filter doesn't reset
+        pause_filter_run_test(20, 21, 10, 1000);
+    } else {
+        report_skip("PAUSE threshold not supported in the guest");
+        return;
+    }
+}
+
+
 static int of_test_counter;
 
 static void guest_test_of_handler(struct ex_regs *r)
@@ -3698,5 +3767,6 @@  struct svm_test svm_tests[] = {
     TEST(svm_intr_intercept_mix_nmi),
     TEST(svm_intr_intercept_mix_smi),
     TEST(svm_tsc_scale_test),
+    TEST(pause_filter_test),
     { NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 };
diff --git a/x86/unittests.cfg b/x86/unittests.cfg
index 89ff949..c277088 100644
--- a/x86/unittests.cfg
+++ b/x86/unittests.cfg
@@ -238,7 +238,12 @@  arch = x86_64
 [svm]
 file = svm.flat
 smp = 2
-extra_params = -cpu max,+svm -m 4g
+extra_params = -cpu max,+svm -m 4g -append "-pause_filter_test"
+arch = x86_64
+
+[svm_pause_filter]
+file = svm.flat
+extra_params = -cpu max,+svm -overcommit cpu-pm=on -m 4g -append pause_filter_test
 arch = x86_64
 
 [taskswitch]