root/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. guest_code
  2. smt_possible
  3. test_hv_cpuid
  4. test_hv_cpuid_e2big
  5. kvm_get_supported_hv_cpuid
  6. main

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Test for x86 KVM_CAP_HYPERV_CPUID
   4  *
   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 
  11 #define _GNU_SOURCE /* for program_invocation_short_name */
  12 #include <fcntl.h>
  13 #include <stdio.h>
  14 #include <stdlib.h>
  15 #include <string.h>
  16 #include <sys/ioctl.h>
  17 
  18 #include "test_util.h"
  19 #include "kvm_util.h"
  20 #include "processor.h"
  21 #include "vmx.h"
  22 
  23 #define VCPU_ID 0
  24 
  25 static void guest_code(void)
  26 {
  27 }
  28 
  29 static int smt_possible(void)
  30 {
  31         char buf[16];
  32         FILE *f;
  33         bool res = 1;
  34 
  35         f = fopen("/sys/devices/system/cpu/smt/control", "r");
  36         if (f) {
  37                 if (fread(buf, sizeof(*buf), sizeof(buf), f) > 0) {
  38                         if (!strncmp(buf, "forceoff", 8) ||
  39                             !strncmp(buf, "notsupported", 12))
  40                                 res = 0;
  41                 }
  42                 fclose(f);
  43         }
  44 
  45         return res;
  46 }
  47 
  48 static void test_hv_cpuid(struct kvm_cpuid2 *hv_cpuid_entries,
  49                           int evmcs_enabled)
  50 {
  51         int i;
  52 
  53         if (!evmcs_enabled)
  54                 TEST_ASSERT(hv_cpuid_entries->nent == 6,
  55                             "KVM_GET_SUPPORTED_HV_CPUID should return 6 entries"
  56                             " when Enlightened VMCS is disabled (returned %d)",
  57                             hv_cpuid_entries->nent);
  58         else
  59                 TEST_ASSERT(hv_cpuid_entries->nent == 7,
  60                             "KVM_GET_SUPPORTED_HV_CPUID should return 7 entries"
  61                             " when Enlightened VMCS is enabled (returned %d)",
  62                             hv_cpuid_entries->nent);
  63 
  64         for (i = 0; i < hv_cpuid_entries->nent; i++) {
  65                 struct kvm_cpuid_entry2 *entry = &hv_cpuid_entries->entries[i];
  66 
  67                 TEST_ASSERT((entry->function >= 0x40000000) &&
  68                             (entry->function <= 0x4000000A),
  69                             "function %lx is our of supported range",
  70                             entry->function);
  71 
  72                 TEST_ASSERT(entry->index == 0,
  73                             ".index field should be zero");
  74 
  75                 TEST_ASSERT(entry->flags == 0,
  76                             ".flags field should be zero");
  77 
  78                 TEST_ASSERT(!entry->padding[0] && !entry->padding[1] &&
  79                             !entry->padding[2], "padding should be zero");
  80 
  81                 if (entry->function == 0x40000004) {
  82                         int nononarchcs = !!(entry->eax & (1UL << 18));
  83 
  84                         TEST_ASSERT(nononarchcs == !smt_possible(),
  85                                     "NoNonArchitecturalCoreSharing bit"
  86                                     " doesn't reflect SMT setting");
  87                 }
  88 
  89                 /*
  90                  * If needed for debug:
  91                  * fprintf(stdout,
  92                  *      "CPUID%lx EAX=0x%lx EBX=0x%lx ECX=0x%lx EDX=0x%lx\n",
  93                  *      entry->function, entry->eax, entry->ebx, entry->ecx,
  94                  *      entry->edx);
  95                  */
  96         }
  97 
  98 }
  99 
 100 void test_hv_cpuid_e2big(struct kvm_vm *vm)
 101 {
 102         static struct kvm_cpuid2 cpuid = {.nent = 0};
 103         int ret;
 104 
 105         ret = _vcpu_ioctl(vm, VCPU_ID, KVM_GET_SUPPORTED_HV_CPUID, &cpuid);
 106 
 107         TEST_ASSERT(ret == -1 && errno == E2BIG,
 108                     "KVM_GET_SUPPORTED_HV_CPUID didn't fail with -E2BIG when"
 109                     " it should have: %d %d", ret, errno);
 110 }
 111 
 112 
 113 struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(struct kvm_vm *vm)
 114 {
 115         int nent = 20; /* should be enough */
 116         static struct kvm_cpuid2 *cpuid;
 117 
 118         cpuid = malloc(sizeof(*cpuid) + nent * sizeof(struct kvm_cpuid_entry2));
 119 
 120         if (!cpuid) {
 121                 perror("malloc");
 122                 abort();
 123         }
 124 
 125         cpuid->nent = nent;
 126 
 127         vcpu_ioctl(vm, VCPU_ID, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
 128 
 129         return cpuid;
 130 }
 131 
 132 
 133 int main(int argc, char *argv[])
 134 {
 135         struct kvm_vm *vm;
 136         int rv;
 137         struct kvm_cpuid2 *hv_cpuid_entries;
 138 
 139         /* Tell stdout not to buffer its content */
 140         setbuf(stdout, NULL);
 141 
 142         rv = kvm_check_cap(KVM_CAP_HYPERV_CPUID);
 143         if (!rv) {
 144                 fprintf(stderr,
 145                         "KVM_CAP_HYPERV_CPUID not supported, skip test\n");
 146                 exit(KSFT_SKIP);
 147         }
 148 
 149         /* Create VM */
 150         vm = vm_create_default(VCPU_ID, 0, guest_code);
 151 
 152         test_hv_cpuid_e2big(vm);
 153 
 154         hv_cpuid_entries = kvm_get_supported_hv_cpuid(vm);
 155         if (!hv_cpuid_entries)
 156                 return 1;
 157 
 158         test_hv_cpuid(hv_cpuid_entries, 0);
 159 
 160         free(hv_cpuid_entries);
 161 
 162         if (!kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) {
 163                 fprintf(stderr,
 164                         "Enlightened VMCS is unsupported, skip related test\n");
 165                 goto vm_free;
 166         }
 167 
 168         vcpu_enable_evmcs(vm, VCPU_ID);
 169 
 170         hv_cpuid_entries = kvm_get_supported_hv_cpuid(vm);
 171         if (!hv_cpuid_entries)
 172                 return 1;
 173 
 174         test_hv_cpuid(hv_cpuid_entries, 1);
 175 
 176         free(hv_cpuid_entries);
 177 
 178 vm_free:
 179         kvm_vm_free(vm);
 180 
 181         return 0;
 182 }

/* [<][>][^][v][top][bottom][index][help] */