1*67730e6cSSean Christopherson // SPDX-License-Identifier: GPL-2.0 2*67730e6cSSean Christopherson /* 3*67730e6cSSean Christopherson * Test for x86 KVM_CAP_HYPERV_CPUID 4*67730e6cSSean Christopherson * 5*67730e6cSSean Christopherson * Copyright (C) 2018, Red Hat, Inc. 6*67730e6cSSean Christopherson * 7*67730e6cSSean Christopherson * This work is licensed under the terms of the GNU GPL, version 2. 8*67730e6cSSean Christopherson * 9*67730e6cSSean Christopherson */ 10*67730e6cSSean Christopherson #include <fcntl.h> 11*67730e6cSSean Christopherson #include <stdio.h> 12*67730e6cSSean Christopherson #include <stdlib.h> 13*67730e6cSSean Christopherson #include <string.h> 14*67730e6cSSean Christopherson #include <sys/ioctl.h> 15*67730e6cSSean Christopherson 16*67730e6cSSean Christopherson #include "test_util.h" 17*67730e6cSSean Christopherson #include "kvm_util.h" 18*67730e6cSSean Christopherson #include "processor.h" 19*67730e6cSSean Christopherson #include "vmx.h" 20*67730e6cSSean Christopherson 21*67730e6cSSean Christopherson static void guest_code(void) 22*67730e6cSSean Christopherson { 23*67730e6cSSean Christopherson } 24*67730e6cSSean Christopherson 25*67730e6cSSean Christopherson static bool smt_possible(void) 26*67730e6cSSean Christopherson { 27*67730e6cSSean Christopherson char buf[16]; 28*67730e6cSSean Christopherson FILE *f; 29*67730e6cSSean Christopherson bool res = true; 30*67730e6cSSean Christopherson 31*67730e6cSSean Christopherson f = fopen("/sys/devices/system/cpu/smt/control", "r"); 32*67730e6cSSean Christopherson if (f) { 33*67730e6cSSean Christopherson if (fread(buf, sizeof(*buf), sizeof(buf), f) > 0) { 34*67730e6cSSean Christopherson if (!strncmp(buf, "forceoff", 8) || 35*67730e6cSSean Christopherson !strncmp(buf, "notsupported", 12)) 36*67730e6cSSean Christopherson res = false; 37*67730e6cSSean Christopherson } 38*67730e6cSSean Christopherson fclose(f); 39*67730e6cSSean Christopherson } 40*67730e6cSSean Christopherson 41*67730e6cSSean Christopherson return res; 42*67730e6cSSean Christopherson } 43*67730e6cSSean Christopherson 44*67730e6cSSean Christopherson static void test_hv_cpuid(const struct kvm_cpuid2 *hv_cpuid_entries, 45*67730e6cSSean Christopherson bool evmcs_expected) 46*67730e6cSSean Christopherson { 47*67730e6cSSean Christopherson int i; 48*67730e6cSSean Christopherson int nent_expected = 10; 49*67730e6cSSean Christopherson u32 test_val; 50*67730e6cSSean Christopherson 51*67730e6cSSean Christopherson TEST_ASSERT(hv_cpuid_entries->nent == nent_expected, 52*67730e6cSSean Christopherson "KVM_GET_SUPPORTED_HV_CPUID should return %d entries" 53*67730e6cSSean Christopherson " (returned %d)", 54*67730e6cSSean Christopherson nent_expected, hv_cpuid_entries->nent); 55*67730e6cSSean Christopherson 56*67730e6cSSean Christopherson for (i = 0; i < hv_cpuid_entries->nent; i++) { 57*67730e6cSSean Christopherson const struct kvm_cpuid_entry2 *entry = &hv_cpuid_entries->entries[i]; 58*67730e6cSSean Christopherson 59*67730e6cSSean Christopherson TEST_ASSERT((entry->function >= 0x40000000) && 60*67730e6cSSean Christopherson (entry->function <= 0x40000082), 61*67730e6cSSean Christopherson "function %x is our of supported range", 62*67730e6cSSean Christopherson entry->function); 63*67730e6cSSean Christopherson 64*67730e6cSSean Christopherson TEST_ASSERT(entry->index == 0, 65*67730e6cSSean Christopherson ".index field should be zero"); 66*67730e6cSSean Christopherson 67*67730e6cSSean Christopherson TEST_ASSERT(entry->flags == 0, 68*67730e6cSSean Christopherson ".flags field should be zero"); 69*67730e6cSSean Christopherson 70*67730e6cSSean Christopherson TEST_ASSERT(!entry->padding[0] && !entry->padding[1] && 71*67730e6cSSean Christopherson !entry->padding[2], "padding should be zero"); 72*67730e6cSSean Christopherson 73*67730e6cSSean Christopherson switch (entry->function) { 74*67730e6cSSean Christopherson case 0x40000000: 75*67730e6cSSean Christopherson test_val = 0x40000082; 76*67730e6cSSean Christopherson 77*67730e6cSSean Christopherson TEST_ASSERT(entry->eax == test_val, 78*67730e6cSSean Christopherson "Wrong max leaf report in 0x40000000.EAX: %x" 79*67730e6cSSean Christopherson " (evmcs=%d)", 80*67730e6cSSean Christopherson entry->eax, evmcs_expected 81*67730e6cSSean Christopherson ); 82*67730e6cSSean Christopherson break; 83*67730e6cSSean Christopherson case 0x40000004: 84*67730e6cSSean Christopherson test_val = entry->eax & (1UL << 18); 85*67730e6cSSean Christopherson 86*67730e6cSSean Christopherson TEST_ASSERT(!!test_val == !smt_possible(), 87*67730e6cSSean Christopherson "NoNonArchitecturalCoreSharing bit" 88*67730e6cSSean Christopherson " doesn't reflect SMT setting"); 89*67730e6cSSean Christopherson break; 90*67730e6cSSean Christopherson case 0x4000000A: 91*67730e6cSSean Christopherson TEST_ASSERT(entry->eax & (1UL << 19), 92*67730e6cSSean Christopherson "Enlightened MSR-Bitmap should always be supported" 93*67730e6cSSean Christopherson " 0x40000000.EAX: %x", entry->eax); 94*67730e6cSSean Christopherson if (evmcs_expected) 95*67730e6cSSean Christopherson TEST_ASSERT((entry->eax & 0xffff) == 0x101, 96*67730e6cSSean Christopherson "Supported Enlightened VMCS version range is supposed to be 1:1" 97*67730e6cSSean Christopherson " 0x40000000.EAX: %x", entry->eax); 98*67730e6cSSean Christopherson 99*67730e6cSSean Christopherson break; 100*67730e6cSSean Christopherson default: 101*67730e6cSSean Christopherson break; 102*67730e6cSSean Christopherson 103*67730e6cSSean Christopherson } 104*67730e6cSSean Christopherson /* 105*67730e6cSSean Christopherson * If needed for debug: 106*67730e6cSSean Christopherson * fprintf(stdout, 107*67730e6cSSean Christopherson * "CPUID%lx EAX=0x%lx EBX=0x%lx ECX=0x%lx EDX=0x%lx\n", 108*67730e6cSSean Christopherson * entry->function, entry->eax, entry->ebx, entry->ecx, 109*67730e6cSSean Christopherson * entry->edx); 110*67730e6cSSean Christopherson */ 111*67730e6cSSean Christopherson } 112*67730e6cSSean Christopherson } 113*67730e6cSSean Christopherson 114*67730e6cSSean Christopherson void test_hv_cpuid_e2big(struct kvm_vm *vm, struct kvm_vcpu *vcpu) 115*67730e6cSSean Christopherson { 116*67730e6cSSean Christopherson static struct kvm_cpuid2 cpuid = {.nent = 0}; 117*67730e6cSSean Christopherson int ret; 118*67730e6cSSean Christopherson 119*67730e6cSSean Christopherson if (vcpu) 120*67730e6cSSean Christopherson ret = __vcpu_ioctl(vcpu, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); 121*67730e6cSSean Christopherson else 122*67730e6cSSean Christopherson ret = __kvm_ioctl(vm->kvm_fd, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); 123*67730e6cSSean Christopherson 124*67730e6cSSean Christopherson TEST_ASSERT(ret == -1 && errno == E2BIG, 125*67730e6cSSean Christopherson "%s KVM_GET_SUPPORTED_HV_CPUID didn't fail with -E2BIG when" 126*67730e6cSSean Christopherson " it should have: %d %d", !vcpu ? "KVM" : "vCPU", ret, errno); 127*67730e6cSSean Christopherson } 128*67730e6cSSean Christopherson 129*67730e6cSSean Christopherson int main(int argc, char *argv[]) 130*67730e6cSSean Christopherson { 131*67730e6cSSean Christopherson struct kvm_vm *vm; 132*67730e6cSSean Christopherson const struct kvm_cpuid2 *hv_cpuid_entries; 133*67730e6cSSean Christopherson struct kvm_vcpu *vcpu; 134*67730e6cSSean Christopherson 135*67730e6cSSean Christopherson TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_CPUID)); 136*67730e6cSSean Christopherson 137*67730e6cSSean Christopherson vm = vm_create_with_one_vcpu(&vcpu, guest_code); 138*67730e6cSSean Christopherson 139*67730e6cSSean Christopherson /* Test vCPU ioctl version */ 140*67730e6cSSean Christopherson test_hv_cpuid_e2big(vm, vcpu); 141*67730e6cSSean Christopherson 142*67730e6cSSean Christopherson hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vcpu); 143*67730e6cSSean Christopherson test_hv_cpuid(hv_cpuid_entries, false); 144*67730e6cSSean Christopherson free((void *)hv_cpuid_entries); 145*67730e6cSSean Christopherson 146*67730e6cSSean Christopherson if (!kvm_cpu_has(X86_FEATURE_VMX) || 147*67730e6cSSean Christopherson !kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { 148*67730e6cSSean Christopherson print_skip("Enlightened VMCS is unsupported"); 149*67730e6cSSean Christopherson goto do_sys; 150*67730e6cSSean Christopherson } 151*67730e6cSSean Christopherson vcpu_enable_evmcs(vcpu); 152*67730e6cSSean Christopherson hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vcpu); 153*67730e6cSSean Christopherson test_hv_cpuid(hv_cpuid_entries, true); 154*67730e6cSSean Christopherson free((void *)hv_cpuid_entries); 155*67730e6cSSean Christopherson 156*67730e6cSSean Christopherson do_sys: 157*67730e6cSSean Christopherson /* Test system ioctl version */ 158*67730e6cSSean Christopherson if (!kvm_has_cap(KVM_CAP_SYS_HYPERV_CPUID)) { 159*67730e6cSSean Christopherson print_skip("KVM_CAP_SYS_HYPERV_CPUID not supported"); 160*67730e6cSSean Christopherson goto out; 161*67730e6cSSean Christopherson } 162*67730e6cSSean Christopherson 163*67730e6cSSean Christopherson test_hv_cpuid_e2big(vm, NULL); 164*67730e6cSSean Christopherson 165*67730e6cSSean Christopherson hv_cpuid_entries = kvm_get_supported_hv_cpuid(); 166*67730e6cSSean Christopherson test_hv_cpuid(hv_cpuid_entries, kvm_cpu_has(X86_FEATURE_VMX)); 167*67730e6cSSean Christopherson 168*67730e6cSSean Christopherson out: 169*67730e6cSSean Christopherson kvm_vm_free(vm); 170*67730e6cSSean Christopherson 171*67730e6cSSean Christopherson return 0; 172*67730e6cSSean Christopherson } 173