Skip to content

Commit 80fd663

Browse files
committed
selftests: kvm: revamp MONITOR/MWAIT tests
Run each testcase in a separate VMs to cover more possibilities; move WRMSR close to MONITOR/MWAIT to test updating CPUID bits while in the VM. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 782f9fe commit 80fd663

File tree

1 file changed

+57
-51
lines changed

1 file changed

+57
-51
lines changed

tools/testing/selftests/kvm/x86/monitor_mwait_test.c

Lines changed: 57 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77

88
#include "kvm_util.h"
99
#include "processor.h"
10+
#include "kselftest.h"
1011

1112
#define CPUID_MWAIT (1u << 3)
1213

1314
enum 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

Comments
 (0)