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