xref: /freebsd/usr.sbin/bhyve/amd64/xmsr.c (revision dc36d6f9bb1753f3808552f3afd30eda9a7b206a)
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 #include <sys/cdefs.h>
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 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #include <vmmapi.h>
42 
43 #include "debug.h"
44 #include "xmsr.h"
45 
46 static int cpu_vendor_intel, cpu_vendor_amd, cpu_vendor_hygon;
47 
48 int
49 emulate_wrmsr(struct vcpu *vcpu __unused, uint32_t num, uint64_t val __unused)
50 {
51 
52 	if (cpu_vendor_intel) {
53 		switch (num) {
54 		case 0xd04:		/* Sandy Bridge uncore PMCs */
55 		case 0xc24:
56 			return (0);
57 		case MSR_BIOS_UPDT_TRIG:
58 			return (0);
59 		case MSR_BIOS_SIGN:
60 			return (0);
61 		default:
62 			break;
63 		}
64 	} else if (cpu_vendor_amd || cpu_vendor_hygon) {
65 		switch (num) {
66 		case MSR_HWCR:
67 			/*
68 			 * Ignore writes to hardware configuration MSR.
69 			 */
70 			return (0);
71 
72 		case MSR_NB_CFG1:
73 		case MSR_LS_CFG:
74 		case MSR_IC_CFG:
75 			return (0);	/* Ignore writes */
76 
77 		case MSR_PERFEVSEL0:
78 		case MSR_PERFEVSEL1:
79 		case MSR_PERFEVSEL2:
80 		case MSR_PERFEVSEL3:
81 			/* Ignore writes to the PerfEvtSel MSRs */
82 			return (0);
83 
84 		case MSR_K7_PERFCTR0:
85 		case MSR_K7_PERFCTR1:
86 		case MSR_K7_PERFCTR2:
87 		case MSR_K7_PERFCTR3:
88 			/* Ignore writes to the PerfCtr MSRs */
89 			return (0);
90 
91 		case MSR_P_STATE_CONTROL:
92 			/* Ignore write to change the P-state */
93 			return (0);
94 
95 		default:
96 			break;
97 		}
98 	}
99 	return (-1);
100 }
101 
102 int
103 emulate_rdmsr(struct vcpu *vcpu __unused, uint32_t num, uint64_t *val)
104 {
105 	int error = 0;
106 
107 	if (cpu_vendor_intel) {
108 		switch (num) {
109 		case MSR_BIOS_SIGN:
110 		case MSR_IA32_PLATFORM_ID:
111 		case MSR_PKG_ENERGY_STATUS:
112 		case MSR_PP0_ENERGY_STATUS:
113 		case MSR_PP1_ENERGY_STATUS:
114 		case MSR_DRAM_ENERGY_STATUS:
115 		case MSR_MISC_FEATURE_ENABLES:
116 			*val = 0;
117 			break;
118 		case MSR_RAPL_POWER_UNIT:
119 			/*
120 			 * Use the default value documented in section
121 			 * "RAPL Interfaces" in Intel SDM vol3.
122 			 */
123 			*val = 0x000a1003;
124 			break;
125 		case MSR_IA32_FEATURE_CONTROL:
126 			/*
127 			 * Windows guests check this MSR.
128 			 * Set the lock bit to avoid writes
129 			 * to this MSR.
130 			 */
131 			*val = IA32_FEATURE_CONTROL_LOCK;
132 			break;
133 		default:
134 			error = -1;
135 			break;
136 		}
137 	} else if (cpu_vendor_amd || cpu_vendor_hygon) {
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 		default:
209 			error = -1;
210 			break;
211 		}
212 	} else {
213 		error = -1;
214 	}
215 	return (error);
216 }
217 
218 int
219 init_msr(void)
220 {
221 	int error;
222 	u_int regs[4];
223 	char cpu_vendor[13];
224 
225 	do_cpuid(0, regs);
226 	((u_int *)&cpu_vendor)[0] = regs[1];
227 	((u_int *)&cpu_vendor)[1] = regs[3];
228 	((u_int *)&cpu_vendor)[2] = regs[2];
229 	cpu_vendor[12] = '\0';
230 
231 	error = 0;
232 	if (strcmp(cpu_vendor, "AuthenticAMD") == 0) {
233 		cpu_vendor_amd = 1;
234 	} else if (strcmp(cpu_vendor, "HygonGenuine") == 0) {
235 		cpu_vendor_hygon = 1;
236 	} else if (strcmp(cpu_vendor, "GenuineIntel") == 0) {
237 		cpu_vendor_intel = 1;
238 	} else {
239 		EPRINTLN("Unknown cpu vendor \"%s\"", cpu_vendor);
240 		error = ENOENT;
241 	}
242 	return (error);
243 }
244