1366f6083SPeter Grehan /*- 2366f6083SPeter Grehan * Copyright (c) 2011 NetApp, Inc. 3366f6083SPeter Grehan * All rights reserved. 4366f6083SPeter Grehan * 5366f6083SPeter Grehan * Redistribution and use in source and binary forms, with or without 6366f6083SPeter Grehan * modification, are permitted provided that the following conditions 7366f6083SPeter Grehan * are met: 8366f6083SPeter Grehan * 1. Redistributions of source code must retain the above copyright 9366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer. 10366f6083SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 11366f6083SPeter Grehan * notice, this list of conditions and the following disclaimer in the 12366f6083SPeter Grehan * documentation and/or other materials provided with the distribution. 13366f6083SPeter Grehan * 14366f6083SPeter Grehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15366f6083SPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16366f6083SPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17366f6083SPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18366f6083SPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19366f6083SPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20366f6083SPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21366f6083SPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22366f6083SPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23366f6083SPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24366f6083SPeter Grehan * SUCH DAMAGE. 25366f6083SPeter Grehan * 26366f6083SPeter Grehan * $FreeBSD$ 27366f6083SPeter Grehan */ 28366f6083SPeter Grehan 29366f6083SPeter Grehan #include <sys/cdefs.h> 30366f6083SPeter Grehan __FBSDID("$FreeBSD$"); 31366f6083SPeter Grehan 32a2da7af6SNeel Natu #include <sys/param.h> 33abb023fbSJohn Baldwin #include <sys/pcpu.h> 348b287612SJohn Baldwin #include <sys/systm.h> 35a2da7af6SNeel Natu #include <sys/cpuset.h> 368bd3845dSNeel Natu #include <sys/sysctl.h> 37366f6083SPeter Grehan 381472b87fSNeel Natu #include <machine/clock.h> 39366f6083SPeter Grehan #include <machine/cpufunc.h> 408b287612SJohn Baldwin #include <machine/md_var.h> 41abb023fbSJohn Baldwin #include <machine/segments.h> 42366f6083SPeter Grehan #include <machine/specialreg.h> 43366f6083SPeter Grehan 44a2da7af6SNeel Natu #include <machine/vmm.h> 45a2da7af6SNeel Natu 46abb023fbSJohn Baldwin #include "vmm_host.h" 47366f6083SPeter Grehan #include "x86.h" 48366f6083SPeter Grehan 498bd3845dSNeel Natu SYSCTL_DECL(_hw_vmm); 508bd3845dSNeel Natu static SYSCTL_NODE(_hw_vmm, OID_AUTO, topology, CTLFLAG_RD, 0, NULL); 518bd3845dSNeel Natu 528b287612SJohn Baldwin #define CPUID_VM_HIGH 0x40000000 538b287612SJohn Baldwin 54560d5edaSPeter Grehan static const char bhyve_id[12] = "bhyve bhyve "; 55560d5edaSPeter Grehan 56560d5edaSPeter Grehan static uint64_t bhyve_xcpuids; 578b287612SJohn Baldwin 588bd3845dSNeel Natu /* 598bd3845dSNeel Natu * The default CPU topology is a single thread per package. 608bd3845dSNeel Natu */ 618bd3845dSNeel Natu static u_int threads_per_core = 1; 628bd3845dSNeel Natu SYSCTL_UINT(_hw_vmm_topology, OID_AUTO, threads_per_core, CTLFLAG_RDTUN, 638bd3845dSNeel Natu &threads_per_core, 0, NULL); 648bd3845dSNeel Natu 658bd3845dSNeel Natu static u_int cores_per_package = 1; 668bd3845dSNeel Natu SYSCTL_UINT(_hw_vmm_topology, OID_AUTO, cores_per_package, CTLFLAG_RDTUN, 678bd3845dSNeel Natu &cores_per_package, 0, NULL); 688bd3845dSNeel Natu 698bd3845dSNeel Natu static int cpuid_leaf_b = 1; 708bd3845dSNeel Natu SYSCTL_INT(_hw_vmm_topology, OID_AUTO, cpuid_leaf_b, CTLFLAG_RDTUN, 718bd3845dSNeel Natu &cpuid_leaf_b, 0, NULL); 728bd3845dSNeel Natu 738bd3845dSNeel Natu /* 748bd3845dSNeel Natu * Round up to the next power of two, if necessary, and then take log2. 758bd3845dSNeel Natu * Returns -1 if argument is zero. 768bd3845dSNeel Natu */ 778bd3845dSNeel Natu static __inline int 788bd3845dSNeel Natu log2(u_int x) 798bd3845dSNeel Natu { 808bd3845dSNeel Natu 818bd3845dSNeel Natu return (fls(x << (1 - powerof2(x))) - 1); 828bd3845dSNeel Natu } 838bd3845dSNeel Natu 84366f6083SPeter Grehan int 85a2da7af6SNeel Natu x86_emulate_cpuid(struct vm *vm, int vcpu_id, 86a2da7af6SNeel Natu uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) 87366f6083SPeter Grehan { 88abb023fbSJohn Baldwin const struct xsave_limits *limits; 89abb023fbSJohn Baldwin uint64_t cr4; 908bd3845dSNeel Natu int error, enable_invpcid, level, width, x2apic_id; 918bd3845dSNeel Natu unsigned int func, regs[4], logical_cpus; 92a2da7af6SNeel Natu enum x2apic_state x2apic_state; 93366f6083SPeter Grehan 948b287612SJohn Baldwin /* 958b287612SJohn Baldwin * Requests for invalid CPUID levels should map to the highest 968b287612SJohn Baldwin * available level instead. 978b287612SJohn Baldwin */ 988b287612SJohn Baldwin if (cpu_exthigh != 0 && *eax >= 0x80000000) { 998b287612SJohn Baldwin if (*eax > cpu_exthigh) 1008b287612SJohn Baldwin *eax = cpu_exthigh; 1018b287612SJohn Baldwin } else if (*eax >= 0x40000000) { 1028b287612SJohn Baldwin if (*eax > CPUID_VM_HIGH) 1038b287612SJohn Baldwin *eax = CPUID_VM_HIGH; 1048b287612SJohn Baldwin } else if (*eax > cpu_high) { 1058b287612SJohn Baldwin *eax = cpu_high; 1068b287612SJohn Baldwin } 107366f6083SPeter Grehan 10825448de2SNeel Natu func = *eax; 10925448de2SNeel Natu 1108b287612SJohn Baldwin /* 1118b287612SJohn Baldwin * In general the approach used for CPU topology is to 1128b287612SJohn Baldwin * advertise a flat topology where all CPUs are packages with 1138b287612SJohn Baldwin * no multi-core or SMT. 1148b287612SJohn Baldwin */ 115366f6083SPeter Grehan switch (func) { 116560d5edaSPeter Grehan /* 117560d5edaSPeter Grehan * Pass these through to the guest 118560d5edaSPeter Grehan */ 119366f6083SPeter Grehan case CPUID_0000_0000: 120366f6083SPeter Grehan case CPUID_0000_0002: 121366f6083SPeter Grehan case CPUID_0000_0003: 122366f6083SPeter Grehan case CPUID_8000_0000: 123366f6083SPeter Grehan case CPUID_8000_0002: 124366f6083SPeter Grehan case CPUID_8000_0003: 125366f6083SPeter Grehan case CPUID_8000_0004: 126366f6083SPeter Grehan case CPUID_8000_0006: 127366f6083SPeter Grehan case CPUID_8000_0008: 1288b287612SJohn Baldwin cpuid_count(*eax, *ecx, regs); 129366f6083SPeter Grehan break; 130366f6083SPeter Grehan 131560d5edaSPeter Grehan case CPUID_8000_0001: 132*06053618SNeel Natu cpuid_count(*eax, *ecx, regs); 133*06053618SNeel Natu 134*06053618SNeel Natu /* 135*06053618SNeel Natu * Hide SVM capability from guest. 136*06053618SNeel Natu */ 137eee8190aSPeter Grehan regs[2] &= ~AMDID2_SVM; 138*06053618SNeel Natu 139560d5edaSPeter Grehan /* 140560d5edaSPeter Grehan * Hide rdtscp/ia32_tsc_aux until we know how 141560d5edaSPeter Grehan * to deal with them. 142560d5edaSPeter Grehan */ 143560d5edaSPeter Grehan regs[3] &= ~AMDID_RDTSCP; 144560d5edaSPeter Grehan break; 145560d5edaSPeter Grehan 1461472b87fSNeel Natu case CPUID_8000_0007: 1471472b87fSNeel Natu cpuid_count(*eax, *ecx, regs); 1481472b87fSNeel Natu /* 1491472b87fSNeel Natu * If the host TSCs are not synchronized across 1501472b87fSNeel Natu * physical cpus then we cannot advertise an 1511472b87fSNeel Natu * invariant tsc to a vcpu. 1521472b87fSNeel Natu * 1531472b87fSNeel Natu * XXX This still falls short because the vcpu 1541472b87fSNeel Natu * can observe the TSC moving backwards as it 1551472b87fSNeel Natu * migrates across physical cpus. But at least 1561472b87fSNeel Natu * it should discourage the guest from using the 1571472b87fSNeel Natu * TSC to keep track of time. 1581472b87fSNeel Natu */ 1591472b87fSNeel Natu if (!smp_tsc) 1601472b87fSNeel Natu regs[3] &= ~AMDPM_TSC_INVARIANT; 1611472b87fSNeel Natu break; 1621472b87fSNeel Natu 163366f6083SPeter Grehan case CPUID_0000_0001: 1648b287612SJohn Baldwin do_cpuid(1, regs); 1658b287612SJohn Baldwin 166a2da7af6SNeel Natu error = vm_get_x2apic_state(vm, vcpu_id, &x2apic_state); 167a2da7af6SNeel Natu if (error) { 168a2da7af6SNeel Natu panic("x86_emulate_cpuid: error %d " 169a2da7af6SNeel Natu "fetching x2apic state", error); 170a2da7af6SNeel Natu } 171a2da7af6SNeel Natu 172366f6083SPeter Grehan /* 173366f6083SPeter Grehan * Override the APIC ID only in ebx 174366f6083SPeter Grehan */ 1758b287612SJohn Baldwin regs[1] &= ~(CPUID_LOCAL_APIC_ID); 1768b287612SJohn Baldwin regs[1] |= (vcpu_id << CPUID_0000_0001_APICID_SHIFT); 177366f6083SPeter Grehan 178366f6083SPeter Grehan /* 1791f3025e1SPeter Grehan * Don't expose VMX, SpeedStep or TME capability. 1808b287612SJohn Baldwin * Advertise x2APIC capability and Hypervisor guest. 181366f6083SPeter Grehan */ 1828b287612SJohn Baldwin regs[2] &= ~(CPUID2_VMX | CPUID2_EST | CPUID2_TM2); 183a2da7af6SNeel Natu 184a2da7af6SNeel Natu regs[2] |= CPUID2_HV; 185a2da7af6SNeel Natu 186a2da7af6SNeel Natu if (x2apic_state != X2APIC_DISABLED) 187a2da7af6SNeel Natu regs[2] |= CPUID2_X2APIC; 18852e5c8a2SNeel Natu else 18952e5c8a2SNeel Natu regs[2] &= ~CPUID2_X2APIC; 190366f6083SPeter Grehan 191366f6083SPeter Grehan /* 192abb023fbSJohn Baldwin * Only advertise CPUID2_XSAVE in the guest if 193abb023fbSJohn Baldwin * the host is using XSAVE. 194298379f7SPeter Grehan */ 195abb023fbSJohn Baldwin if (!(regs[2] & CPUID2_OSXSAVE)) 196abb023fbSJohn Baldwin regs[2] &= ~CPUID2_XSAVE; 197abb023fbSJohn Baldwin 198abb023fbSJohn Baldwin /* 199abb023fbSJohn Baldwin * If CPUID2_XSAVE is being advertised and the 200abb023fbSJohn Baldwin * guest has set CR4_XSAVE, set 201abb023fbSJohn Baldwin * CPUID2_OSXSAVE. 202abb023fbSJohn Baldwin */ 203abb023fbSJohn Baldwin regs[2] &= ~CPUID2_OSXSAVE; 204abb023fbSJohn Baldwin if (regs[2] & CPUID2_XSAVE) { 205abb023fbSJohn Baldwin error = vm_get_register(vm, vcpu_id, 206abb023fbSJohn Baldwin VM_REG_GUEST_CR4, &cr4); 207abb023fbSJohn Baldwin if (error) 208abb023fbSJohn Baldwin panic("x86_emulate_cpuid: error %d " 209abb023fbSJohn Baldwin "fetching %%cr4", error); 210abb023fbSJohn Baldwin if (cr4 & CR4_XSAVE) 211abb023fbSJohn Baldwin regs[2] |= CPUID2_OSXSAVE; 212abb023fbSJohn Baldwin } 213298379f7SPeter Grehan 214298379f7SPeter Grehan /* 215ff6ec151SNeel Natu * Hide monitor/mwait until we know how to deal with 216ff6ec151SNeel Natu * these instructions. 217ff6ec151SNeel Natu */ 218ff6ec151SNeel Natu regs[2] &= ~CPUID2_MON; 219ff6ec151SNeel Natu 220ff6ec151SNeel Natu /* 221560d5edaSPeter Grehan * Hide the performance and debug features. 222560d5edaSPeter Grehan */ 223560d5edaSPeter Grehan regs[2] &= ~CPUID2_PDCM; 224560d5edaSPeter Grehan 225517e21d3SPeter Grehan /* 226517e21d3SPeter Grehan * No TSC deadline support in the APIC yet 227517e21d3SPeter Grehan */ 228517e21d3SPeter Grehan regs[2] &= ~CPUID2_TSCDLT; 229517e21d3SPeter Grehan 230560d5edaSPeter Grehan /* 2311f3025e1SPeter Grehan * Hide thermal monitoring 2321f3025e1SPeter Grehan */ 2331f3025e1SPeter Grehan regs[3] &= ~(CPUID_ACPI | CPUID_TM); 2341f3025e1SPeter Grehan 2351f3025e1SPeter Grehan /* 236366f6083SPeter Grehan * Machine check handling is done in the host. 237366f6083SPeter Grehan * Hide MTRR capability. 238366f6083SPeter Grehan */ 239366f6083SPeter Grehan regs[3] &= ~(CPUID_MCA | CPUID_MCE | CPUID_MTRR); 240366f6083SPeter Grehan 2418b287612SJohn Baldwin /* 242560d5edaSPeter Grehan * Hide the debug store capability. 243560d5edaSPeter Grehan */ 244560d5edaSPeter Grehan regs[3] &= ~CPUID_DS; 245560d5edaSPeter Grehan 2468bd3845dSNeel Natu logical_cpus = threads_per_core * cores_per_package; 2478b287612SJohn Baldwin regs[1] &= ~CPUID_HTT_CORES; 2488bd3845dSNeel Natu regs[1] |= (logical_cpus & 0xff) << 16; 2498bd3845dSNeel Natu regs[3] |= CPUID_HTT; 2508b287612SJohn Baldwin break; 2518b287612SJohn Baldwin 2528b287612SJohn Baldwin case CPUID_0000_0004: 253534dc967SNeel Natu cpuid_count(*eax, *ecx, regs); 2548b287612SJohn Baldwin 2558bd3845dSNeel Natu if (regs[0] || regs[1] || regs[2] || regs[3]) { 256534dc967SNeel Natu regs[0] &= 0x3ff; 2578bd3845dSNeel Natu regs[0] |= (cores_per_package - 1) << 26; 2588b287612SJohn Baldwin /* 2598bd3845dSNeel Natu * Cache topology: 2608bd3845dSNeel Natu * - L1 and L2 are shared only by the logical 2618bd3845dSNeel Natu * processors in a single core. 2628bd3845dSNeel Natu * - L3 and above are shared by all logical 2638bd3845dSNeel Natu * processors in the package. 2648b287612SJohn Baldwin */ 2658bd3845dSNeel Natu logical_cpus = threads_per_core; 2668bd3845dSNeel Natu level = (regs[0] >> 5) & 0x7; 2678bd3845dSNeel Natu if (level >= 3) 2688bd3845dSNeel Natu logical_cpus *= cores_per_package; 2698bd3845dSNeel Natu regs[0] |= (logical_cpus - 1) << 14; 2708bd3845dSNeel Natu } 271366f6083SPeter Grehan break; 272366f6083SPeter Grehan 273a0cad470SPeter Grehan case CPUID_0000_0007: 27449cc03daSNeel Natu regs[0] = 0; 27549cc03daSNeel Natu regs[1] = 0; 27649cc03daSNeel Natu regs[2] = 0; 27749cc03daSNeel Natu regs[3] = 0; 27849cc03daSNeel Natu 27949cc03daSNeel Natu /* leaf 0 */ 28049cc03daSNeel Natu if (*ecx == 0) { 28144a68c4eSJohn Baldwin cpuid_count(*eax, *ecx, regs); 28244a68c4eSJohn Baldwin 28344a68c4eSJohn Baldwin /* Only leaf 0 is supported */ 28444a68c4eSJohn Baldwin regs[0] = 0; 28544a68c4eSJohn Baldwin 28644a68c4eSJohn Baldwin /* 28744a68c4eSJohn Baldwin * Expose known-safe features. 28844a68c4eSJohn Baldwin */ 28944a68c4eSJohn Baldwin regs[1] &= (CPUID_STDEXT_FSGSBASE | 29044a68c4eSJohn Baldwin CPUID_STDEXT_BMI1 | CPUID_STDEXT_HLE | 29144a68c4eSJohn Baldwin CPUID_STDEXT_AVX2 | CPUID_STDEXT_BMI2 | 29244a68c4eSJohn Baldwin CPUID_STDEXT_ERMS | CPUID_STDEXT_RTM | 29344a68c4eSJohn Baldwin CPUID_STDEXT_AVX512F | 29444a68c4eSJohn Baldwin CPUID_STDEXT_AVX512PF | 29544a68c4eSJohn Baldwin CPUID_STDEXT_AVX512ER | 29644a68c4eSJohn Baldwin CPUID_STDEXT_AVX512CD); 29744a68c4eSJohn Baldwin regs[2] = 0; 29844a68c4eSJohn Baldwin regs[3] = 0; 29944a68c4eSJohn Baldwin 30044a68c4eSJohn Baldwin /* Advertise INVPCID if it is enabled. */ 30149cc03daSNeel Natu error = vm_get_capability(vm, vcpu_id, 30249cc03daSNeel Natu VM_CAP_ENABLE_INVPCID, &enable_invpcid); 30349cc03daSNeel Natu if (error == 0 && enable_invpcid) 30449cc03daSNeel Natu regs[1] |= CPUID_STDEXT_INVPCID; 30549cc03daSNeel Natu } 30649cc03daSNeel Natu break; 30749cc03daSNeel Natu 30849cc03daSNeel Natu case CPUID_0000_0006: 309560d5edaSPeter Grehan case CPUID_0000_000A: 3101f3025e1SPeter Grehan /* 3111f3025e1SPeter Grehan * Handle the access, but report 0 for 3121f3025e1SPeter Grehan * all options 3131f3025e1SPeter Grehan */ 3141f3025e1SPeter Grehan regs[0] = 0; 3151f3025e1SPeter Grehan regs[1] = 0; 3161f3025e1SPeter Grehan regs[2] = 0; 3171f3025e1SPeter Grehan regs[3] = 0; 3181f3025e1SPeter Grehan break; 3191f3025e1SPeter Grehan 320366f6083SPeter Grehan case CPUID_0000_000B: 321366f6083SPeter Grehan /* 322366f6083SPeter Grehan * Processor topology enumeration 323366f6083SPeter Grehan */ 3248bd3845dSNeel Natu if (*ecx == 0) { 3258bd3845dSNeel Natu logical_cpus = threads_per_core; 3268bd3845dSNeel Natu width = log2(logical_cpus); 3278bd3845dSNeel Natu level = CPUID_TYPE_SMT; 3288bd3845dSNeel Natu x2apic_id = vcpu_id; 3298bd3845dSNeel Natu } 3308bd3845dSNeel Natu 3318bd3845dSNeel Natu if (*ecx == 1) { 3328bd3845dSNeel Natu logical_cpus = threads_per_core * 3338bd3845dSNeel Natu cores_per_package; 3348bd3845dSNeel Natu width = log2(logical_cpus); 3358bd3845dSNeel Natu level = CPUID_TYPE_CORE; 3368bd3845dSNeel Natu x2apic_id = vcpu_id; 3378bd3845dSNeel Natu } 3388bd3845dSNeel Natu 3398bd3845dSNeel Natu if (!cpuid_leaf_b || *ecx >= 2) { 3408bd3845dSNeel Natu width = 0; 3418bd3845dSNeel Natu logical_cpus = 0; 3428bd3845dSNeel Natu level = 0; 3438bd3845dSNeel Natu x2apic_id = 0; 3448bd3845dSNeel Natu } 3458bd3845dSNeel Natu 3468bd3845dSNeel Natu regs[0] = width & 0x1f; 3478bd3845dSNeel Natu regs[1] = logical_cpus & 0xffff; 3488bd3845dSNeel Natu regs[2] = (level << 8) | (*ecx & 0xff); 3498bd3845dSNeel Natu regs[3] = x2apic_id; 350366f6083SPeter Grehan break; 351366f6083SPeter Grehan 352abb023fbSJohn Baldwin case CPUID_0000_000D: 353abb023fbSJohn Baldwin limits = vmm_get_xsave_limits(); 354abb023fbSJohn Baldwin if (!limits->xsave_enabled) { 355abb023fbSJohn Baldwin regs[0] = 0; 356abb023fbSJohn Baldwin regs[1] = 0; 357abb023fbSJohn Baldwin regs[2] = 0; 358abb023fbSJohn Baldwin regs[3] = 0; 359abb023fbSJohn Baldwin break; 360abb023fbSJohn Baldwin } 361abb023fbSJohn Baldwin 362abb023fbSJohn Baldwin cpuid_count(*eax, *ecx, regs); 363abb023fbSJohn Baldwin switch (*ecx) { 364abb023fbSJohn Baldwin case 0: 365abb023fbSJohn Baldwin /* 366abb023fbSJohn Baldwin * Only permit the guest to use bits 367abb023fbSJohn Baldwin * that are active in the host in 368abb023fbSJohn Baldwin * %xcr0. Also, claim that the 369abb023fbSJohn Baldwin * maximum save area size is 370abb023fbSJohn Baldwin * equivalent to the host's current 371abb023fbSJohn Baldwin * save area size. Since this runs 372abb023fbSJohn Baldwin * "inside" of vmrun(), it runs with 373abb023fbSJohn Baldwin * the guest's xcr0, so the current 374abb023fbSJohn Baldwin * save area size is correct as-is. 375abb023fbSJohn Baldwin */ 376abb023fbSJohn Baldwin regs[0] &= limits->xcr0_allowed; 377abb023fbSJohn Baldwin regs[2] = limits->xsave_max_size; 378abb023fbSJohn Baldwin regs[3] &= (limits->xcr0_allowed >> 32); 379abb023fbSJohn Baldwin break; 380abb023fbSJohn Baldwin case 1: 381abb023fbSJohn Baldwin /* Only permit XSAVEOPT. */ 382abb023fbSJohn Baldwin regs[0] &= CPUID_EXTSTATE_XSAVEOPT; 383abb023fbSJohn Baldwin regs[1] = 0; 384abb023fbSJohn Baldwin regs[2] = 0; 385abb023fbSJohn Baldwin regs[3] = 0; 386abb023fbSJohn Baldwin break; 387abb023fbSJohn Baldwin default: 388abb023fbSJohn Baldwin /* 389abb023fbSJohn Baldwin * If the leaf is for a permitted feature, 390abb023fbSJohn Baldwin * pass through as-is, otherwise return 391abb023fbSJohn Baldwin * all zeroes. 392abb023fbSJohn Baldwin */ 393abb023fbSJohn Baldwin if (!(limits->xcr0_allowed & (1ul << *ecx))) { 394abb023fbSJohn Baldwin regs[0] = 0; 395abb023fbSJohn Baldwin regs[1] = 0; 396abb023fbSJohn Baldwin regs[2] = 0; 397abb023fbSJohn Baldwin regs[3] = 0; 398abb023fbSJohn Baldwin } 399abb023fbSJohn Baldwin break; 400abb023fbSJohn Baldwin } 401abb023fbSJohn Baldwin break; 402abb023fbSJohn Baldwin 4038b287612SJohn Baldwin case 0x40000000: 4048b287612SJohn Baldwin regs[0] = CPUID_VM_HIGH; 4058b287612SJohn Baldwin bcopy(bhyve_id, ®s[1], 4); 406560d5edaSPeter Grehan bcopy(bhyve_id + 4, ®s[2], 4); 407560d5edaSPeter Grehan bcopy(bhyve_id + 8, ®s[3], 4); 4088b287612SJohn Baldwin break; 409560d5edaSPeter Grehan 410366f6083SPeter Grehan default: 411560d5edaSPeter Grehan /* 412560d5edaSPeter Grehan * The leaf value has already been clamped so 413560d5edaSPeter Grehan * simply pass this through, keeping count of 414560d5edaSPeter Grehan * how many unhandled leaf values have been seen. 415560d5edaSPeter Grehan */ 416560d5edaSPeter Grehan atomic_add_long(&bhyve_xcpuids, 1); 417560d5edaSPeter Grehan cpuid_count(*eax, *ecx, regs); 418560d5edaSPeter Grehan break; 419366f6083SPeter Grehan } 420366f6083SPeter Grehan 421366f6083SPeter Grehan *eax = regs[0]; 422366f6083SPeter Grehan *ebx = regs[1]; 423366f6083SPeter Grehan *ecx = regs[2]; 424366f6083SPeter Grehan *edx = regs[3]; 425560d5edaSPeter Grehan 426366f6083SPeter Grehan return (1); 427366f6083SPeter Grehan } 428