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