xref: /illumos-gate/usr/src/test/bhyve-tests/tests/inst_emul/cpuid.c (revision dd72704bd9e794056c558153663c739e2012d721)
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 
23 #include <sys/types.h>
24 #include <sys/sysmacros.h>
25 #include <sys/debug.h>
26 #include <sys/vmm.h>
27 #include <sys/vmm_dev.h>
28 #include <vmmapi.h>
29 
30 #include "in_guest.h"
31 
32 static const struct vcpu_cpuid_entry test_entries[] = {
33 	{
34 		.vce_function = 0,
35 		.vce_eax = 5,
36 		.vce_ebx = 0x74737552,
37 		.vce_edx = 0x4f206465,
38 		.vce_ecx = 0x65646978,
39 	},
40 	/* basic "std" leaf */
41 	{
42 		.vce_function = 1,
43 		.vce_eax = 0x100,
44 	},
45 
46 	/* skip 2 for a hole */
47 
48 	/* leaf with index matching */
49 	{
50 		.vce_function = 3,
51 		.vce_index = 0,
52 		.vce_flags = VCE_FLAG_MATCH_INDEX,
53 		.vce_eax = 0x300,
54 	},
55 	{
56 		.vce_function = 3,
57 		.vce_index = 1,
58 		.vce_flags = VCE_FLAG_MATCH_INDEX,
59 		.vce_eax = 0x301,
60 	},
61 
62 	/* leaf with index matching and a hole */
63 	{
64 		.vce_function = 4,
65 		.vce_index = 0,
66 		.vce_flags = VCE_FLAG_MATCH_INDEX,
67 		.vce_eax = 0x400,
68 	},
69 	{
70 		.vce_function = 4,
71 		.vce_index = 2,
72 		.vce_flags = VCE_FLAG_MATCH_INDEX,
73 		.vce_eax = 0x402,
74 	},
75 
76 	/* terminal "std" leaf */
77 	{
78 		.vce_function = 5,
79 		.vce_eax = 5,
80 		.vce_ebx = 5,
81 		.vce_edx = 5,
82 		.vce_ecx = 5,
83 	},
84 
85 	/* base "extended" leaf */
86 	{
87 		.vce_function = 0x80000000,
88 		.vce_eax = 0x80000001,
89 	},
90 	/* index-match "extended" leaves */
91 	{
92 		.vce_function = 0x80000001,
93 		.vce_index = 0x0,
94 		.vce_flags = VCE_FLAG_MATCH_INDEX,
95 		.vce_eax = 0x8000,
96 	},
97 	{
98 		.vce_function = 0x80000001,
99 		.vce_index = 0x1,
100 		.vce_flags = VCE_FLAG_MATCH_INDEX,
101 		.vce_eax = 0x8001,
102 	},
103 };
104 
105 int
106 main(int argc, char *argv[])
107 {
108 	const char *test_suite_name = basename(argv[0]);
109 	struct vmctx *ctx = NULL;
110 	int err;
111 
112 	ctx = test_initialize(test_suite_name);
113 
114 	err = test_setup_vcpu(ctx, 0, MEM_LOC_PAYLOAD, MEM_LOC_STACK);
115 	if (err != 0) {
116 		test_fail_errno(err, "Could not initialize vcpu0");
117 	}
118 
119 
120 	/* Start with test data using Intel-style fallback */
121 	int vmfd = vm_get_device_fd(ctx);
122 
123 	struct vm_vcpu_cpuid_config cfg = {
124 		.vvcc_vcpuid = 0,
125 		.vvcc_flags = VCC_FLAG_INTEL_FALLBACK,
126 		.vvcc_nent = ARRAY_SIZE(test_entries),
127 		/* We trust the ioctl not to alter this const value */
128 		.vvcc_entries = (struct vcpu_cpuid_entry *)test_entries,
129 	};
130 	err = ioctl(vmfd, VM_SET_CPUID, &cfg);
131 	if (err != 0) {
132 		test_fail_errno(err, "ioctl(VM_SET_CPUID) failed");
133 	}
134 
135 	struct vm_entry ventry = { 0 };
136 	struct vm_exit vexit = { 0 };
137 
138 	do {
139 		const enum vm_exit_kind kind =
140 		    test_run_vcpu(ctx, 0, &ventry, &vexit);
141 		switch (kind) {
142 		case VEK_REENTR:
143 			break;
144 		case VEK_TEST_PASS:
145 			test_pass();
146 			break;
147 		case VEK_TEST_FAIL:
148 			test_fail_msg("failed result %rip: %x", vexit.rip);
149 			break;
150 		case VEK_UNHANDLED: {
151 			uint32_t val;
152 			if (vexit_match_inout(&vexit, false, IOP_TEST_VALUE, 4,
153 			    &val)) {
154 				/*
155 				 * The payload has requested switch to AMD-style
156 				 * fallback to run the second half of the test.
157 				 */
158 				cfg.vvcc_flags = 0;
159 				err = ioctl(vmfd, VM_SET_CPUID, &cfg);
160 				if (err != 0) {
161 					test_fail_errno(err,
162 					    "ioctl(VM_SET_CPUID) failed");
163 				}
164 				ventry_fulfill_inout(&vexit, &ventry, 0);
165 			} else {
166 				test_fail_vmexit(&vexit);
167 			}
168 			break;
169 		}
170 
171 		default:
172 			test_fail_vmexit(&vexit);
173 			break;
174 		}
175 	} while (true);
176 }
177