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 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 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 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