1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2022 Oxide Computer Company
14 */
15
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <strings.h>
20 #include <libgen.h>
21 #include <assert.h>
22 #include <errno.h>
23
24 #include <sys/types.h>
25 #include <sys/sysmacros.h>
26 #include <sys/debug.h>
27 #include <sys/vmm.h>
28 #include <sys/vmm_dev.h>
29 #include <vmmapi.h>
30
31 #include "in_guest.h"
32
33 static const struct vcpu_cpuid_entry test_entries[] = {
34 {
35 .vce_function = 0,
36 .vce_eax = 5,
37 .vce_ebx = 0x74737552,
38 .vce_edx = 0x4f206465,
39 .vce_ecx = 0x65646978,
40 },
41 /* basic "std" leaf */
42 {
43 .vce_function = 1,
44 .vce_eax = 0x100,
45 },
46
47 /* skip 2 for a hole */
48
49 /* leaf with index matching */
50 {
51 .vce_function = 3,
52 .vce_index = 0,
53 .vce_flags = VCE_FLAG_MATCH_INDEX,
54 .vce_eax = 0x300,
55 },
56 {
57 .vce_function = 3,
58 .vce_index = 1,
59 .vce_flags = VCE_FLAG_MATCH_INDEX,
60 .vce_eax = 0x301,
61 },
62
63 /* leaf with index matching and a hole */
64 {
65 .vce_function = 4,
66 .vce_index = 0,
67 .vce_flags = VCE_FLAG_MATCH_INDEX,
68 .vce_eax = 0x400,
69 },
70 {
71 .vce_function = 4,
72 .vce_index = 2,
73 .vce_flags = VCE_FLAG_MATCH_INDEX,
74 .vce_eax = 0x402,
75 },
76
77 /* terminal "std" leaf */
78 {
79 .vce_function = 5,
80 .vce_eax = 5,
81 .vce_ebx = 5,
82 .vce_edx = 5,
83 .vce_ecx = 5,
84 },
85
86 /* base "extended" leaf */
87 {
88 .vce_function = 0x80000000,
89 .vce_eax = 0x80000001,
90 },
91 /* index-match "extended" leaves */
92 {
93 .vce_function = 0x80000001,
94 .vce_index = 0x0,
95 .vce_flags = VCE_FLAG_MATCH_INDEX,
96 .vce_eax = 0x8000,
97 },
98 {
99 .vce_function = 0x80000001,
100 .vce_index = 0x1,
101 .vce_flags = VCE_FLAG_MATCH_INDEX,
102 .vce_eax = 0x8001,
103 },
104 };
105
106 int
main(int argc,char * argv[])107 main(int argc, char *argv[])
108 {
109 const char *test_suite_name = basename(argv[0]);
110 struct vmctx *ctx = NULL;
111 struct vcpu *vcpu;
112 int err;
113
114 ctx = test_initialize(test_suite_name);
115
116 if ((vcpu = vm_vcpu_open(ctx, 0)) == NULL) {
117 test_fail_errno(errno, "Could not open vcpu0");
118 }
119
120 err = test_setup_vcpu(vcpu, MEM_LOC_PAYLOAD, MEM_LOC_STACK);
121 if (err != 0) {
122 test_fail_errno(err, "Could not initialize vcpu0");
123 }
124
125
126 /* Start with test data using Intel-style fallback */
127 int vmfd = vm_get_device_fd(ctx);
128
129 struct vm_vcpu_cpuid_config cfg = {
130 .vvcc_vcpuid = 0,
131 .vvcc_flags = VCC_FLAG_INTEL_FALLBACK,
132 .vvcc_nent = ARRAY_SIZE(test_entries),
133 /* We trust the ioctl not to alter this const value */
134 .vvcc_entries = (struct vcpu_cpuid_entry *)test_entries,
135 };
136 err = ioctl(vmfd, VM_SET_CPUID, &cfg);
137 if (err != 0) {
138 test_fail_errno(err, "ioctl(VM_SET_CPUID) failed");
139 }
140
141 struct vm_entry ventry = { 0 };
142 struct vm_exit vexit = { 0 };
143
144 do {
145 const enum vm_exit_kind kind =
146 test_run_vcpu(vcpu, &ventry, &vexit);
147 switch (kind) {
148 case VEK_REENTR:
149 break;
150 case VEK_TEST_PASS:
151 test_pass();
152 break;
153 case VEK_TEST_FAIL:
154 test_fail_msg("failed result %rip: %x", vexit.rip);
155 break;
156 case VEK_UNHANDLED: {
157 uint32_t val;
158 if (vexit_match_inout(&vexit, false, IOP_TEST_VALUE, 4,
159 &val)) {
160 /*
161 * The payload has requested switch to AMD-style
162 * fallback to run the second half of the test.
163 */
164 cfg.vvcc_flags = 0;
165 err = ioctl(vmfd, VM_SET_CPUID, &cfg);
166 if (err != 0) {
167 test_fail_errno(err,
168 "ioctl(VM_SET_CPUID) failed");
169 }
170 ventry_fulfill_inout(&vexit, &ventry, 0);
171 } else {
172 test_fail_vmexit(&vexit);
173 }
174 break;
175 }
176
177 default:
178 test_fail_vmexit(&vexit);
179 break;
180 }
181 } while (true);
182 }
183