xref: /illumos-gate/usr/src/cmd/bhyve/xmsr.c (revision cab7c30c9587a8c7b5dd94af5f688dc5b8e8add7)
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 "xmsr.h"
47 
48 static int cpu_vendor_intel, cpu_vendor_amd;
49 
50 int
51 emulate_wrmsr(struct vmctx *ctx, int vcpu, uint32_t num, uint64_t val)
52 {
53 
54 	if (cpu_vendor_intel) {
55 		switch (num) {
56 #ifndef	__FreeBSD__
57 		case MSR_PERFCTR0:
58 		case MSR_PERFCTR1:
59 		case MSR_EVNTSEL0:
60 		case MSR_EVNTSEL1:
61 			return (0);
62 #endif
63 		case 0xd04:		/* Sandy Bridge uncore PMCs */
64 		case 0xc24:
65 			return (0);
66 		case MSR_BIOS_UPDT_TRIG:
67 			return (0);
68 		case MSR_BIOS_SIGN:
69 			return (0);
70 		default:
71 			break;
72 		}
73 	} else if (cpu_vendor_amd) {
74 		switch (num) {
75 		case MSR_HWCR:
76 			/*
77 			 * Ignore writes to hardware configuration MSR.
78 			 */
79 			return (0);
80 
81 		case MSR_NB_CFG1:
82 		case MSR_LS_CFG:
83 		case MSR_IC_CFG:
84 			return (0);	/* Ignore writes */
85 
86 		case MSR_PERFEVSEL0:
87 		case MSR_PERFEVSEL1:
88 		case MSR_PERFEVSEL2:
89 		case MSR_PERFEVSEL3:
90 			/* Ignore writes to the PerfEvtSel MSRs */
91 			return (0);
92 
93 		case MSR_K7_PERFCTR0:
94 		case MSR_K7_PERFCTR1:
95 		case MSR_K7_PERFCTR2:
96 		case MSR_K7_PERFCTR3:
97 			/* Ignore writes to the PerfCtr MSRs */
98 			return (0);
99 
100 		case MSR_P_STATE_CONTROL:
101 			/* Ignore write to change the P-state */
102 			return (0);
103 
104 		default:
105 			break;
106 		}
107 	}
108 	return (-1);
109 }
110 
111 int
112 emulate_rdmsr(struct vmctx *ctx, int vcpu, uint32_t num, uint64_t *val)
113 {
114 	int error = 0;
115 
116 	if (cpu_vendor_intel) {
117 		switch (num) {
118 		case MSR_BIOS_SIGN:
119 		case MSR_IA32_PLATFORM_ID:
120 		case MSR_PKG_ENERGY_STATUS:
121 		case MSR_PP0_ENERGY_STATUS:
122 		case MSR_PP1_ENERGY_STATUS:
123 		case MSR_DRAM_ENERGY_STATUS:
124 			*val = 0;
125 			break;
126 		case MSR_RAPL_POWER_UNIT:
127 			/*
128 			 * Use the default value documented in section
129 			 * "RAPL Interfaces" in Intel SDM vol3.
130 			 */
131 			*val = 0x000a1003;
132 			break;
133 		default:
134 			error = -1;
135 			break;
136 		}
137 	} else if (cpu_vendor_amd) {
138 		switch (num) {
139 		case MSR_BIOS_SIGN:
140 			*val = 0;
141 			break;
142 		case MSR_HWCR:
143 			/*
144 			 * Bios and Kernel Developer's Guides for AMD Families
145 			 * 12H, 14H, 15H and 16H.
146 			 */
147 			*val = 0x01000010;	/* Reset value */
148 			*val |= 1 << 9;		/* MONITOR/MWAIT disable */
149 			break;
150 
151 		case MSR_NB_CFG1:
152 		case MSR_LS_CFG:
153 		case MSR_IC_CFG:
154 			/*
155 			 * The reset value is processor family dependent so
156 			 * just return 0.
157 			 */
158 			*val = 0;
159 			break;
160 
161 		case MSR_PERFEVSEL0:
162 		case MSR_PERFEVSEL1:
163 		case MSR_PERFEVSEL2:
164 		case MSR_PERFEVSEL3:
165 			/*
166 			 * PerfEvtSel MSRs are not properly virtualized so just
167 			 * return zero.
168 			 */
169 			*val = 0;
170 			break;
171 
172 		case MSR_K7_PERFCTR0:
173 		case MSR_K7_PERFCTR1:
174 		case MSR_K7_PERFCTR2:
175 		case MSR_K7_PERFCTR3:
176 			/*
177 			 * PerfCtr MSRs are not properly virtualized so just
178 			 * return zero.
179 			 */
180 			*val = 0;
181 			break;
182 
183 		case MSR_SMM_ADDR:
184 		case MSR_SMM_MASK:
185 			/*
186 			 * Return the reset value defined in the AMD Bios and
187 			 * Kernel Developer's Guide.
188 			 */
189 			*val = 0;
190 			break;
191 
192 		case MSR_P_STATE_LIMIT:
193 		case MSR_P_STATE_CONTROL:
194 		case MSR_P_STATE_STATUS:
195 		case MSR_P_STATE_CONFIG(0):	/* P0 configuration */
196 			*val = 0;
197 			break;
198 
199 		/*
200 		 * OpenBSD guests test bit 0 of this MSR to detect if the
201 		 * workaround for erratum 721 is already applied.
202 		 * https://support.amd.com/TechDocs/41322_10h_Rev_Gd.pdf
203 		 */
204 		case 0xC0011029:
205 			*val = 1;
206 			break;
207 
208 #ifndef	__FreeBSD__
209 		case MSR_VM_CR:
210 			/*
211 			 * We currently don't support nested virt.
212 			 * Windows seems to ignore the cpuid bits and reads this
213 			 * MSR anyways.
214 			 */
215 			*val = VM_CR_SVMDIS;
216 			break;
217 #endif
218 
219 		default:
220 			error = -1;
221 			break;
222 		}
223 	} else {
224 		error = -1;
225 	}
226 	return (error);
227 }
228 
229 int
230 init_msr(void)
231 {
232 	int error;
233 	u_int regs[4];
234 	char cpu_vendor[13];
235 
236 	do_cpuid(0, regs);
237 	((u_int *)&cpu_vendor)[0] = regs[1];
238 	((u_int *)&cpu_vendor)[1] = regs[3];
239 	((u_int *)&cpu_vendor)[2] = regs[2];
240 	cpu_vendor[12] = '\0';
241 
242 	error = 0;
243 	if (strcmp(cpu_vendor, "AuthenticAMD") == 0) {
244 		cpu_vendor_amd = 1;
245 	} else if (strcmp(cpu_vendor, "GenuineIntel") == 0) {
246 		cpu_vendor_intel = 1;
247 	} else {
248 		fprintf(stderr, "Unknown cpu vendor \"%s\"\n", cpu_vendor);
249 		error = -1;
250 	}
251 	return (error);
252 }
253