x86.c revision 256869
1221828Sgrehan/*- 2221828Sgrehan * Copyright (c) 2011 NetApp, Inc. 3221828Sgrehan * All rights reserved. 4221828Sgrehan * 5221828Sgrehan * Redistribution and use in source and binary forms, with or without 6221828Sgrehan * modification, are permitted provided that the following conditions 7221828Sgrehan * are met: 8221828Sgrehan * 1. Redistributions of source code must retain the above copyright 9221828Sgrehan * notice, this list of conditions and the following disclaimer. 10221828Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 11221828Sgrehan * notice, this list of conditions and the following disclaimer in the 12221828Sgrehan * documentation and/or other materials provided with the distribution. 13221828Sgrehan * 14221828Sgrehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15221828Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16221828Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17221828Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18221828Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19221828Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20221828Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21221828Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22221828Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23221828Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24221828Sgrehan * SUCH DAMAGE. 25221828Sgrehan * 26221828Sgrehan * $FreeBSD: stable/10/sys/amd64/vmm/x86.c 256869 2013-10-22 00:58:51Z neel $ 27221828Sgrehan */ 28221828Sgrehan 29221828Sgrehan#include <sys/cdefs.h> 30221828Sgrehan__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/x86.c 256869 2013-10-22 00:58:51Z neel $"); 31221828Sgrehan 32240941Sneel#include <sys/param.h> 33221828Sgrehan#include <sys/types.h> 34222610Sjhb#include <sys/systm.h> 35240941Sneel#include <sys/cpuset.h> 36221828Sgrehan 37249324Sneel#include <machine/clock.h> 38221828Sgrehan#include <machine/cpufunc.h> 39222610Sjhb#include <machine/md_var.h> 40221828Sgrehan#include <machine/specialreg.h> 41221828Sgrehan 42240941Sneel#include <machine/vmm.h> 43240941Sneel 44221828Sgrehan#include "x86.h" 45221828Sgrehan 46222610Sjhb#define CPUID_VM_HIGH 0x40000000 47222610Sjhb 48252335Sgrehanstatic const char bhyve_id[12] = "bhyve bhyve "; 49222610Sjhb 50252335Sgrehanstatic uint64_t bhyve_xcpuids; 51252335Sgrehan 52221828Sgrehanint 53240941Sneelx86_emulate_cpuid(struct vm *vm, int vcpu_id, 54240941Sneel uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) 55221828Sgrehan{ 56256869Sneel int error, enable_invpcid; 57221828Sgrehan unsigned int func, regs[4]; 58240941Sneel enum x2apic_state x2apic_state; 59221828Sgrehan 60222610Sjhb /* 61222610Sjhb * Requests for invalid CPUID levels should map to the highest 62222610Sjhb * available level instead. 63222610Sjhb */ 64222610Sjhb if (cpu_exthigh != 0 && *eax >= 0x80000000) { 65222610Sjhb if (*eax > cpu_exthigh) 66222610Sjhb *eax = cpu_exthigh; 67222610Sjhb } else if (*eax >= 0x40000000) { 68222610Sjhb if (*eax > CPUID_VM_HIGH) 69222610Sjhb *eax = CPUID_VM_HIGH; 70222610Sjhb } else if (*eax > cpu_high) { 71222610Sjhb *eax = cpu_high; 72222610Sjhb } 73221828Sgrehan 74246774Sneel func = *eax; 75246774Sneel 76222610Sjhb /* 77222610Sjhb * In general the approach used for CPU topology is to 78222610Sjhb * advertise a flat topology where all CPUs are packages with 79222610Sjhb * no multi-core or SMT. 80222610Sjhb */ 81222610Sjhb switch (func) { 82252335Sgrehan /* 83252335Sgrehan * Pass these through to the guest 84252335Sgrehan */ 85221828Sgrehan case CPUID_0000_0000: 86221828Sgrehan case CPUID_0000_0002: 87221828Sgrehan case CPUID_0000_0003: 88221828Sgrehan case CPUID_8000_0000: 89221828Sgrehan case CPUID_8000_0002: 90221828Sgrehan case CPUID_8000_0003: 91221828Sgrehan case CPUID_8000_0004: 92221828Sgrehan case CPUID_8000_0006: 93221828Sgrehan case CPUID_8000_0008: 94222610Sjhb cpuid_count(*eax, *ecx, regs); 95221828Sgrehan break; 96221828Sgrehan 97252335Sgrehan case CPUID_8000_0001: 98252335Sgrehan /* 99252335Sgrehan * Hide rdtscp/ia32_tsc_aux until we know how 100252335Sgrehan * to deal with them. 101252335Sgrehan */ 102252335Sgrehan cpuid_count(*eax, *ecx, regs); 103252335Sgrehan regs[3] &= ~AMDID_RDTSCP; 104252335Sgrehan break; 105252335Sgrehan 106249324Sneel case CPUID_8000_0007: 107249324Sneel cpuid_count(*eax, *ecx, regs); 108249324Sneel /* 109249324Sneel * If the host TSCs are not synchronized across 110249324Sneel * physical cpus then we cannot advertise an 111249324Sneel * invariant tsc to a vcpu. 112249324Sneel * 113249324Sneel * XXX This still falls short because the vcpu 114249324Sneel * can observe the TSC moving backwards as it 115249324Sneel * migrates across physical cpus. But at least 116249324Sneel * it should discourage the guest from using the 117249324Sneel * TSC to keep track of time. 118249324Sneel */ 119249324Sneel if (!smp_tsc) 120249324Sneel regs[3] &= ~AMDPM_TSC_INVARIANT; 121249324Sneel break; 122249324Sneel 123221828Sgrehan case CPUID_0000_0001: 124222610Sjhb do_cpuid(1, regs); 125222610Sjhb 126240941Sneel error = vm_get_x2apic_state(vm, vcpu_id, &x2apic_state); 127240941Sneel if (error) { 128240941Sneel panic("x86_emulate_cpuid: error %d " 129240941Sneel "fetching x2apic state", error); 130240941Sneel } 131240941Sneel 132221828Sgrehan /* 133221828Sgrehan * Override the APIC ID only in ebx 134221828Sgrehan */ 135222610Sjhb regs[1] &= ~(CPUID_LOCAL_APIC_ID); 136222610Sjhb regs[1] |= (vcpu_id << CPUID_0000_0001_APICID_SHIFT); 137221828Sgrehan 138221828Sgrehan /* 139222105Sgrehan * Don't expose VMX, SpeedStep or TME capability. 140222610Sjhb * Advertise x2APIC capability and Hypervisor guest. 141221828Sgrehan */ 142222610Sjhb regs[2] &= ~(CPUID2_VMX | CPUID2_EST | CPUID2_TM2); 143221828Sgrehan 144240941Sneel regs[2] |= CPUID2_HV; 145240941Sneel 146240941Sneel if (x2apic_state != X2APIC_DISABLED) 147240941Sneel regs[2] |= CPUID2_X2APIC; 148240941Sneel 149221828Sgrehan /* 150234939Sgrehan * Hide xsave/osxsave/avx until the FPU save/restore 151234939Sgrehan * issues are resolved 152234939Sgrehan */ 153234939Sgrehan regs[2] &= ~(CPUID2_XSAVE | CPUID2_OSXSAVE | 154234939Sgrehan CPUID2_AVX); 155234939Sgrehan 156234939Sgrehan /* 157242060Sneel * Hide monitor/mwait until we know how to deal with 158242060Sneel * these instructions. 159242060Sneel */ 160242060Sneel regs[2] &= ~CPUID2_MON; 161242060Sneel 162252335Sgrehan /* 163252335Sgrehan * Hide the performance and debug features. 164252335Sgrehan */ 165252335Sgrehan regs[2] &= ~CPUID2_PDCM; 166255645Sgrehan 167242060Sneel /* 168255645Sgrehan * No TSC deadline support in the APIC yet 169255645Sgrehan */ 170255645Sgrehan regs[2] &= ~CPUID2_TSCDLT; 171255645Sgrehan 172255645Sgrehan /* 173222105Sgrehan * Hide thermal monitoring 174222105Sgrehan */ 175222105Sgrehan regs[3] &= ~(CPUID_ACPI | CPUID_TM); 176222105Sgrehan 177222105Sgrehan /* 178221828Sgrehan * Machine check handling is done in the host. 179221828Sgrehan * Hide MTRR capability. 180221828Sgrehan */ 181221828Sgrehan regs[3] &= ~(CPUID_MCA | CPUID_MCE | CPUID_MTRR); 182221828Sgrehan 183252335Sgrehan /* 184252335Sgrehan * Hide the debug store capability. 185252335Sgrehan */ 186252335Sgrehan regs[3] &= ~CPUID_DS; 187252335Sgrehan 188222610Sjhb /* 189222610Sjhb * Disable multi-core. 190222610Sjhb */ 191222610Sjhb regs[1] &= ~CPUID_HTT_CORES; 192222610Sjhb regs[3] &= ~CPUID_HTT; 193221828Sgrehan break; 194221828Sgrehan 195222610Sjhb case CPUID_0000_0004: 196222610Sjhb do_cpuid(4, regs); 197222610Sjhb 198222610Sjhb /* 199222610Sjhb * Do not expose topology. 200222610Sjhb */ 201222610Sjhb regs[0] &= 0xffff8000; 202222610Sjhb regs[0] |= 0x04008000; 203222610Sjhb break; 204222610Sjhb 205256869Sneel case CPUID_0000_0007: 206256869Sneel regs[0] = 0; 207256869Sneel regs[1] = 0; 208256869Sneel regs[2] = 0; 209256869Sneel regs[3] = 0; 210256869Sneel 211256869Sneel /* leaf 0 */ 212256869Sneel if (*ecx == 0) { 213256869Sneel error = vm_get_capability(vm, vcpu_id, 214256869Sneel VM_CAP_ENABLE_INVPCID, &enable_invpcid); 215256869Sneel if (error == 0 && enable_invpcid) 216256869Sneel regs[1] |= CPUID_STDEXT_INVPCID; 217256869Sneel } 218256869Sneel break; 219256869Sneel 220222105Sgrehan case CPUID_0000_0006: 221252335Sgrehan case CPUID_0000_000A: 222255287Sgrehan case CPUID_0000_000D: 223222105Sgrehan /* 224222105Sgrehan * Handle the access, but report 0 for 225222105Sgrehan * all options 226222105Sgrehan */ 227222105Sgrehan regs[0] = 0; 228222105Sgrehan regs[1] = 0; 229222105Sgrehan regs[2] = 0; 230222105Sgrehan regs[3] = 0; 231222105Sgrehan break; 232222105Sgrehan 233221828Sgrehan case CPUID_0000_000B: 234221828Sgrehan /* 235221828Sgrehan * Processor topology enumeration 236221828Sgrehan */ 237221828Sgrehan regs[0] = 0; 238221828Sgrehan regs[1] = 0; 239221828Sgrehan regs[2] = *ecx & 0xff; 240222610Sjhb regs[3] = vcpu_id; 241221828Sgrehan break; 242221828Sgrehan 243222610Sjhb case 0x40000000: 244222610Sjhb regs[0] = CPUID_VM_HIGH; 245222610Sjhb bcopy(bhyve_id, ®s[1], 4); 246252335Sgrehan bcopy(bhyve_id + 4, ®s[2], 4); 247252335Sgrehan bcopy(bhyve_id + 8, ®s[3], 4); 248222610Sjhb break; 249252335Sgrehan 250221828Sgrehan default: 251252335Sgrehan /* 252252335Sgrehan * The leaf value has already been clamped so 253252335Sgrehan * simply pass this through, keeping count of 254252335Sgrehan * how many unhandled leaf values have been seen. 255252335Sgrehan */ 256252335Sgrehan atomic_add_long(&bhyve_xcpuids, 1); 257252335Sgrehan cpuid_count(*eax, *ecx, regs); 258252335Sgrehan break; 259221828Sgrehan } 260221828Sgrehan 261221828Sgrehan *eax = regs[0]; 262221828Sgrehan *ebx = regs[1]; 263221828Sgrehan *ecx = regs[2]; 264221828Sgrehan *edx = regs[3]; 265252335Sgrehan 266221828Sgrehan return (1); 267221828Sgrehan} 268