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 #include "kselftest.h" 11 12 #define CPUID_MWAIT (1u << 3) 13 14 enum monitor_mwait_testcases { 15 MWAIT_QUIRK_DISABLED = BIT(0), 16 MISC_ENABLES_QUIRK_DISABLED = BIT(1), 17 MWAIT_DISABLED = BIT(2), 18 CPUID_DISABLED = BIT(3), 19 TEST_MAX = CPUID_DISABLED * 2 - 1, 20 }; 21 22 /* 23 * If both MWAIT and its quirk are disabled, MONITOR/MWAIT should #UD, in all 24 * other scenarios KVM should emulate them as nops. 25 */ 26 #define GUEST_ASSERT_MONITOR_MWAIT(insn, testcase, vector) \ 27 do { \ 28 bool fault_wanted = ((testcase) & MWAIT_QUIRK_DISABLED) && \ 29 ((testcase) & MWAIT_DISABLED); \ 30 \ 31 if (fault_wanted) \ 32 __GUEST_ASSERT((vector) == UD_VECTOR, \ 33 "Expected #UD on " insn " for testcase '0x%x', got '0x%x'", \ 34 testcase, vector); \ 35 else \ 36 __GUEST_ASSERT(!(vector), \ 37 "Expected success on " insn " for testcase '0x%x', got '0x%x'", \ 38 testcase, vector); \ 39 } while (0) 40 41 static void guest_monitor_wait(void *arg) 42 { 43 int testcase = (int) (long) arg; 44 u8 vector; 45 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"); 54 55 /* 56 * Arbitrarily MONITOR this function, SVM performs fault checks before 57 * intercept checks, so the inputs for MONITOR and MWAIT must be valid. 58 */ 59 vector = kvm_asm_safe("monitor", "a"(guest_monitor_wait), "c"(0), "d"(0)); 60 GUEST_ASSERT_MONITOR_MWAIT("MONITOR", testcase, vector); 61 62 vector = kvm_asm_safe("mwait", "a"(guest_monitor_wait), "c"(0), "d"(0)); 63 GUEST_ASSERT_MONITOR_MWAIT("MWAIT", testcase, vector); 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 char test[80]; 76 77 TEST_REQUIRE(this_cpu_has(X86_FEATURE_MWAIT)); 78 TEST_REQUIRE(kvm_has_cap(KVM_CAP_DISABLE_QUIRKS2)); 79 80 ksft_print_header(); 81 ksft_set_plan(12); 82 for (testcase = 0; testcase <= TEST_MAX; testcase++) { 83 vm = vm_create_with_one_vcpu(&vcpu, guest_monitor_wait); 84 vcpu_args_set(vcpu, 1, (void *)(long)testcase); 85 86 disabled_quirks = 0; 87 if (testcase & MWAIT_QUIRK_DISABLED) { 88 disabled_quirks |= KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS; 89 strcpy(test, "MWAIT can fault"); 90 } else { 91 strcpy(test, "MWAIT never faults"); 92 } 93 if (testcase & MISC_ENABLES_QUIRK_DISABLED) { 94 disabled_quirks |= KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT; 95 strcat(test, ", MISC_ENABLE updates CPUID"); 96 } else { 97 strcat(test, ", no CPUID updates"); 98 } 99 100 vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, disabled_quirks); 101 102 if (!(testcase & MISC_ENABLES_QUIRK_DISABLED) && 103 (!!(testcase & CPUID_DISABLED) ^ !!(testcase & MWAIT_DISABLED))) 104 continue; 105 106 if (testcase & CPUID_DISABLED) { 107 strcat(test, ", CPUID clear"); 108 vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_MWAIT); 109 } else { 110 strcat(test, ", CPUID set"); 111 vcpu_set_cpuid_feature(vcpu, X86_FEATURE_MWAIT); 112 } 113 114 if (testcase & MWAIT_DISABLED) 115 strcat(test, ", MWAIT disabled"); 116 117 vcpu_run(vcpu); 118 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); 119 120 switch (get_ucall(vcpu, &uc)) { 121 case UCALL_ABORT: 122 /* Detected in vcpu_run */ 123 break; 124 case UCALL_DONE: 125 ksft_test_result_pass("%s\n", test); 126 break; 127 default: 128 TEST_FAIL("Unknown ucall %lu", uc.cmd); 129 break; 130 } 131 kvm_vm_free(vm); 132 } 133 ksft_finished(); 134 135 return 0; 136 } 137