]>
Commit | Line | Data |
---|---|---|
7edcb734 VK |
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" | |
65efa61d | 21 | #include "vmx.h" |
7edcb734 VK |
22 | |
23 | #define VCPU_ID 0 | |
24 | ||
25 | static void guest_code(void) | |
26 | { | |
27 | } | |
28 | ||
29 | static void test_hv_cpuid(struct kvm_cpuid2 *hv_cpuid_entries, | |
30 | int evmcs_enabled) | |
31 | { | |
32 | int i; | |
33 | ||
34 | if (!evmcs_enabled) | |
35 | TEST_ASSERT(hv_cpuid_entries->nent == 6, | |
36 | "KVM_GET_SUPPORTED_HV_CPUID should return 6 entries" | |
37 | " when Enlightened VMCS is disabled (returned %d)", | |
38 | hv_cpuid_entries->nent); | |
39 | else | |
40 | TEST_ASSERT(hv_cpuid_entries->nent == 7, | |
41 | "KVM_GET_SUPPORTED_HV_CPUID should return 7 entries" | |
42 | " when Enlightened VMCS is enabled (returned %d)", | |
43 | hv_cpuid_entries->nent); | |
44 | ||
45 | for (i = 0; i < hv_cpuid_entries->nent; i++) { | |
46 | struct kvm_cpuid_entry2 *entry = &hv_cpuid_entries->entries[i]; | |
47 | ||
48 | TEST_ASSERT((entry->function >= 0x40000000) && | |
49 | (entry->function <= 0x4000000A), | |
50 | "function %lx is our of supported range", | |
51 | entry->function); | |
52 | ||
53 | TEST_ASSERT(entry->index == 0, | |
54 | ".index field should be zero"); | |
55 | ||
7edcb734 VK |
56 | TEST_ASSERT(entry->flags == 0, |
57 | ".flags field should be zero"); | |
58 | ||
be7fcf1d DC |
59 | TEST_ASSERT(!entry->padding[0] && !entry->padding[1] && |
60 | !entry->padding[2], "padding should be zero"); | |
7edcb734 VK |
61 | |
62 | /* | |
63 | * If needed for debug: | |
64 | * fprintf(stdout, | |
65 | * "CPUID%lx EAX=0x%lx EBX=0x%lx ECX=0x%lx EDX=0x%lx\n", | |
66 | * entry->function, entry->eax, entry->ebx, entry->ecx, | |
67 | * entry->edx); | |
68 | */ | |
69 | } | |
70 | ||
71 | } | |
72 | ||
73 | void test_hv_cpuid_e2big(struct kvm_vm *vm) | |
74 | { | |
75 | static struct kvm_cpuid2 cpuid = {.nent = 0}; | |
76 | int ret; | |
77 | ||
78 | ret = _vcpu_ioctl(vm, VCPU_ID, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); | |
79 | ||
80 | TEST_ASSERT(ret == -1 && errno == E2BIG, | |
81 | "KVM_GET_SUPPORTED_HV_CPUID didn't fail with -E2BIG when" | |
82 | " it should have: %d %d", ret, errno); | |
83 | } | |
84 | ||
85 | ||
86 | struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(struct kvm_vm *vm) | |
87 | { | |
88 | int nent = 20; /* should be enough */ | |
89 | static struct kvm_cpuid2 *cpuid; | |
7edcb734 VK |
90 | |
91 | cpuid = malloc(sizeof(*cpuid) + nent * sizeof(struct kvm_cpuid_entry2)); | |
92 | ||
93 | if (!cpuid) { | |
94 | perror("malloc"); | |
95 | abort(); | |
96 | } | |
97 | ||
98 | cpuid->nent = nent; | |
99 | ||
100 | vcpu_ioctl(vm, VCPU_ID, KVM_GET_SUPPORTED_HV_CPUID, cpuid); | |
101 | ||
102 | return cpuid; | |
103 | } | |
104 | ||
105 | ||
106 | int main(int argc, char *argv[]) | |
107 | { | |
108 | struct kvm_vm *vm; | |
109 | int rv; | |
7edcb734 | 110 | struct kvm_cpuid2 *hv_cpuid_entries; |
7edcb734 VK |
111 | |
112 | /* Tell stdout not to buffer its content */ | |
113 | setbuf(stdout, NULL); | |
114 | ||
115 | rv = kvm_check_cap(KVM_CAP_HYPERV_CPUID); | |
116 | if (!rv) { | |
117 | fprintf(stderr, | |
118 | "KVM_CAP_HYPERV_CPUID not supported, skip test\n"); | |
119 | exit(KSFT_SKIP); | |
120 | } | |
121 | ||
122 | /* Create VM */ | |
123 | vm = vm_create_default(VCPU_ID, 0, guest_code); | |
124 | ||
125 | test_hv_cpuid_e2big(vm); | |
126 | ||
127 | hv_cpuid_entries = kvm_get_supported_hv_cpuid(vm); | |
128 | if (!hv_cpuid_entries) | |
129 | return 1; | |
130 | ||
131 | test_hv_cpuid(hv_cpuid_entries, 0); | |
132 | ||
133 | free(hv_cpuid_entries); | |
134 | ||
65efa61d | 135 | if (!kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { |
eba3afde VK |
136 | fprintf(stderr, |
137 | "Enlightened VMCS is unsupported, skip related test\n"); | |
138 | goto vm_free; | |
139 | } | |
7edcb734 | 140 | |
65efa61d PB |
141 | vcpu_enable_evmcs(vm, VCPU_ID); |
142 | ||
7edcb734 VK |
143 | hv_cpuid_entries = kvm_get_supported_hv_cpuid(vm); |
144 | if (!hv_cpuid_entries) | |
145 | return 1; | |
146 | ||
147 | test_hv_cpuid(hv_cpuid_entries, 1); | |
148 | ||
149 | free(hv_cpuid_entries); | |
150 | ||
eba3afde | 151 | vm_free: |
7edcb734 VK |
152 | kvm_vm_free(vm); |
153 | ||
154 | return 0; | |
155 | } |