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