0001
0002 #include <fcntl.h>
0003 #include <stdio.h>
0004 #include <stdlib.h>
0005 #include <string.h>
0006 #include <sys/ioctl.h>
0007
0008 #include "kvm_util.h"
0009 #include "processor.h"
0010
0011 #define CPUID_MWAIT (1u << 3)
0012
0013 enum monitor_mwait_testcases {
0014 MWAIT_QUIRK_DISABLED = BIT(0),
0015 MISC_ENABLES_QUIRK_DISABLED = BIT(1),
0016 MWAIT_DISABLED = BIT(2),
0017 };
0018
0019 static void guest_monitor_wait(int testcase)
0020 {
0021
0022
0023
0024
0025 bool fault_wanted = (testcase & MWAIT_QUIRK_DISABLED) &&
0026 (testcase & MWAIT_DISABLED);
0027 u8 vector;
0028
0029 GUEST_SYNC(testcase);
0030
0031
0032
0033
0034
0035 vector = kvm_asm_safe("monitor", "a"(guest_monitor_wait), "c"(0), "d"(0));
0036 if (fault_wanted)
0037 GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector);
0038 else
0039 GUEST_ASSERT_2(!vector, testcase, vector);
0040
0041 vector = kvm_asm_safe("mwait", "a"(guest_monitor_wait), "c"(0), "d"(0));
0042 if (fault_wanted)
0043 GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector);
0044 else
0045 GUEST_ASSERT_2(!vector, testcase, vector);
0046 }
0047
0048 static void guest_code(void)
0049 {
0050 guest_monitor_wait(MWAIT_DISABLED);
0051
0052 guest_monitor_wait(MWAIT_QUIRK_DISABLED | MWAIT_DISABLED);
0053
0054 guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_DISABLED);
0055 guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED);
0056
0057 guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED | MWAIT_DISABLED);
0058 guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED);
0059
0060 GUEST_DONE();
0061 }
0062
0063 int main(int argc, char *argv[])
0064 {
0065 uint64_t disabled_quirks;
0066 struct kvm_vcpu *vcpu;
0067 struct kvm_run *run;
0068 struct kvm_vm *vm;
0069 struct ucall uc;
0070 int testcase;
0071
0072 TEST_REQUIRE(kvm_has_cap(KVM_CAP_DISABLE_QUIRKS2));
0073
0074 vm = vm_create_with_one_vcpu(&vcpu, guest_code);
0075 vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_MWAIT);
0076
0077 run = vcpu->run;
0078
0079 vm_init_descriptor_tables(vm);
0080 vcpu_init_descriptor_tables(vcpu);
0081
0082 while (1) {
0083 vcpu_run(vcpu);
0084
0085 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
0086 "Unexpected exit reason: %u (%s),\n",
0087 run->exit_reason,
0088 exit_reason_str(run->exit_reason));
0089
0090 switch (get_ucall(vcpu, &uc)) {
0091 case UCALL_SYNC:
0092 testcase = uc.args[1];
0093 break;
0094 case UCALL_ABORT:
0095 REPORT_GUEST_ASSERT_2(uc, "testcase = %lx, vector = %ld");
0096 goto done;
0097 case UCALL_DONE:
0098 goto done;
0099 default:
0100 TEST_FAIL("Unknown ucall %lu", uc.cmd);
0101 goto done;
0102 }
0103
0104 disabled_quirks = 0;
0105 if (testcase & MWAIT_QUIRK_DISABLED)
0106 disabled_quirks |= KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS;
0107 if (testcase & MISC_ENABLES_QUIRK_DISABLED)
0108 disabled_quirks |= KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT;
0109 vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, disabled_quirks);
0110
0111
0112
0113
0114
0115
0116
0117
0118 if (!(testcase & MISC_ENABLES_QUIRK_DISABLED)) {
0119 TEST_ASSERT(testcase & MWAIT_DISABLED,
0120 "Can't toggle CPUID features after running vCPU");
0121 continue;
0122 }
0123
0124 vcpu_set_msr(vcpu, MSR_IA32_MISC_ENABLE,
0125 (testcase & MWAIT_DISABLED) ? 0 : MSR_IA32_MISC_ENABLE_MWAIT);
0126 }
0127
0128 done:
0129 kvm_vm_free(vm);
0130 return 0;
0131 }