xref: /illumos-gate/usr/src/cmd/bhyve/xmsr.c (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2011 NetApp, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include <sys/types.h>
35 
36 #include <machine/cpufunc.h>
37 #include <machine/vmm.h>
38 #include <machine/specialreg.h>
39 
40 #include <vmmapi.h>
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 
46 #include "debug.h"
47 #include "xmsr.h"
48 
49 static int cpu_vendor_intel, cpu_vendor_amd, cpu_vendor_hygon;
50 
51 int
52 emulate_wrmsr(struct vmctx *ctx, int vcpu, uint32_t num, uint64_t val)
53 {
54 
55 	if (cpu_vendor_intel) {
56 		switch (num) {
57 #ifndef	__FreeBSD__
58 		case MSR_PERFCTR0:
59 		case MSR_PERFCTR1:
60 		case MSR_EVNTSEL0:
61 		case MSR_EVNTSEL1:
62 			return (0);
63 #endif
64 		case 0xd04:		/* Sandy Bridge uncore PMCs */
65 		case 0xc24:
66 			return (0);
67 		case MSR_BIOS_UPDT_TRIG:
68 			return (0);
69 		case MSR_BIOS_SIGN:
70 			return (0);
71 		default:
72 			break;
73 		}
74 	} else if (cpu_vendor_amd || cpu_vendor_hygon) {
75 		switch (num) {
76 		case MSR_HWCR:
77 			/*
78 			 * Ignore writes to hardware configuration MSR.
79 			 */
80 			return (0);
81 
82 		case MSR_NB_CFG1:
83 		case MSR_LS_CFG:
84 		case MSR_IC_CFG:
85 			return (0);	/* Ignore writes */
86 
87 		case MSR_PERFEVSEL0:
88 		case MSR_PERFEVSEL1:
89 		case MSR_PERFEVSEL2:
90 		case MSR_PERFEVSEL3:
91 			/* Ignore writes to the PerfEvtSel MSRs */
92 			return (0);
93 
94 		case MSR_K7_PERFCTR0:
95 		case MSR_K7_PERFCTR1:
96 		case MSR_K7_PERFCTR2:
97 		case MSR_K7_PERFCTR3:
98 			/* Ignore writes to the PerfCtr MSRs */
99 			return (0);
100 
101 		case MSR_P_STATE_CONTROL:
102 			/* Ignore write to change the P-state */
103 			return (0);
104 
105 		default:
106 			break;
107 		}
108 	}
109 	return (-1);
110 }
111 
112 int
113 emulate_rdmsr(struct vmctx *ctx, int vcpu, uint32_t num, uint64_t *val)
114 {
115 	int error = 0;
116 
117 	if (cpu_vendor_intel) {
118 		switch (num) {
119 		case MSR_BIOS_SIGN:
120 		case MSR_IA32_PLATFORM_ID:
121 		case MSR_PKG_ENERGY_STATUS:
122 		case MSR_PP0_ENERGY_STATUS:
123 		case MSR_PP1_ENERGY_STATUS:
124 		case MSR_DRAM_ENERGY_STATUS:
125 		case MSR_MISC_FEATURE_ENABLES:
126 			*val = 0;
127 			break;
128 		case MSR_RAPL_POWER_UNIT:
129 			/*
130 			 * Use the default value documented in section
131 			 * "RAPL Interfaces" in Intel SDM vol3.
132 			 */
133 			*val = 0x000a1003;
134 			break;
135 		case MSR_IA32_FEATURE_CONTROL:
136 			/*
137 			 * Windows guests check this MSR.
138 			 * Set the lock bit to avoid writes
139 			 * to this MSR.
140 			 */
141 			*val = IA32_FEATURE_CONTROL_LOCK;
142 			break;
143 		default:
144 			error = -1;
145 			break;
146 		}
147 	} else if (cpu_vendor_amd || cpu_vendor_hygon) {
148 		switch (num) {
149 		case MSR_BIOS_SIGN:
150 			*val = 0;
151 			break;
152 		case MSR_HWCR:
153 			/*
154 			 * Bios and Kernel Developer's Guides for AMD Families
155 			 * 12H, 14H, 15H and 16H.
156 			 */
157 			*val = 0x01000010;	/* Reset value */
158 			*val |= 1 << 9;		/* MONITOR/MWAIT disable */
159 			break;
160 
161 		case MSR_NB_CFG1:
162 		case MSR_LS_CFG:
163 		case MSR_IC_CFG:
164 			/*
165 			 * The reset value is processor family dependent so
166 			 * just return 0.
167 			 */
168 			*val = 0;
169 			break;
170 
171 		case MSR_PERFEVSEL0:
172 		case MSR_PERFEVSEL1:
173 		case MSR_PERFEVSEL2:
174 		case MSR_PERFEVSEL3:
175 			/*
176 			 * PerfEvtSel MSRs are not properly virtualized so just
177 			 * return zero.
178 			 */
179 			*val = 0;
180 			break;
181 
182 		case MSR_K7_PERFCTR0:
183 		case MSR_K7_PERFCTR1:
184 		case MSR_K7_PERFCTR2:
185 		case MSR_K7_PERFCTR3:
186 			/*
187 			 * PerfCtr MSRs are not properly virtualized so just
188 			 * return zero.
189 			 */
190 			*val = 0;
191 			break;
192 
193 		case MSR_SMM_ADDR:
194 		case MSR_SMM_MASK:
195 			/*
196 			 * Return the reset value defined in the AMD Bios and
197 			 * Kernel Developer's Guide.
198 			 */
199 			*val = 0;
200 			break;
201 
202 		case MSR_P_STATE_LIMIT:
203 		case MSR_P_STATE_CONTROL:
204 		case MSR_P_STATE_STATUS:
205 		case MSR_P_STATE_CONFIG(0):	/* P0 configuration */
206 			*val = 0;
207 			break;
208 
209 		/*
210 		 * OpenBSD guests test bit 0 of this MSR to detect if the
211 		 * workaround for erratum 721 is already applied.
212 		 * https://support.amd.com/TechDocs/41322_10h_Rev_Gd.pdf
213 		 */
214 		case 0xC0011029:
215 			*val = 1;
216 			break;
217 
218 #ifndef	__FreeBSD__
219 		case MSR_VM_CR:
220 			/*
221 			 * We currently don't support nested virt.
222 			 * Windows seems to ignore the cpuid bits and reads this
223 			 * MSR anyways.
224 			 */
225 			*val = VM_CR_SVMDIS;
226 			break;
227 #endif
228 
229 		default:
230 			error = -1;
231 			break;
232 		}
233 	} else {
234 		error = -1;
235 	}
236 	return (error);
237 }
238 
239 int
240 init_msr(void)
241 {
242 	int error;
243 	u_int regs[4];
244 	char cpu_vendor[13];
245 
246 	do_cpuid(0, regs);
247 	((u_int *)&cpu_vendor)[0] = regs[1];
248 	((u_int *)&cpu_vendor)[1] = regs[3];
249 	((u_int *)&cpu_vendor)[2] = regs[2];
250 	cpu_vendor[12] = '\0';
251 
252 	error = 0;
253 	if (strcmp(cpu_vendor, "AuthenticAMD") == 0) {
254 		cpu_vendor_amd = 1;
255 	} else if (strcmp(cpu_vendor, "HygonGenuine") == 0) {
256 		cpu_vendor_hygon = 1;
257 	} else if (strcmp(cpu_vendor, "GenuineIntel") == 0) {
258 		cpu_vendor_intel = 1;
259 	} else {
260 		EPRINTLN("Unknown cpu vendor \"%s\"", cpu_vendor);
261 		error = -1;
262 	}
263 	return (error);
264 }
265