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