77
88#include "kvm_util.h"
99#include "processor.h"
10+ #include "kselftest.h"
1011
1112#define CPUID_MWAIT (1u << 3)
1213
1314enum monitor_mwait_testcases {
1415 MWAIT_QUIRK_DISABLED = BIT (0 ),
1516 MISC_ENABLES_QUIRK_DISABLED = BIT (1 ),
1617 MWAIT_DISABLED = BIT (2 ),
18+ CPUID_DISABLED = BIT (3 ),
19+ TEST_MAX = CPUID_DISABLED * 2 - 1 ,
1720};
1821
1922/*
@@ -35,11 +38,19 @@ do { \
3538 testcase, vector); \
3639} while (0)
3740
38- static void guest_monitor_wait (int testcase )
41+ static void guest_monitor_wait (void * arg )
3942{
43+ int testcase = (int ) (long ) arg ;
4044 u8 vector ;
4145
42- GUEST_SYNC (testcase );
46+ u64 val = rdmsr (MSR_IA32_MISC_ENABLE ) & ~MSR_IA32_MISC_ENABLE_MWAIT ;
47+ if (!(testcase & MWAIT_DISABLED ))
48+ val |= MSR_IA32_MISC_ENABLE_MWAIT ;
49+ wrmsr (MSR_IA32_MISC_ENABLE , val );
50+
51+ __GUEST_ASSERT (this_cpu_has (X86_FEATURE_MWAIT ) == !(testcase & MWAIT_DISABLED ),
52+ "Expected CPUID.MWAIT %s\n" ,
53+ (testcase & MWAIT_DISABLED ) ? "cleared" : "set" );
4354
4455 /*
4556 * Arbitrarily MONITOR this function, SVM performs fault checks before
@@ -50,19 +61,6 @@ static void guest_monitor_wait(int testcase)
5061
5162 vector = kvm_asm_safe ("mwait" , "a" (guest_monitor_wait ), "c" (0 ), "d" (0 ));
5263 GUEST_ASSERT_MONITOR_MWAIT ("MWAIT" , testcase , vector );
53- }
54-
55- static void guest_code (void )
56- {
57- guest_monitor_wait (MWAIT_DISABLED );
58-
59- guest_monitor_wait (MWAIT_QUIRK_DISABLED | MWAIT_DISABLED );
60-
61- guest_monitor_wait (MISC_ENABLES_QUIRK_DISABLED | MWAIT_DISABLED );
62- guest_monitor_wait (MISC_ENABLES_QUIRK_DISABLED );
63-
64- guest_monitor_wait (MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED | MWAIT_DISABLED );
65- guest_monitor_wait (MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED );
6664
6765 GUEST_DONE ();
6866}
@@ -74,56 +72,64 @@ int main(int argc, char *argv[])
7472 struct kvm_vm * vm ;
7573 struct ucall uc ;
7674 int testcase ;
75+ char test [80 ];
7776
78- TEST_REQUIRE (this_cpu_has (X86_FEATURE_MWAIT ));
7977 TEST_REQUIRE (kvm_has_cap (KVM_CAP_DISABLE_QUIRKS2 ));
8078
81- vm = vm_create_with_one_vcpu (& vcpu , guest_code );
82- vcpu_clear_cpuid_feature (vcpu , X86_FEATURE_MWAIT );
79+ ksft_print_header ();
80+ ksft_set_plan (12 );
81+ for (testcase = 0 ; testcase <= TEST_MAX ; testcase ++ ) {
82+ vm = vm_create_with_one_vcpu (& vcpu , guest_monitor_wait );
83+ vcpu_args_set (vcpu , 1 , (void * )(long )testcase );
84+
85+ disabled_quirks = 0 ;
86+ if (testcase & MWAIT_QUIRK_DISABLED ) {
87+ disabled_quirks |= KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS ;
88+ strcpy (test , "MWAIT can fault" );
89+ } else {
90+ strcpy (test , "MWAIT never faults" );
91+ }
92+ if (testcase & MISC_ENABLES_QUIRK_DISABLED ) {
93+ disabled_quirks |= KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT ;
94+ strcat (test , ", MISC_ENABLE updates CPUID" );
95+ } else {
96+ strcat (test , ", no CPUID updates" );
97+ }
98+
99+ vm_enable_cap (vm , KVM_CAP_DISABLE_QUIRKS2 , disabled_quirks );
100+
101+ if (!(testcase & MISC_ENABLES_QUIRK_DISABLED ) &&
102+ (!!(testcase & CPUID_DISABLED ) ^ !!(testcase & MWAIT_DISABLED )))
103+ continue ;
104+
105+ if (testcase & CPUID_DISABLED ) {
106+ strcat (test , ", CPUID clear" );
107+ vcpu_clear_cpuid_feature (vcpu , X86_FEATURE_MWAIT );
108+ } else {
109+ strcat (test , ", CPUID set" );
110+ vcpu_set_cpuid_feature (vcpu , X86_FEATURE_MWAIT );
111+ }
112+
113+ if (testcase & MWAIT_DISABLED )
114+ strcat (test , ", MWAIT disabled" );
83115
84- while (1 ) {
85116 vcpu_run (vcpu );
86117 TEST_ASSERT_KVM_EXIT_REASON (vcpu , KVM_EXIT_IO );
87118
88119 switch (get_ucall (vcpu , & uc )) {
89- case UCALL_SYNC :
90- testcase = uc .args [1 ];
91- break ;
92120 case UCALL_ABORT :
93- REPORT_GUEST_ASSERT ( uc );
94- goto done ;
121+ /* Detected in vcpu_run */
122+ break ;
95123 case UCALL_DONE :
96- goto done ;
124+ ksft_test_result_pass ("%s\n" , test );
125+ break ;
97126 default :
98127 TEST_FAIL ("Unknown ucall %lu" , uc .cmd );
99- goto done ;
100- }
101-
102- disabled_quirks = 0 ;
103- if (testcase & MWAIT_QUIRK_DISABLED )
104- disabled_quirks |= KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS ;
105- if (testcase & MISC_ENABLES_QUIRK_DISABLED )
106- disabled_quirks |= KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT ;
107- vm_enable_cap (vm , KVM_CAP_DISABLE_QUIRKS2 , disabled_quirks );
108-
109- /*
110- * If the MISC_ENABLES quirk (KVM neglects to update CPUID to
111- * enable/disable MWAIT) is disabled, toggle the ENABLE_MWAIT
112- * bit in MISC_ENABLES accordingly. If the quirk is enabled,
113- * the only valid configuration is MWAIT disabled, as CPUID
114- * can't be manually changed after running the vCPU.
115- */
116- if (!(testcase & MISC_ENABLES_QUIRK_DISABLED )) {
117- TEST_ASSERT (testcase & MWAIT_DISABLED ,
118- "Can't toggle CPUID features after running vCPU" );
119- continue ;
128+ break ;
120129 }
121-
122- vcpu_set_msr (vcpu , MSR_IA32_MISC_ENABLE ,
123- (testcase & MWAIT_DISABLED ) ? 0 : MSR_IA32_MISC_ENABLE_MWAIT );
130+ kvm_vm_free (vm );
124131 }
132+ ksft_finished ();
125133
126- done :
127- kvm_vm_free (vm );
128134 return 0 ;
129135}
0 commit comments