7
7
8
8
#include "kvm_util.h"
9
9
#include "processor.h"
10
+ #include "kselftest.h"
10
11
11
12
#define CPUID_MWAIT (1u << 3)
12
13
13
14
enum monitor_mwait_testcases {
14
15
MWAIT_QUIRK_DISABLED = BIT (0 ),
15
16
MISC_ENABLES_QUIRK_DISABLED = BIT (1 ),
16
17
MWAIT_DISABLED = BIT (2 ),
18
+ CPUID_DISABLED = BIT (3 ),
19
+ TEST_MAX = CPUID_DISABLED * 2 - 1 ,
17
20
};
18
21
19
22
/*
@@ -35,11 +38,19 @@ do { \
35
38
testcase, vector); \
36
39
} while (0)
37
40
38
- static void guest_monitor_wait (int testcase )
41
+ static void guest_monitor_wait (void * arg )
39
42
{
43
+ int testcase = (int ) (long ) arg ;
40
44
u8 vector ;
41
45
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" );
43
54
44
55
/*
45
56
* Arbitrarily MONITOR this function, SVM performs fault checks before
@@ -50,19 +61,6 @@ static void guest_monitor_wait(int testcase)
50
61
51
62
vector = kvm_asm_safe ("mwait" , "a" (guest_monitor_wait ), "c" (0 ), "d" (0 ));
52
63
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 );
66
64
67
65
GUEST_DONE ();
68
66
}
@@ -74,56 +72,64 @@ int main(int argc, char *argv[])
74
72
struct kvm_vm * vm ;
75
73
struct ucall uc ;
76
74
int testcase ;
75
+ char test [80 ];
77
76
78
- TEST_REQUIRE (this_cpu_has (X86_FEATURE_MWAIT ));
79
77
TEST_REQUIRE (kvm_has_cap (KVM_CAP_DISABLE_QUIRKS2 ));
80
78
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" );
83
115
84
- while (1 ) {
85
116
vcpu_run (vcpu );
86
117
TEST_ASSERT_KVM_EXIT_REASON (vcpu , KVM_EXIT_IO );
87
118
88
119
switch (get_ucall (vcpu , & uc )) {
89
- case UCALL_SYNC :
90
- testcase = uc .args [1 ];
91
- break ;
92
120
case UCALL_ABORT :
93
- REPORT_GUEST_ASSERT ( uc );
94
- goto done ;
121
+ /* Detected in vcpu_run */
122
+ break ;
95
123
case UCALL_DONE :
96
- goto done ;
124
+ ksft_test_result_pass ("%s\n" , test );
125
+ break ;
97
126
default :
98
127
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 ;
120
129
}
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 );
124
131
}
132
+ ksft_finished ();
125
133
126
- done :
127
- kvm_vm_free (vm );
128
134
return 0 ;
129
135
}
0 commit comments