@@ -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;
@@ -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);
@@ -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);
@@ -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 }
};
@@ -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]
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(-)