OSDN Git Service

perf/x86/uncore: Correct the number of CHAs on EMR
[tomoyo/tomoyo-test1.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 static void guest_monitor_wait(int testcase)
20 {
21         /*
22          * If both MWAIT and its quirk are disabled, MONITOR/MWAIT should #UD,
23          * in all other scenarios KVM should emulate them as nops.
24          */
25         bool fault_wanted = (testcase & MWAIT_QUIRK_DISABLED) &&
26                             (testcase & MWAIT_DISABLED);
27         u8 vector;
28
29         GUEST_SYNC(testcase);
30
31         /*
32          * Arbitrarily MONITOR this function, SVM performs fault checks before
33          * intercept checks, so the inputs for MONITOR and MWAIT must be valid.
34          */
35         vector = kvm_asm_safe("monitor", "a"(guest_monitor_wait), "c"(0), "d"(0));
36         if (fault_wanted)
37                 GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector);
38         else
39                 GUEST_ASSERT_2(!vector, testcase, vector);
40
41         vector = kvm_asm_safe("mwait", "a"(guest_monitor_wait), "c"(0), "d"(0));
42         if (fault_wanted)
43                 GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector);
44         else
45                 GUEST_ASSERT_2(!vector, testcase, vector);
46 }
47
48 static void guest_code(void)
49 {
50         guest_monitor_wait(MWAIT_DISABLED);
51
52         guest_monitor_wait(MWAIT_QUIRK_DISABLED | MWAIT_DISABLED);
53
54         guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_DISABLED);
55         guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED);
56
57         guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED | MWAIT_DISABLED);
58         guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED);
59
60         GUEST_DONE();
61 }
62
63 int main(int argc, char *argv[])
64 {
65         uint64_t disabled_quirks;
66         struct kvm_vcpu *vcpu;
67         struct kvm_vm *vm;
68         struct ucall uc;
69         int testcase;
70
71         TEST_REQUIRE(kvm_has_cap(KVM_CAP_DISABLE_QUIRKS2));
72
73         vm = vm_create_with_one_vcpu(&vcpu, guest_code);
74         vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_MWAIT);
75
76         vm_init_descriptor_tables(vm);
77         vcpu_init_descriptor_tables(vcpu);
78
79         while (1) {
80                 vcpu_run(vcpu);
81                 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
82
83                 switch (get_ucall(vcpu, &uc)) {
84                 case UCALL_SYNC:
85                         testcase = uc.args[1];
86                         break;
87                 case UCALL_ABORT:
88                         REPORT_GUEST_ASSERT_2(uc, "testcase = %lx, vector = %ld");
89                         goto done;
90                 case UCALL_DONE:
91                         goto done;
92                 default:
93                         TEST_FAIL("Unknown ucall %lu", uc.cmd);
94                         goto done;
95                 }
96
97                 disabled_quirks = 0;
98                 if (testcase & MWAIT_QUIRK_DISABLED)
99                         disabled_quirks |= KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS;
100                 if (testcase & MISC_ENABLES_QUIRK_DISABLED)
101                         disabled_quirks |= KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT;
102                 vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, disabled_quirks);
103
104                 /*
105                  * If the MISC_ENABLES quirk (KVM neglects to update CPUID to
106                  * enable/disable MWAIT) is disabled, toggle the ENABLE_MWAIT
107                  * bit in MISC_ENABLES accordingly.  If the quirk is enabled,
108                  * the only valid configuration is MWAIT disabled, as CPUID
109                  * can't be manually changed after running the vCPU.
110                  */
111                 if (!(testcase & MISC_ENABLES_QUIRK_DISABLED)) {
112                         TEST_ASSERT(testcase & MWAIT_DISABLED,
113                                     "Can't toggle CPUID features after running vCPU");
114                         continue;
115                 }
116
117                 vcpu_set_msr(vcpu, MSR_IA32_MISC_ENABLE,
118                              (testcase & MWAIT_DISABLED) ? 0 : MSR_IA32_MISC_ENABLE_MWAIT);
119         }
120
121 done:
122         kvm_vm_free(vm);
123         return 0;
124 }