xref: /illumos-gate/usr/src/cmd/bhyve/xmsr.c (revision c94be9439c4f0773ef60e2cec21d548359cfea20)
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 			*val = 0;
126 			break;
127 		case MSR_RAPL_POWER_UNIT:
128 			/*
129 			 * Use the default value documented in section
130 			 * "RAPL Interfaces" in Intel SDM vol3.
131 			 */
132 			*val = 0x000a1003;
133 			break;
134 		default:
135 			error = -1;
136 			break;
137 		}
138 	} else if (cpu_vendor_amd || cpu_vendor_hygon) {
139 		switch (num) {
140 		case MSR_BIOS_SIGN:
141 			*val = 0;
142 			break;
143 		case MSR_HWCR:
144 			/*
145 			 * Bios and Kernel Developer's Guides for AMD Families
146 			 * 12H, 14H, 15H and 16H.
147 			 */
148 			*val = 0x01000010;	/* Reset value */
149 			*val |= 1 << 9;		/* MONITOR/MWAIT disable */
150 			break;
151 
152 		case MSR_NB_CFG1:
153 		case MSR_LS_CFG:
154 		case MSR_IC_CFG:
155 			/*
156 			 * The reset value is processor family dependent so
157 			 * just return 0.
158 			 */
159 			*val = 0;
160 			break;
161 
162 		case MSR_PERFEVSEL0:
163 		case MSR_PERFEVSEL1:
164 		case MSR_PERFEVSEL2:
165 		case MSR_PERFEVSEL3:
166 			/*
167 			 * PerfEvtSel MSRs are not properly virtualized so just
168 			 * return zero.
169 			 */
170 			*val = 0;
171 			break;
172 
173 		case MSR_K7_PERFCTR0:
174 		case MSR_K7_PERFCTR1:
175 		case MSR_K7_PERFCTR2:
176 		case MSR_K7_PERFCTR3:
177 			/*
178 			 * PerfCtr MSRs are not properly virtualized so just
179 			 * return zero.
180 			 */
181 			*val = 0;
182 			break;
183 
184 		case MSR_SMM_ADDR:
185 		case MSR_SMM_MASK:
186 			/*
187 			 * Return the reset value defined in the AMD Bios and
188 			 * Kernel Developer's Guide.
189 			 */
190 			*val = 0;
191 			break;
192 
193 		case MSR_P_STATE_LIMIT:
194 		case MSR_P_STATE_CONTROL:
195 		case MSR_P_STATE_STATUS:
196 		case MSR_P_STATE_CONFIG(0):	/* P0 configuration */
197 			*val = 0;
198 			break;
199 
200 		/*
201 		 * OpenBSD guests test bit 0 of this MSR to detect if the
202 		 * workaround for erratum 721 is already applied.
203 		 * https://support.amd.com/TechDocs/41322_10h_Rev_Gd.pdf
204 		 */
205 		case 0xC0011029:
206 			*val = 1;
207 			break;
208 
209 #ifndef	__FreeBSD__
210 		case MSR_VM_CR:
211 			/*
212 			 * We currently don't support nested virt.
213 			 * Windows seems to ignore the cpuid bits and reads this
214 			 * MSR anyways.
215 			 */
216 			*val = VM_CR_SVMDIS;
217 			break;
218 #endif
219 
220 		default:
221 			error = -1;
222 			break;
223 		}
224 	} else {
225 		error = -1;
226 	}
227 	return (error);
228 }
229 
230 int
231 init_msr(void)
232 {
233 	int error;
234 	u_int regs[4];
235 	char cpu_vendor[13];
236 
237 	do_cpuid(0, regs);
238 	((u_int *)&cpu_vendor)[0] = regs[1];
239 	((u_int *)&cpu_vendor)[1] = regs[3];
240 	((u_int *)&cpu_vendor)[2] = regs[2];
241 	cpu_vendor[12] = '\0';
242 
243 	error = 0;
244 	if (strcmp(cpu_vendor, "AuthenticAMD") == 0) {
245 		cpu_vendor_amd = 1;
246 	} else if (strcmp(cpu_vendor, "HygonGenuine") == 0) {
247 		cpu_vendor_hygon = 1;
248 	} else if (strcmp(cpu_vendor, "GenuineIntel") == 0) {
249 		cpu_vendor_intel = 1;
250 	} else {
251 		EPRINTLN("Unknown cpu vendor \"%s\"", cpu_vendor);
252 		error = -1;
253 	}
254 	return (error);
255 }
256