167730e6cSSean Christopherson // SPDX-License-Identifier: GPL-2.0 267730e6cSSean Christopherson /* 367730e6cSSean Christopherson * Test for x86 KVM_CAP_HYPERV_CPUID 467730e6cSSean Christopherson * 567730e6cSSean Christopherson * Copyright (C) 2018, Red Hat, Inc. 667730e6cSSean Christopherson * 767730e6cSSean Christopherson * This work is licensed under the terms of the GNU GPL, version 2. 867730e6cSSean Christopherson * 967730e6cSSean Christopherson */ 1067730e6cSSean Christopherson #include <fcntl.h> 1167730e6cSSean Christopherson #include <stdio.h> 1267730e6cSSean Christopherson #include <stdlib.h> 1367730e6cSSean Christopherson #include <string.h> 1467730e6cSSean Christopherson #include <sys/ioctl.h> 1567730e6cSSean Christopherson 1667730e6cSSean Christopherson #include "test_util.h" 1767730e6cSSean Christopherson #include "kvm_util.h" 1867730e6cSSean Christopherson #include "processor.h" 1967730e6cSSean Christopherson #include "vmx.h" 2067730e6cSSean Christopherson 2167730e6cSSean Christopherson static void guest_code(void) 2267730e6cSSean Christopherson { 2367730e6cSSean Christopherson } 2467730e6cSSean Christopherson 2567730e6cSSean Christopherson static bool smt_possible(void) 2667730e6cSSean Christopherson { 2767730e6cSSean Christopherson char buf[16]; 2867730e6cSSean Christopherson FILE *f; 2967730e6cSSean Christopherson bool res = true; 3067730e6cSSean Christopherson 3167730e6cSSean Christopherson f = fopen("/sys/devices/system/cpu/smt/control", "r"); 3267730e6cSSean Christopherson if (f) { 3367730e6cSSean Christopherson if (fread(buf, sizeof(*buf), sizeof(buf), f) > 0) { 3467730e6cSSean Christopherson if (!strncmp(buf, "forceoff", 8) || 3567730e6cSSean Christopherson !strncmp(buf, "notsupported", 12)) 3667730e6cSSean Christopherson res = false; 3767730e6cSSean Christopherson } 3867730e6cSSean Christopherson fclose(f); 3967730e6cSSean Christopherson } 4067730e6cSSean Christopherson 4167730e6cSSean Christopherson return res; 4267730e6cSSean Christopherson } 4367730e6cSSean Christopherson 44*cd5a0c2fSSean Christopherson static void test_hv_cpuid(struct kvm_vcpu *vcpu, bool evmcs_expected) 4567730e6cSSean Christopherson { 46*cd5a0c2fSSean Christopherson const struct kvm_cpuid2 *hv_cpuid_entries; 4767730e6cSSean Christopherson int i; 4867730e6cSSean Christopherson int nent_expected = 10; 4967730e6cSSean Christopherson u32 test_val; 5067730e6cSSean Christopherson 51*cd5a0c2fSSean Christopherson if (vcpu) 52*cd5a0c2fSSean Christopherson hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vcpu); 53*cd5a0c2fSSean Christopherson else 54*cd5a0c2fSSean Christopherson hv_cpuid_entries = kvm_get_supported_hv_cpuid(); 55*cd5a0c2fSSean Christopherson 5667730e6cSSean Christopherson TEST_ASSERT(hv_cpuid_entries->nent == nent_expected, 5767730e6cSSean Christopherson "KVM_GET_SUPPORTED_HV_CPUID should return %d entries" 5867730e6cSSean Christopherson " (returned %d)", 5967730e6cSSean Christopherson nent_expected, hv_cpuid_entries->nent); 6067730e6cSSean Christopherson 6167730e6cSSean Christopherson for (i = 0; i < hv_cpuid_entries->nent; i++) { 6267730e6cSSean Christopherson const struct kvm_cpuid_entry2 *entry = &hv_cpuid_entries->entries[i]; 6367730e6cSSean Christopherson 6467730e6cSSean Christopherson TEST_ASSERT((entry->function >= 0x40000000) && 6567730e6cSSean Christopherson (entry->function <= 0x40000082), 6667730e6cSSean Christopherson "function %x is our of supported range", 6767730e6cSSean Christopherson entry->function); 6867730e6cSSean Christopherson 6967730e6cSSean Christopherson TEST_ASSERT(entry->index == 0, 7067730e6cSSean Christopherson ".index field should be zero"); 7167730e6cSSean Christopherson 7267730e6cSSean Christopherson TEST_ASSERT(entry->flags == 0, 7367730e6cSSean Christopherson ".flags field should be zero"); 7467730e6cSSean Christopherson 7567730e6cSSean Christopherson TEST_ASSERT(!entry->padding[0] && !entry->padding[1] && 7667730e6cSSean Christopherson !entry->padding[2], "padding should be zero"); 7767730e6cSSean Christopherson 7867730e6cSSean Christopherson switch (entry->function) { 7967730e6cSSean Christopherson case 0x40000000: 8067730e6cSSean Christopherson test_val = 0x40000082; 8167730e6cSSean Christopherson 8267730e6cSSean Christopherson TEST_ASSERT(entry->eax == test_val, 8367730e6cSSean Christopherson "Wrong max leaf report in 0x40000000.EAX: %x" 8467730e6cSSean Christopherson " (evmcs=%d)", 8567730e6cSSean Christopherson entry->eax, evmcs_expected 8667730e6cSSean Christopherson ); 8767730e6cSSean Christopherson break; 8867730e6cSSean Christopherson case 0x40000004: 8967730e6cSSean Christopherson test_val = entry->eax & (1UL << 18); 9067730e6cSSean Christopherson 9167730e6cSSean Christopherson TEST_ASSERT(!!test_val == !smt_possible(), 9267730e6cSSean Christopherson "NoNonArchitecturalCoreSharing bit" 9367730e6cSSean Christopherson " doesn't reflect SMT setting"); 9467730e6cSSean Christopherson break; 9567730e6cSSean Christopherson case 0x4000000A: 9667730e6cSSean Christopherson TEST_ASSERT(entry->eax & (1UL << 19), 9767730e6cSSean Christopherson "Enlightened MSR-Bitmap should always be supported" 9867730e6cSSean Christopherson " 0x40000000.EAX: %x", entry->eax); 9967730e6cSSean Christopherson if (evmcs_expected) 10067730e6cSSean Christopherson TEST_ASSERT((entry->eax & 0xffff) == 0x101, 10167730e6cSSean Christopherson "Supported Enlightened VMCS version range is supposed to be 1:1" 10267730e6cSSean Christopherson " 0x40000000.EAX: %x", entry->eax); 10367730e6cSSean Christopherson 10467730e6cSSean Christopherson break; 10567730e6cSSean Christopherson default: 10667730e6cSSean Christopherson break; 10767730e6cSSean Christopherson 10867730e6cSSean Christopherson } 10967730e6cSSean Christopherson /* 11067730e6cSSean Christopherson * If needed for debug: 11167730e6cSSean Christopherson * fprintf(stdout, 11267730e6cSSean Christopherson * "CPUID%lx EAX=0x%lx EBX=0x%lx ECX=0x%lx EDX=0x%lx\n", 11367730e6cSSean Christopherson * entry->function, entry->eax, entry->ebx, entry->ecx, 11467730e6cSSean Christopherson * entry->edx); 11567730e6cSSean Christopherson */ 11667730e6cSSean Christopherson } 117*cd5a0c2fSSean Christopherson 118*cd5a0c2fSSean Christopherson /* 119*cd5a0c2fSSean Christopherson * Note, the CPUID array returned by the system-scoped helper is a one- 120*cd5a0c2fSSean Christopherson * time allocation, i.e. must not be freed. 121*cd5a0c2fSSean Christopherson */ 122*cd5a0c2fSSean Christopherson if (vcpu) 123*cd5a0c2fSSean Christopherson free((void *)hv_cpuid_entries); 12467730e6cSSean Christopherson } 12567730e6cSSean Christopherson 1260b6db0dcSSean Christopherson static void test_hv_cpuid_e2big(struct kvm_vm *vm, struct kvm_vcpu *vcpu) 12767730e6cSSean Christopherson { 12867730e6cSSean Christopherson static struct kvm_cpuid2 cpuid = {.nent = 0}; 12967730e6cSSean Christopherson int ret; 13067730e6cSSean Christopherson 13167730e6cSSean Christopherson if (vcpu) 13267730e6cSSean Christopherson ret = __vcpu_ioctl(vcpu, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); 13367730e6cSSean Christopherson else 13467730e6cSSean Christopherson ret = __kvm_ioctl(vm->kvm_fd, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); 13567730e6cSSean Christopherson 13667730e6cSSean Christopherson TEST_ASSERT(ret == -1 && errno == E2BIG, 13767730e6cSSean Christopherson "%s KVM_GET_SUPPORTED_HV_CPUID didn't fail with -E2BIG when" 13867730e6cSSean Christopherson " it should have: %d %d", !vcpu ? "KVM" : "vCPU", ret, errno); 13967730e6cSSean Christopherson } 14067730e6cSSean Christopherson 14167730e6cSSean Christopherson int main(int argc, char *argv[]) 14267730e6cSSean Christopherson { 14367730e6cSSean Christopherson struct kvm_vm *vm; 14467730e6cSSean Christopherson struct kvm_vcpu *vcpu; 14567730e6cSSean Christopherson 14667730e6cSSean Christopherson TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_CPUID)); 14767730e6cSSean Christopherson 14867730e6cSSean Christopherson vm = vm_create_with_one_vcpu(&vcpu, guest_code); 14967730e6cSSean Christopherson 15067730e6cSSean Christopherson /* Test vCPU ioctl version */ 15167730e6cSSean Christopherson test_hv_cpuid_e2big(vm, vcpu); 152*cd5a0c2fSSean Christopherson test_hv_cpuid(vcpu, false); 15367730e6cSSean Christopherson 15467730e6cSSean Christopherson if (!kvm_cpu_has(X86_FEATURE_VMX) || 15567730e6cSSean Christopherson !kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { 15667730e6cSSean Christopherson print_skip("Enlightened VMCS is unsupported"); 15767730e6cSSean Christopherson goto do_sys; 15867730e6cSSean Christopherson } 15967730e6cSSean Christopherson vcpu_enable_evmcs(vcpu); 160*cd5a0c2fSSean Christopherson test_hv_cpuid(vcpu, true); 16167730e6cSSean Christopherson 16267730e6cSSean Christopherson do_sys: 16367730e6cSSean Christopherson /* Test system ioctl version */ 16467730e6cSSean Christopherson if (!kvm_has_cap(KVM_CAP_SYS_HYPERV_CPUID)) { 16567730e6cSSean Christopherson print_skip("KVM_CAP_SYS_HYPERV_CPUID not supported"); 16667730e6cSSean Christopherson goto out; 16767730e6cSSean Christopherson } 16867730e6cSSean Christopherson 16967730e6cSSean Christopherson test_hv_cpuid_e2big(vm, NULL); 170*cd5a0c2fSSean Christopherson test_hv_cpuid(NULL, kvm_cpu_has(X86_FEATURE_VMX)); 17167730e6cSSean Christopherson 17267730e6cSSean Christopherson out: 17367730e6cSSean Christopherson kvm_vm_free(vm); 17467730e6cSSean Christopherson 17567730e6cSSean Christopherson return 0; 17667730e6cSSean Christopherson } 177