1 /*
2 * Copyright 2018 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 #include <errno.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "crosvm.h"
14
15 typedef int (*crosvm_function)(struct crosvm*, uint32_t,
16 struct kvm_cpuid_entry2*, uint32_t*);
17 typedef int (*vcpu_function)(struct crosvm_vcpu*, uint32_t,
18 struct kvm_cpuid_entry2*, uint32_t*);
19
20 // Members of union should only differ by the pointer type of 1st arg.
21 union cpuid_function {
22 crosvm_function crosvm;
23 vcpu_function vcpu;
24 };
25
test_cpuid(void * crosvm,union cpuid_function funct,const char * name)26 int test_cpuid(void* crosvm, union cpuid_function funct, const char* name) {
27 struct kvm_cpuid_entry2 cpuids[100];
28 int n_entries = 0;
29 int ret = funct.crosvm(crosvm, 1, cpuids, &n_entries);
30 if (ret >= 0) {
31 fprintf(stderr,
32 "expected %s to fail with E2BIG\n", name);
33 return ret;
34 }
35
36 ret = funct.crosvm(crosvm, 100, cpuids, &n_entries);
37 if (ret < 0) {
38 if (ret != -EINVAL) {
39 fprintf(stderr, "unexpected failure of %s: %d\n", name, ret);
40 } else {
41 fprintf(stderr,
42 "Query of %s failed with EINVAL (may be expected)\n",
43 name, ret);
44 }
45 return ret;
46 }
47
48 if (n_entries <= 1) {
49 fprintf(stderr,
50 "unexpected number of cpuid entries from %s: %d\n",
51 name, n_entries);
52 return 1;
53 }
54 return 0;
55 }
56
main(int argc,char ** argv)57 int main(int argc, char** argv) {
58 struct crosvm* crosvm = NULL;
59 int ret = crosvm_connect(&crosvm);
60 if (ret) {
61 fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
62 return 1;
63 }
64
65 struct crosvm_vcpu* vcpu = NULL;
66 ret = crosvm_get_vcpu(crosvm, 0, &vcpu);
67 if (ret) {
68 fprintf(stderr, "failed to get vcpu #0: %d\n", ret);
69 return 1;
70 }
71
72 union cpuid_function funct;
73 funct.crosvm = crosvm_get_supported_cpuid;
74 if (test_cpuid(crosvm, funct, "crosvm_get_supported_cpuid")) {
75 return 1;
76 }
77 funct.crosvm = crosvm_get_emulated_cpuid;
78 if (test_cpuid(crosvm, funct, "crosvm_get_emulated_cpuid")) {
79 return 1;
80 }
81
82 ret = crosvm_start(crosvm);
83 if (ret) {
84 fprintf(stderr, "failed to start vm: %d\n", ret);
85 return 1;
86 }
87
88 struct crosvm_vcpu_event evt = {0};
89 ret = crosvm_vcpu_wait(vcpu, &evt);
90 if (ret) {
91 fprintf(stderr, "failed to wait for vm start: %d\n", ret);
92 return 1;
93 }
94 if (evt.kind != CROSVM_VCPU_EVENT_KIND_INIT) {
95 fprintf(stderr, "Got unexpected exit type: %d\n", evt.kind);
96 return 1;
97 }
98
99 funct.vcpu = crosvm_get_hyperv_cpuid;
100 ret = test_cpuid(vcpu, funct, "crosvm_get_hyperv_cpuid");
101 // Older kernels don't support and return EINVAL, so allow this for now.
102 if (ret && ret != -EINVAL) {
103 fprintf(stderr, "Ignoring failure of crosvm_get_hyperv_cpuid\n");
104 return 1;
105 }
106 return 0;
107 }
108