Merge tag '6.6-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6
[sfrench/cifs-2.6.git] / tools / testing / selftests / kvm / x86_64 / monitor_mwait_test.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <fcntl.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/ioctl.h>
7
8 #include "kvm_util.h"
9 #include "processor.h"
10
11 #define CPUID_MWAIT (1u << 3)
12
13 enum monitor_mwait_testcases {
14         MWAIT_QUIRK_DISABLED = BIT(0),
15         MISC_ENABLES_QUIRK_DISABLED = BIT(1),
16         MWAIT_DISABLED = BIT(2),
17 };
18
19 /*
20  * If both MWAIT and its quirk are disabled, MONITOR/MWAIT should #UD, in all
21  * other scenarios KVM should emulate them as nops.
22  */
23 #define GUEST_ASSERT_MONITOR_MWAIT(insn, testcase, vector)              \
24 do {                                                                    \
25         bool fault_wanted = ((testcase) & MWAIT_QUIRK_DISABLED) &&      \
26                             ((testcase) & MWAIT_DISABLED);              \
27                                                                         \
28         if (fault_wanted)                                               \
29                 __GUEST_ASSERT((vector) == UD_VECTOR,                   \
30                                "Expected #UD on " insn " for testcase '0x%x', got '0x%x'", vector); \
31         else                                                            \
32                 __GUEST_ASSERT(!(vector),                               \
33                                "Expected success on " insn " for testcase '0x%x', got '0x%x'", vector); \
34 } while (0)
35
36 static void guest_monitor_wait(int testcase)
37 {
38         u8 vector;
39
40         GUEST_SYNC(testcase);
41
42         /*
43          * Arbitrarily MONITOR this function, SVM performs fault checks before
44          * intercept checks, so the inputs for MONITOR and MWAIT must be valid.
45          */
46         vector = kvm_asm_safe("monitor", "a"(guest_monitor_wait), "c"(0), "d"(0));
47         GUEST_ASSERT_MONITOR_MWAIT("MONITOR", testcase, vector);
48
49         vector = kvm_asm_safe("mwait", "a"(guest_monitor_wait), "c"(0), "d"(0));
50         GUEST_ASSERT_MONITOR_MWAIT("MWAIT", testcase, vector);
51 }
52
53 static void guest_code(void)
54 {
55         guest_monitor_wait(MWAIT_DISABLED);
56
57         guest_monitor_wait(MWAIT_QUIRK_DISABLED | MWAIT_DISABLED);
58
59         guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_DISABLED);
60         guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED);
61
62         guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED | MWAIT_DISABLED);
63         guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED);
64
65         GUEST_DONE();
66 }
67
68 int main(int argc, char *argv[])
69 {
70         uint64_t disabled_quirks;
71         struct kvm_vcpu *vcpu;
72         struct kvm_vm *vm;
73         struct ucall uc;
74         int testcase;
75
76         TEST_REQUIRE(kvm_has_cap(KVM_CAP_DISABLE_QUIRKS2));
77
78         vm = vm_create_with_one_vcpu(&vcpu, guest_code);
79         vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_MWAIT);
80
81         vm_init_descriptor_tables(vm);
82         vcpu_init_descriptor_tables(vcpu);
83
84         while (1) {
85                 vcpu_run(vcpu);
86                 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
87
88                 switch (get_ucall(vcpu, &uc)) {
89                 case UCALL_SYNC:
90                         testcase = uc.args[1];
91                         break;
92                 case UCALL_ABORT:
93                         REPORT_GUEST_ASSERT(uc);
94                         goto done;
95                 case UCALL_DONE:
96                         goto done;
97                 default:
98                         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;
120                 }
121
122                 vcpu_set_msr(vcpu, MSR_IA32_MISC_ENABLE,
123                              (testcase & MWAIT_DISABLED) ? 0 : MSR_IA32_MISC_ENABLE_MWAIT);
124         }
125
126 done:
127         kvm_vm_free(vm);
128         return 0;
129 }