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