xref: /illumos-gate/usr/src/uts/intel/io/vmm/x86.c (revision 54cf5b63)
1bf21cd93STycho Nightingale /*-
24c87aefeSPatrick Mooney  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
34c87aefeSPatrick Mooney  *
4bf21cd93STycho Nightingale  * Copyright (c) 2011 NetApp, Inc.
5bf21cd93STycho Nightingale  * All rights reserved.
6bf21cd93STycho Nightingale  *
7bf21cd93STycho Nightingale  * Redistribution and use in source and binary forms, with or without
8bf21cd93STycho Nightingale  * modification, are permitted provided that the following conditions
9bf21cd93STycho Nightingale  * are met:
10bf21cd93STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
11bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
12bf21cd93STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
13bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
14bf21cd93STycho Nightingale  *    documentation and/or other materials provided with the distribution.
15bf21cd93STycho Nightingale  *
16bf21cd93STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
26bf21cd93STycho Nightingale  * SUCH DAMAGE.
27bf21cd93STycho Nightingale  *
284c87aefeSPatrick Mooney  * $FreeBSD$
29bf21cd93STycho Nightingale  */
30bf21cd93STycho Nightingale /*
31bf21cd93STycho Nightingale  * This file and its contents are supplied under the terms of the
32bf21cd93STycho Nightingale  * Common Development and Distribution License ("CDDL"), version 1.0.
33bf21cd93STycho Nightingale  * You may only use this file in accordance with the terms of version
34bf21cd93STycho Nightingale  * 1.0 of the CDDL.
35bf21cd93STycho Nightingale  *
36bf21cd93STycho Nightingale  * A full copy of the text of the CDDL should have accompanied this
37bf21cd93STycho Nightingale  * source.  A copy of the CDDL is also available via the Internet at
38bf21cd93STycho Nightingale  * http://www.illumos.org/license/CDDL.
39bf21cd93STycho Nightingale  *
40bf21cd93STycho Nightingale  * Copyright 2014 Pluribus Networks Inc.
414c87aefeSPatrick Mooney  * Copyright 2018 Joyent, Inc.
423c5f2a9dSPatrick Mooney  * Copyright 2020 Oxide Computer Company
43bf21cd93STycho Nightingale  */
44bf21cd93STycho Nightingale 
45bf21cd93STycho Nightingale #include <sys/cdefs.h>
464c87aefeSPatrick Mooney __FBSDID("$FreeBSD$");
47bf21cd93STycho Nightingale 
48bf21cd93STycho Nightingale #include <sys/param.h>
494c87aefeSPatrick Mooney #include <sys/pcpu.h>
50bf21cd93STycho Nightingale #include <sys/systm.h>
514c87aefeSPatrick Mooney #include <sys/sysctl.h>
524c87aefeSPatrick Mooney #include <sys/x86_archext.h>
53bf21cd93STycho Nightingale 
54bf21cd93STycho Nightingale #include <machine/clock.h>
55bf21cd93STycho Nightingale #include <machine/cpufunc.h>
56bf21cd93STycho Nightingale #include <machine/md_var.h>
574c87aefeSPatrick Mooney #include <machine/segments.h>
58bf21cd93STycho Nightingale #include <machine/specialreg.h>
59bf21cd93STycho Nightingale 
60bf21cd93STycho Nightingale #include <machine/vmm.h>
61*54cf5b63SPatrick Mooney #include <sys/vmm_kernel.h>
62bf21cd93STycho Nightingale 
634c87aefeSPatrick Mooney #include "vmm_host.h"
644c87aefeSPatrick Mooney #include "vmm_util.h"
65bf21cd93STycho Nightingale 
664c87aefeSPatrick Mooney SYSCTL_DECL(_hw_vmm);
674c87aefeSPatrick Mooney 
68bf21cd93STycho Nightingale #define	CPUID_VM_HIGH		0x40000000
69bf21cd93STycho Nightingale 
70bf21cd93STycho Nightingale static const char bhyve_id[12] = "bhyve bhyve ";
71bf21cd93STycho Nightingale 
722699b94cSPatrick Mooney /* Number of times an unknown cpuid leaf was accessed */
73bf21cd93STycho Nightingale static uint64_t bhyve_xcpuids;
744c87aefeSPatrick Mooney 
754c87aefeSPatrick Mooney static int cpuid_leaf_b = 1;
764c87aefeSPatrick Mooney 
779250eb13SPatrick Mooney /*
789250eb13SPatrick Mooney  * Force exposition of the invariant TSC capability, regardless of whether the
799250eb13SPatrick Mooney  * host CPU reports having it.
809250eb13SPatrick Mooney  */
819250eb13SPatrick Mooney static int vmm_force_invariant_tsc = 0;
829250eb13SPatrick Mooney 
83*54cf5b63SPatrick Mooney #define	CPUID_0000_0000	(0x0)
84*54cf5b63SPatrick Mooney #define	CPUID_0000_0001	(0x1)
85*54cf5b63SPatrick Mooney #define	CPUID_0000_0002	(0x2)
86*54cf5b63SPatrick Mooney #define	CPUID_0000_0003	(0x3)
87*54cf5b63SPatrick Mooney #define	CPUID_0000_0004	(0x4)
88*54cf5b63SPatrick Mooney #define	CPUID_0000_0006	(0x6)
89*54cf5b63SPatrick Mooney #define	CPUID_0000_0007	(0x7)
90*54cf5b63SPatrick Mooney #define	CPUID_0000_000A	(0xA)
91*54cf5b63SPatrick Mooney #define	CPUID_0000_000B	(0xB)
92*54cf5b63SPatrick Mooney #define	CPUID_0000_000D	(0xD)
93*54cf5b63SPatrick Mooney #define	CPUID_0000_000F	(0xF)
94*54cf5b63SPatrick Mooney #define	CPUID_0000_0010	(0x10)
95*54cf5b63SPatrick Mooney #define	CPUID_0000_0015	(0x15)
96*54cf5b63SPatrick Mooney #define	CPUID_8000_0000	(0x80000000)
97*54cf5b63SPatrick Mooney #define	CPUID_8000_0001	(0x80000001)
98*54cf5b63SPatrick Mooney #define	CPUID_8000_0002	(0x80000002)
99*54cf5b63SPatrick Mooney #define	CPUID_8000_0003	(0x80000003)
100*54cf5b63SPatrick Mooney #define	CPUID_8000_0004	(0x80000004)
101*54cf5b63SPatrick Mooney #define	CPUID_8000_0006	(0x80000006)
102*54cf5b63SPatrick Mooney #define	CPUID_8000_0007	(0x80000007)
103*54cf5b63SPatrick Mooney #define	CPUID_8000_0008	(0x80000008)
104*54cf5b63SPatrick Mooney #define	CPUID_8000_001D	(0x8000001D)
105*54cf5b63SPatrick Mooney #define	CPUID_8000_001E	(0x8000001E)
106*54cf5b63SPatrick Mooney 
107*54cf5b63SPatrick Mooney /*
108*54cf5b63SPatrick Mooney  * CPUID instruction Fn0000_0001:
109*54cf5b63SPatrick Mooney  */
110*54cf5b63SPatrick Mooney #define	CPUID_0000_0001_APICID_MASK	(0xff<<24)
111*54cf5b63SPatrick Mooney #define	CPUID_0000_0001_APICID_SHIFT	24
112*54cf5b63SPatrick Mooney 
113*54cf5b63SPatrick Mooney /*
114*54cf5b63SPatrick Mooney  * CPUID instruction Fn0000_0001 ECX
115*54cf5b63SPatrick Mooney  */
116*54cf5b63SPatrick Mooney #define	CPUID_0000_0001_FEAT0_VMX	(1<<5)
117*54cf5b63SPatrick Mooney 
118*54cf5b63SPatrick Mooney 
1194c87aefeSPatrick Mooney /*
1204c87aefeSPatrick Mooney  * Round up to the next power of two, if necessary, and then take log2.
1214c87aefeSPatrick Mooney  * Returns -1 if argument is zero.
1224c87aefeSPatrick Mooney  */
1234c87aefeSPatrick Mooney static __inline int
log2(uint_t x)1242699b94cSPatrick Mooney log2(uint_t x)
1254c87aefeSPatrick Mooney {
1264c87aefeSPatrick Mooney 
1274c87aefeSPatrick Mooney 	return (fls(x << (1 - powerof2(x))) - 1);
1284c87aefeSPatrick Mooney }
129bf21cd93STycho Nightingale 
130bf21cd93STycho Nightingale int
x86_emulate_cpuid(struct vm * vm,int vcpu_id,uint64_t * rax,uint64_t * rbx,uint64_t * rcx,uint64_t * rdx)1313c5f2a9dSPatrick Mooney x86_emulate_cpuid(struct vm *vm, int vcpu_id, uint64_t *rax, uint64_t *rbx,
1323c5f2a9dSPatrick Mooney     uint64_t *rcx, uint64_t *rdx)
133bf21cd93STycho Nightingale {
1344c87aefeSPatrick Mooney 	const struct xsave_limits *limits;
1354c87aefeSPatrick Mooney 	uint64_t cr4;
1364c87aefeSPatrick Mooney 	int error, enable_invpcid, level, width = 0, x2apic_id = 0;
1373c5f2a9dSPatrick Mooney 	unsigned int func, regs[4], logical_cpus = 0, param;
138bf21cd93STycho Nightingale 	enum x2apic_state x2apic_state;
1394c87aefeSPatrick Mooney 	uint16_t cores, maxcpus, sockets, threads;
1404c87aefeSPatrick Mooney 
1413c5f2a9dSPatrick Mooney 	/*
1423c5f2a9dSPatrick Mooney 	 * The function of CPUID is controlled through the provided value of
1433c5f2a9dSPatrick Mooney 	 * %eax (and secondarily %ecx, for certain leaf data).
1443c5f2a9dSPatrick Mooney 	 */
1453c5f2a9dSPatrick Mooney 	func = (uint32_t)*rax;
1463c5f2a9dSPatrick Mooney 	param = (uint32_t)*rcx;
1473c5f2a9dSPatrick Mooney 
148bf21cd93STycho Nightingale 	/*
149bf21cd93STycho Nightingale 	 * Requests for invalid CPUID levels should map to the highest
150bf21cd93STycho Nightingale 	 * available level instead.
151bf21cd93STycho Nightingale 	 */
1523c5f2a9dSPatrick Mooney 	if (cpu_exthigh != 0 && func >= 0x80000000) {
1533c5f2a9dSPatrick Mooney 		if (func > cpu_exthigh)
1543c5f2a9dSPatrick Mooney 			func = cpu_exthigh;
1553c5f2a9dSPatrick Mooney 	} else if (func >= 0x40000000) {
1563c5f2a9dSPatrick Mooney 		if (func > CPUID_VM_HIGH)
1573c5f2a9dSPatrick Mooney 			func = CPUID_VM_HIGH;
1583c5f2a9dSPatrick Mooney 	} else if (func > cpu_high) {
1593c5f2a9dSPatrick Mooney 		func = cpu_high;
160bf21cd93STycho Nightingale 	}
161bf21cd93STycho Nightingale 
162bf21cd93STycho Nightingale 	/*
163bf21cd93STycho Nightingale 	 * In general the approach used for CPU topology is to
164bf21cd93STycho Nightingale 	 * advertise a flat topology where all CPUs are packages with
165bf21cd93STycho Nightingale 	 * no multi-core or SMT.
166bf21cd93STycho Nightingale 	 */
167bf21cd93STycho Nightingale 	switch (func) {
168bf21cd93STycho Nightingale 		/*
169bf21cd93STycho Nightingale 		 * Pass these through to the guest
170bf21cd93STycho Nightingale 		 */
171bf21cd93STycho Nightingale 		case CPUID_0000_0000:
172bf21cd93STycho Nightingale 		case CPUID_0000_0002:
173bf21cd93STycho Nightingale 		case CPUID_0000_0003:
174bf21cd93STycho Nightingale 		case CPUID_8000_0000:
175bf21cd93STycho Nightingale 		case CPUID_8000_0002:
176bf21cd93STycho Nightingale 		case CPUID_8000_0003:
177bf21cd93STycho Nightingale 		case CPUID_8000_0004:
178bf21cd93STycho Nightingale 		case CPUID_8000_0006:
1793c5f2a9dSPatrick Mooney 			cpuid_count(func, param, regs);
1804c87aefeSPatrick Mooney 			break;
181bf21cd93STycho Nightingale 		case CPUID_8000_0008:
1823c5f2a9dSPatrick Mooney 			cpuid_count(func, param, regs);
183154972afSPatrick Mooney 			if (vmm_is_svm()) {
1844c87aefeSPatrick Mooney 				/*
1854c87aefeSPatrick Mooney 				 * As on Intel (0000_0007:0, EDX), mask out
1864c87aefeSPatrick Mooney 				 * unsupported or unsafe AMD extended features
1874c87aefeSPatrick Mooney 				 * (8000_0008 EBX).
1884c87aefeSPatrick Mooney 				 */
1894c87aefeSPatrick Mooney 				regs[1] &= (AMDFEID_CLZERO | AMDFEID_IRPERF |
1904c87aefeSPatrick Mooney 				    AMDFEID_XSAVEERPTR);
1914c87aefeSPatrick Mooney 
1924c87aefeSPatrick Mooney 				vm_get_topology(vm, &sockets, &cores, &threads,
1934c87aefeSPatrick Mooney 				    &maxcpus);
1944c87aefeSPatrick Mooney 				/*
1954c87aefeSPatrick Mooney 				 * Here, width is ApicIdCoreIdSize, present on
1964c87aefeSPatrick Mooney 				 * at least Family 15h and newer.  It
1974c87aefeSPatrick Mooney 				 * represents the "number of bits in the
1984c87aefeSPatrick Mooney 				 * initial apicid that indicate thread id
1994c87aefeSPatrick Mooney 				 * within a package."
2004c87aefeSPatrick Mooney 				 *
2014c87aefeSPatrick Mooney 				 * Our topo_probe_amd() uses it for
2024c87aefeSPatrick Mooney 				 * pkg_id_shift and other OSes may rely on it.
2034c87aefeSPatrick Mooney 				 */
2044c87aefeSPatrick Mooney 				width = MIN(0xF, log2(threads * cores));
2054c87aefeSPatrick Mooney 				if (width < 0x4)
2064c87aefeSPatrick Mooney 					width = 0;
2074c87aefeSPatrick Mooney 				logical_cpus = MIN(0xFF, threads * cores - 1);
2082699b94cSPatrick Mooney 				regs[2] = (width << AMDID_COREID_SIZE_SHIFT) |
2092699b94cSPatrick Mooney 				    logical_cpus;
2104c87aefeSPatrick Mooney 			}
211bf21cd93STycho Nightingale 			break;
212bf21cd93STycho Nightingale 
213bf21cd93STycho Nightingale 		case CPUID_8000_0001:
2143c5f2a9dSPatrick Mooney 			cpuid_count(func, param, regs);
2154c87aefeSPatrick Mooney 
2164c87aefeSPatrick Mooney 			/*
2174c87aefeSPatrick Mooney 			 * Hide SVM from guest.
2184c87aefeSPatrick Mooney 			 */
2194c87aefeSPatrick Mooney 			regs[2] &= ~AMDID2_SVM;
2204c87aefeSPatrick Mooney 
2214c87aefeSPatrick Mooney 			/*
2224c87aefeSPatrick Mooney 			 * Don't advertise extended performance counter MSRs
2234c87aefeSPatrick Mooney 			 * to the guest.
2244c87aefeSPatrick Mooney 			 */
2254c87aefeSPatrick Mooney 			regs[2] &= ~AMDID2_PCXC;
2264c87aefeSPatrick Mooney 			regs[2] &= ~AMDID2_PNXC;
2274c87aefeSPatrick Mooney 			regs[2] &= ~AMDID2_PTSCEL2I;
2284c87aefeSPatrick Mooney 
2294c87aefeSPatrick Mooney 			/*
2304c87aefeSPatrick Mooney 			 * Don't advertise Instruction Based Sampling feature.
2314c87aefeSPatrick Mooney 			 */
2324c87aefeSPatrick Mooney 			regs[2] &= ~AMDID2_IBS;
2334c87aefeSPatrick Mooney 
2344c87aefeSPatrick Mooney 			/* NodeID MSR not available */
2354c87aefeSPatrick Mooney 			regs[2] &= ~AMDID2_NODE_ID;
2364c87aefeSPatrick Mooney 
2374c87aefeSPatrick Mooney 			/* Don't advertise the OS visible workaround feature */
2384c87aefeSPatrick Mooney 			regs[2] &= ~AMDID2_OSVW;
2394c87aefeSPatrick Mooney 
2404c87aefeSPatrick Mooney 			/* Hide mwaitx/monitorx capability from the guest */
2414c87aefeSPatrick Mooney 			regs[2] &= ~AMDID2_MWAITX;
2424c87aefeSPatrick Mooney 
2434c87aefeSPatrick Mooney #ifndef __FreeBSD__
2444c87aefeSPatrick Mooney 			/*
2454c87aefeSPatrick Mooney 			 * Detection routines for TCE and FFXSR are missing
2464c87aefeSPatrick Mooney 			 * from our vm_cpuid_capability() detection logic
2474c87aefeSPatrick Mooney 			 * today.  Mask them out until that is remedied.
2484c87aefeSPatrick Mooney 			 * They do not appear to be in common usage, so their
2494c87aefeSPatrick Mooney 			 * absence should not cause undue trouble.
2504c87aefeSPatrick Mooney 			 */
2514c87aefeSPatrick Mooney 			regs[2] &= ~AMDID2_TCE;
2524c87aefeSPatrick Mooney 			regs[3] &= ~AMDID_FFXSR;
2534c87aefeSPatrick Mooney #endif
2544c87aefeSPatrick Mooney 
255bf21cd93STycho Nightingale 			/*
256bf21cd93STycho Nightingale 			 * Hide rdtscp/ia32_tsc_aux until we know how
257bf21cd93STycho Nightingale 			 * to deal with them.
258bf21cd93STycho Nightingale 			 */
259bf21cd93STycho Nightingale 			regs[3] &= ~AMDID_RDTSCP;
260bf21cd93STycho Nightingale 			break;
261bf21cd93STycho Nightingale 
262bf21cd93STycho Nightingale 		case CPUID_8000_0007:
2639250eb13SPatrick Mooney 			cpuid_count(func, param, regs);
264bf21cd93STycho Nightingale 			/*
2654c87aefeSPatrick Mooney 			 * AMD uses this leaf to advertise the processor's
2664c87aefeSPatrick Mooney 			 * power monitoring and RAS capabilities. These
2674c87aefeSPatrick Mooney 			 * features are hardware-specific and exposing
2684c87aefeSPatrick Mooney 			 * them to a guest doesn't make a lot of sense.
2694c87aefeSPatrick Mooney 			 *
2704c87aefeSPatrick Mooney 			 * Intel uses this leaf only to advertise the
2714c87aefeSPatrick Mooney 			 * "Invariant TSC" feature with all other bits
2724c87aefeSPatrick Mooney 			 * being reserved (set to zero).
2734c87aefeSPatrick Mooney 			 */
2744c87aefeSPatrick Mooney 			regs[0] = 0;
2754c87aefeSPatrick Mooney 			regs[1] = 0;
2764c87aefeSPatrick Mooney 			regs[2] = 0;
2774c87aefeSPatrick Mooney 
2784c87aefeSPatrick Mooney 			/*
2799250eb13SPatrick Mooney 			 * If the host system possesses an invariant TSC, then
2809250eb13SPatrick Mooney 			 * it is safe to expose to the guest.
281bf21cd93STycho Nightingale 			 *
2829250eb13SPatrick Mooney 			 * If there is measured skew between host TSCs, it will
2839250eb13SPatrick Mooney 			 * be properly offset so guests do not observe any
2849250eb13SPatrick Mooney 			 * change between CPU migrations.
285bf21cd93STycho Nightingale 			 */
2869250eb13SPatrick Mooney 			regs[3] &= AMDPM_TSC_INVARIANT;
2879250eb13SPatrick Mooney 
2889250eb13SPatrick Mooney 			/*
2899250eb13SPatrick Mooney 			 * Since illumos avoids deep C-states on CPUs which do
2909250eb13SPatrick Mooney 			 * not support an invariant TSC, it may be safe (and
2919250eb13SPatrick Mooney 			 * desired) to unconditionally expose that capability to
2929250eb13SPatrick Mooney 			 * the guest.
2939250eb13SPatrick Mooney 			 */
2949250eb13SPatrick Mooney 			if (vmm_force_invariant_tsc != 0) {
2954c87aefeSPatrick Mooney 				regs[3] |= AMDPM_TSC_INVARIANT;
2969250eb13SPatrick Mooney 			}
2974c87aefeSPatrick Mooney 			break;
2984c87aefeSPatrick Mooney 
2994c87aefeSPatrick Mooney 		case CPUID_8000_001D:
3004c87aefeSPatrick Mooney 			/* AMD Cache topology, like 0000_0004 for Intel. */
301154972afSPatrick Mooney 			if (!vmm_is_svm())
3024c87aefeSPatrick Mooney 				goto default_leaf;
3034c87aefeSPatrick Mooney 
3044c87aefeSPatrick Mooney 			/*
3054c87aefeSPatrick Mooney 			 * Similar to Intel, generate a ficticious cache
3064c87aefeSPatrick Mooney 			 * topology for the guest with L3 shared by the
3074c87aefeSPatrick Mooney 			 * package, and L1 and L2 local to a core.
3084c87aefeSPatrick Mooney 			 */
3094c87aefeSPatrick Mooney 			vm_get_topology(vm, &sockets, &cores, &threads,
3104c87aefeSPatrick Mooney 			    &maxcpus);
3113c5f2a9dSPatrick Mooney 			switch (param) {
3124c87aefeSPatrick Mooney 			case 0:
3134c87aefeSPatrick Mooney 				logical_cpus = threads;
3144c87aefeSPatrick Mooney 				level = 1;
3154c87aefeSPatrick Mooney 				func = 1;	/* data cache */
3164c87aefeSPatrick Mooney 				break;
3174c87aefeSPatrick Mooney 			case 1:
3184c87aefeSPatrick Mooney 				logical_cpus = threads;
3194c87aefeSPatrick Mooney 				level = 2;
3204c87aefeSPatrick Mooney 				func = 3;	/* unified cache */
3214c87aefeSPatrick Mooney 				break;
3224c87aefeSPatrick Mooney 			case 2:
3234c87aefeSPatrick Mooney 				logical_cpus = threads * cores;
3244c87aefeSPatrick Mooney 				level = 3;
3254c87aefeSPatrick Mooney 				func = 3;	/* unified cache */
3264c87aefeSPatrick Mooney 				break;
3274c87aefeSPatrick Mooney 			default:
3284c87aefeSPatrick Mooney 				logical_cpus = 0;
3294c87aefeSPatrick Mooney 				level = 0;
3304c87aefeSPatrick Mooney 				func = 0;
3314c87aefeSPatrick Mooney 				break;
3324c87aefeSPatrick Mooney 			}
3334c87aefeSPatrick Mooney 
3344c87aefeSPatrick Mooney 			logical_cpus = MIN(0xfff, logical_cpus - 1);
3354c87aefeSPatrick Mooney 			regs[0] = (logical_cpus << 14) | (1 << 8) |
3364c87aefeSPatrick Mooney 			    (level << 5) | func;
3374c87aefeSPatrick Mooney 			regs[1] = (func > 0) ? (CACHE_LINE_SIZE - 1) : 0;
3384c87aefeSPatrick Mooney 			regs[2] = 0;
3394c87aefeSPatrick Mooney 			regs[3] = 0;
3404c87aefeSPatrick Mooney 			break;
3414c87aefeSPatrick Mooney 
3424c87aefeSPatrick Mooney 		case CPUID_8000_001E:
343154972afSPatrick Mooney 			/*
344154972afSPatrick Mooney 			 * AMD Family 16h+ and Hygon Family 18h additional
345154972afSPatrick Mooney 			 * identifiers.
346154972afSPatrick Mooney 			 */
347154972afSPatrick Mooney 			if (!vmm_is_svm() || CPUID_TO_FAMILY(cpu_id) < 0x16)
3484c87aefeSPatrick Mooney 				goto default_leaf;
3494c87aefeSPatrick Mooney 
3504c87aefeSPatrick Mooney 			vm_get_topology(vm, &sockets, &cores, &threads,
3514c87aefeSPatrick Mooney 			    &maxcpus);
3524c87aefeSPatrick Mooney 			regs[0] = vcpu_id;
3534c87aefeSPatrick Mooney 			threads = MIN(0xFF, threads - 1);
3544c87aefeSPatrick Mooney 			regs[1] = (threads << 8) |
3554c87aefeSPatrick Mooney 			    (vcpu_id >> log2(threads + 1));
3564c87aefeSPatrick Mooney 			/*
3574c87aefeSPatrick Mooney 			 * XXX Bhyve topology cannot yet represent >1 node per
3584c87aefeSPatrick Mooney 			 * processor.
3594c87aefeSPatrick Mooney 			 */
3604c87aefeSPatrick Mooney 			regs[2] = 0;
3614c87aefeSPatrick Mooney 			regs[3] = 0;
362bf21cd93STycho Nightingale 			break;
363bf21cd93STycho Nightingale 
364bf21cd93STycho Nightingale 		case CPUID_0000_0001:
365bf21cd93STycho Nightingale 			do_cpuid(1, regs);
366bf21cd93STycho Nightingale 
367bf21cd93STycho Nightingale 			error = vm_get_x2apic_state(vm, vcpu_id, &x2apic_state);
368bf21cd93STycho Nightingale 			if (error) {
369bf21cd93STycho Nightingale 				panic("x86_emulate_cpuid: error %d "
3702699b94cSPatrick Mooney 				    "fetching x2apic state", error);
371bf21cd93STycho Nightingale 			}
372bf21cd93STycho Nightingale 
373bf21cd93STycho Nightingale 			/*
374bf21cd93STycho Nightingale 			 * Override the APIC ID only in ebx
375bf21cd93STycho Nightingale 			 */
376bf21cd93STycho Nightingale 			regs[1] &= ~(CPUID_LOCAL_APIC_ID);
377bf21cd93STycho Nightingale 			regs[1] |= (vcpu_id << CPUID_0000_0001_APICID_SHIFT);
378bf21cd93STycho Nightingale 
379bf21cd93STycho Nightingale 			/*
3804c87aefeSPatrick Mooney 			 * Don't expose VMX, SpeedStep, TME or SMX capability.
381bf21cd93STycho Nightingale 			 * Advertise x2APIC capability and Hypervisor guest.
382bf21cd93STycho Nightingale 			 */
383bf21cd93STycho Nightingale 			regs[2] &= ~(CPUID2_VMX | CPUID2_EST | CPUID2_TM2);
3844c87aefeSPatrick Mooney 			regs[2] &= ~(CPUID2_SMX);
385bf21cd93STycho Nightingale 
386bf21cd93STycho Nightingale 			regs[2] |= CPUID2_HV;
387bf21cd93STycho Nightingale 
388bf21cd93STycho Nightingale 			if (x2apic_state != X2APIC_DISABLED)
389bf21cd93STycho Nightingale 				regs[2] |= CPUID2_X2APIC;
3904c87aefeSPatrick Mooney 			else
3914c87aefeSPatrick Mooney 				regs[2] &= ~CPUID2_X2APIC;
392bf21cd93STycho Nightingale 
393bf21cd93STycho Nightingale 			/*
3944c87aefeSPatrick Mooney 			 * Only advertise CPUID2_XSAVE in the guest if
3954c87aefeSPatrick Mooney 			 * the host is using XSAVE.
396bf21cd93STycho Nightingale 			 */
3974c87aefeSPatrick Mooney 			if (!(regs[2] & CPUID2_OSXSAVE))
3984c87aefeSPatrick Mooney 				regs[2] &= ~CPUID2_XSAVE;
3994c87aefeSPatrick Mooney 
4004c87aefeSPatrick Mooney 			/*
4014c87aefeSPatrick Mooney 			 * If CPUID2_XSAVE is being advertised and the
4024c87aefeSPatrick Mooney 			 * guest has set CR4_XSAVE, set
4034c87aefeSPatrick Mooney 			 * CPUID2_OSXSAVE.
4044c87aefeSPatrick Mooney 			 */
4054c87aefeSPatrick Mooney 			regs[2] &= ~CPUID2_OSXSAVE;
4064c87aefeSPatrick Mooney 			if (regs[2] & CPUID2_XSAVE) {
4074c87aefeSPatrick Mooney 				error = vm_get_register(vm, vcpu_id,
4084c87aefeSPatrick Mooney 				    VM_REG_GUEST_CR4, &cr4);
4094c87aefeSPatrick Mooney 				if (error)
4104c87aefeSPatrick Mooney 					panic("x86_emulate_cpuid: error %d "
4112699b94cSPatrick Mooney 					    "fetching %%cr4", error);
4124c87aefeSPatrick Mooney 				if (cr4 & CR4_XSAVE)
4134c87aefeSPatrick Mooney 					regs[2] |= CPUID2_OSXSAVE;
4144c87aefeSPatrick Mooney 			}
415bf21cd93STycho Nightingale 
416bf21cd93STycho Nightingale 			/*
417bf21cd93STycho Nightingale 			 * Hide monitor/mwait until we know how to deal with
418bf21cd93STycho Nightingale 			 * these instructions.
419bf21cd93STycho Nightingale 			 */
420bf21cd93STycho Nightingale 			regs[2] &= ~CPUID2_MON;
421bf21cd93STycho Nightingale 
4222699b94cSPatrick Mooney 			/*
423bf21cd93STycho Nightingale 			 * Hide the performance and debug features.
424bf21cd93STycho Nightingale 			 */
425bf21cd93STycho Nightingale 			regs[2] &= ~CPUID2_PDCM;
4264c87aefeSPatrick Mooney 
427bf21cd93STycho Nightingale 			/*
428bf21cd93STycho Nightingale 			 * No TSC deadline support in the APIC yet
429bf21cd93STycho Nightingale 			 */
430bf21cd93STycho Nightingale 			regs[2] &= ~CPUID2_TSCDLT;
431bf21cd93STycho Nightingale 
432bf21cd93STycho Nightingale 			/*
433bf21cd93STycho Nightingale 			 * Hide thermal monitoring
434bf21cd93STycho Nightingale 			 */
435bf21cd93STycho Nightingale 			regs[3] &= ~(CPUID_ACPI | CPUID_TM);
4364c87aefeSPatrick Mooney 
437bf21cd93STycho Nightingale 			/*
4384c87aefeSPatrick Mooney 			 * Hide the debug store capability.
439bf21cd93STycho Nightingale 			 */
440bf21cd93STycho Nightingale 			regs[3] &= ~CPUID_DS;
441bf21cd93STycho Nightingale 
442bf21cd93STycho Nightingale 			/*
4434c87aefeSPatrick Mooney 			 * Advertise the Machine Check and MTRR capability.
4444c87aefeSPatrick Mooney 			 *
4454c87aefeSPatrick Mooney 			 * Some guest OSes (e.g. Windows) will not boot if
4464c87aefeSPatrick Mooney 			 * these features are absent.
447bf21cd93STycho Nightingale 			 */
4484c87aefeSPatrick Mooney 			regs[3] |= (CPUID_MCA | CPUID_MCE | CPUID_MTRR);
4494c87aefeSPatrick Mooney 
4504c87aefeSPatrick Mooney 			vm_get_topology(vm, &sockets, &cores, &threads,
4514c87aefeSPatrick Mooney 			    &maxcpus);
4524c87aefeSPatrick Mooney 			logical_cpus = threads * cores;
453bf21cd93STycho Nightingale 			regs[1] &= ~CPUID_HTT_CORES;
4544c87aefeSPatrick Mooney 			regs[1] |= (logical_cpus & 0xff) << 16;
4554c87aefeSPatrick Mooney 			regs[3] |= CPUID_HTT;
456bf21cd93STycho Nightingale 			break;
457bf21cd93STycho Nightingale 
458bf21cd93STycho Nightingale 		case CPUID_0000_0004:
4593c5f2a9dSPatrick Mooney 			cpuid_count(func, param, regs);
460bf21cd93STycho Nightingale 
4614c87aefeSPatrick Mooney 			if (regs[0] || regs[1] || regs[2] || regs[3]) {
4624c87aefeSPatrick Mooney 				vm_get_topology(vm, &sockets, &cores, &threads,
4634c87aefeSPatrick Mooney 				    &maxcpus);
4644c87aefeSPatrick Mooney 				regs[0] &= 0x3ff;
4654c87aefeSPatrick Mooney 				regs[0] |= (cores - 1) << 26;
4664c87aefeSPatrick Mooney 				/*
4674c87aefeSPatrick Mooney 				 * Cache topology:
4684c87aefeSPatrick Mooney 				 * - L1 and L2 are shared only by the logical
4694c87aefeSPatrick Mooney 				 *   processors in a single core.
4704c87aefeSPatrick Mooney 				 * - L3 and above are shared by all logical
4714c87aefeSPatrick Mooney 				 *   processors in the package.
4724c87aefeSPatrick Mooney 				 */
4734c87aefeSPatrick Mooney 				logical_cpus = threads;
4744c87aefeSPatrick Mooney 				level = (regs[0] >> 5) & 0x7;
4754c87aefeSPatrick Mooney 				if (level >= 3)
4764c87aefeSPatrick Mooney 					logical_cpus *= cores;
4774c87aefeSPatrick Mooney 				regs[0] |= (logical_cpus - 1) << 14;
4784c87aefeSPatrick Mooney 			}
479bf21cd93STycho Nightingale 			break;
480bf21cd93STycho Nightingale 
481bf21cd93STycho Nightingale 		case CPUID_0000_0007:
4824c87aefeSPatrick Mooney 			regs[0] = 0;
4834c87aefeSPatrick Mooney 			regs[1] = 0;
4844c87aefeSPatrick Mooney 			regs[2] = 0;
4854c87aefeSPatrick Mooney 			regs[3] = 0;
4864c87aefeSPatrick Mooney 
4874c87aefeSPatrick Mooney 			/* leaf 0 */
4883c5f2a9dSPatrick Mooney 			if (param == 0) {
4893c5f2a9dSPatrick Mooney 				cpuid_count(func, param, regs);
4904c87aefeSPatrick Mooney 
4914c87aefeSPatrick Mooney 				/* Only leaf 0 is supported */
4924c87aefeSPatrick Mooney 				regs[0] = 0;
4934c87aefeSPatrick Mooney 
4944c87aefeSPatrick Mooney 				/*
4954c87aefeSPatrick Mooney 				 * Expose known-safe features.
4964c87aefeSPatrick Mooney 				 */
4974c87aefeSPatrick Mooney 				regs[1] &= (CPUID_STDEXT_FSGSBASE |
4984c87aefeSPatrick Mooney 				    CPUID_STDEXT_BMI1 | CPUID_STDEXT_HLE |
499b0de25cbSAndy Fiddaman 				    CPUID_STDEXT_AVX2 | CPUID_STDEXT_SMEP |
500b0de25cbSAndy Fiddaman 				    CPUID_STDEXT_BMI2 |
5014c87aefeSPatrick Mooney 				    CPUID_STDEXT_ERMS | CPUID_STDEXT_RTM |
5024c87aefeSPatrick Mooney 				    CPUID_STDEXT_AVX512F |
5034c87aefeSPatrick Mooney 				    CPUID_STDEXT_RDSEED |
504b0de25cbSAndy Fiddaman 				    CPUID_STDEXT_SMAP |
5054c87aefeSPatrick Mooney 				    CPUID_STDEXT_AVX512PF |
5064c87aefeSPatrick Mooney 				    CPUID_STDEXT_AVX512ER |
5074c87aefeSPatrick Mooney 				    CPUID_STDEXT_AVX512CD | CPUID_STDEXT_SHA);
5084c87aefeSPatrick Mooney 				regs[2] = 0;
5094c87aefeSPatrick Mooney 				regs[3] &= CPUID_STDEXT3_MD_CLEAR;
5104c87aefeSPatrick Mooney 
5114c87aefeSPatrick Mooney 				/* Advertise INVPCID if it is enabled. */
5124c87aefeSPatrick Mooney 				error = vm_get_capability(vm, vcpu_id,
5134c87aefeSPatrick Mooney 				    VM_CAP_ENABLE_INVPCID, &enable_invpcid);
5144c87aefeSPatrick Mooney 				if (error == 0 && enable_invpcid)
5154c87aefeSPatrick Mooney 					regs[1] |= CPUID_STDEXT_INVPCID;
5164c87aefeSPatrick Mooney 			}
5174c87aefeSPatrick Mooney 			break;
5184c87aefeSPatrick Mooney 
5194c87aefeSPatrick Mooney 		case CPUID_0000_0006:
5204c87aefeSPatrick Mooney 			regs[0] = CPUTPM1_ARAT;
5214c87aefeSPatrick Mooney 			regs[1] = 0;
5224c87aefeSPatrick Mooney 			regs[2] = 0;
5234c87aefeSPatrick Mooney 			regs[3] = 0;
5244c87aefeSPatrick Mooney 			break;
5254c87aefeSPatrick Mooney 
526bf21cd93STycho Nightingale 		case CPUID_0000_000A:
527bf21cd93STycho Nightingale 			/*
528bf21cd93STycho Nightingale 			 * Handle the access, but report 0 for
529bf21cd93STycho Nightingale 			 * all options
530bf21cd93STycho Nightingale 			 */
531bf21cd93STycho Nightingale 			regs[0] = 0;
532bf21cd93STycho Nightingale 			regs[1] = 0;
533bf21cd93STycho Nightingale 			regs[2] = 0;
534bf21cd93STycho Nightingale 			regs[3] = 0;
535bf21cd93STycho Nightingale 			break;
536bf21cd93STycho Nightingale 
537bf21cd93STycho Nightingale 		case CPUID_0000_000B:
538bf21cd93STycho Nightingale 			/*
5394c87aefeSPatrick Mooney 			 * Intel processor topology enumeration
540bf21cd93STycho Nightingale 			 */
5414c87aefeSPatrick Mooney 			if (vmm_is_intel()) {
5424c87aefeSPatrick Mooney 				vm_get_topology(vm, &sockets, &cores, &threads,
5434c87aefeSPatrick Mooney 				    &maxcpus);
5443c5f2a9dSPatrick Mooney 				if (param == 0) {
5454c87aefeSPatrick Mooney 					logical_cpus = threads;
5464c87aefeSPatrick Mooney 					width = log2(logical_cpus);
5474c87aefeSPatrick Mooney 					level = CPUID_TYPE_SMT;
5484c87aefeSPatrick Mooney 					x2apic_id = vcpu_id;
5494c87aefeSPatrick Mooney 				}
5504c87aefeSPatrick Mooney 
5513c5f2a9dSPatrick Mooney 				if (param == 1) {
5524c87aefeSPatrick Mooney 					logical_cpus = threads * cores;
5534c87aefeSPatrick Mooney 					width = log2(logical_cpus);
5544c87aefeSPatrick Mooney 					level = CPUID_TYPE_CORE;
5554c87aefeSPatrick Mooney 					x2apic_id = vcpu_id;
5564c87aefeSPatrick Mooney 				}
5574c87aefeSPatrick Mooney 
5583c5f2a9dSPatrick Mooney 				if (!cpuid_leaf_b || param >= 2) {
5594c87aefeSPatrick Mooney 					width = 0;
5604c87aefeSPatrick Mooney 					logical_cpus = 0;
5614c87aefeSPatrick Mooney 					level = 0;
5624c87aefeSPatrick Mooney 					x2apic_id = 0;
5634c87aefeSPatrick Mooney 				}
5644c87aefeSPatrick Mooney 
5654c87aefeSPatrick Mooney 				regs[0] = width & 0x1f;
5664c87aefeSPatrick Mooney 				regs[1] = logical_cpus & 0xffff;
5673c5f2a9dSPatrick Mooney 				regs[2] = (level << 8) | (param & 0xff);
5684c87aefeSPatrick Mooney 				regs[3] = x2apic_id;
5694c87aefeSPatrick Mooney 			} else {
5704c87aefeSPatrick Mooney 				regs[0] = 0;
5714c87aefeSPatrick Mooney 				regs[1] = 0;
5724c87aefeSPatrick Mooney 				regs[2] = 0;
5734c87aefeSPatrick Mooney 				regs[3] = 0;
5744c87aefeSPatrick Mooney 			}
5754c87aefeSPatrick Mooney 			break;
5764c87aefeSPatrick Mooney 
5774c87aefeSPatrick Mooney 		case CPUID_0000_000D:
5784c87aefeSPatrick Mooney 			limits = vmm_get_xsave_limits();
5794c87aefeSPatrick Mooney 			if (!limits->xsave_enabled) {
5804c87aefeSPatrick Mooney 				regs[0] = 0;
5814c87aefeSPatrick Mooney 				regs[1] = 0;
5824c87aefeSPatrick Mooney 				regs[2] = 0;
5834c87aefeSPatrick Mooney 				regs[3] = 0;
5844c87aefeSPatrick Mooney 				break;
5854c87aefeSPatrick Mooney 			}
5864c87aefeSPatrick Mooney 
5873c5f2a9dSPatrick Mooney 			cpuid_count(func, param, regs);
5883c5f2a9dSPatrick Mooney 			switch (param) {
5894c87aefeSPatrick Mooney 			case 0:
5904c87aefeSPatrick Mooney 				/*
5914c87aefeSPatrick Mooney 				 * Only permit the guest to use bits
5924c87aefeSPatrick Mooney 				 * that are active in the host in
5934c87aefeSPatrick Mooney 				 * %xcr0.  Also, claim that the
5944c87aefeSPatrick Mooney 				 * maximum save area size is
5954c87aefeSPatrick Mooney 				 * equivalent to the host's current
5964c87aefeSPatrick Mooney 				 * save area size.  Since this runs
5974c87aefeSPatrick Mooney 				 * "inside" of vmrun(), it runs with
5984c87aefeSPatrick Mooney 				 * the guest's xcr0, so the current
5994c87aefeSPatrick Mooney 				 * save area size is correct as-is.
6004c87aefeSPatrick Mooney 				 */
6014c87aefeSPatrick Mooney 				regs[0] &= limits->xcr0_allowed;
6024c87aefeSPatrick Mooney 				regs[2] = limits->xsave_max_size;
6034c87aefeSPatrick Mooney 				regs[3] &= (limits->xcr0_allowed >> 32);
6044c87aefeSPatrick Mooney 				break;
6054c87aefeSPatrick Mooney 			case 1:
6064c87aefeSPatrick Mooney 				/* Only permit XSAVEOPT. */
6074c87aefeSPatrick Mooney 				regs[0] &= CPUID_EXTSTATE_XSAVEOPT;
6084c87aefeSPatrick Mooney 				regs[1] = 0;
6094c87aefeSPatrick Mooney 				regs[2] = 0;
6104c87aefeSPatrick Mooney 				regs[3] = 0;
6114c87aefeSPatrick Mooney 				break;
6124c87aefeSPatrick Mooney 			default:
6134c87aefeSPatrick Mooney 				/*
6144c87aefeSPatrick Mooney 				 * If the leaf is for a permitted feature,
6154c87aefeSPatrick Mooney 				 * pass through as-is, otherwise return
6164c87aefeSPatrick Mooney 				 * all zeroes.
6174c87aefeSPatrick Mooney 				 */
6183c5f2a9dSPatrick Mooney 				if (!(limits->xcr0_allowed & (1ul << param))) {
6194c87aefeSPatrick Mooney 					regs[0] = 0;
6204c87aefeSPatrick Mooney 					regs[1] = 0;
6214c87aefeSPatrick Mooney 					regs[2] = 0;
6224c87aefeSPatrick Mooney 					regs[3] = 0;
6234c87aefeSPatrick Mooney 				}
6244c87aefeSPatrick Mooney 				break;
6254c87aefeSPatrick Mooney 			}
626bf21cd93STycho Nightingale 			break;
627bf21cd93STycho Nightingale 
6281a5f1879SPatrick Mooney 		case CPUID_0000_000F:
6291a5f1879SPatrick Mooney 		case CPUID_0000_0010:
6301a5f1879SPatrick Mooney 			/*
6311a5f1879SPatrick Mooney 			 * Do not report any Resource Director Technology
6321a5f1879SPatrick Mooney 			 * capabilities.  Exposing control of cache or memory
6331a5f1879SPatrick Mooney 			 * controller resource partitioning to the guest is not
6341a5f1879SPatrick Mooney 			 * at all sensible.
6351a5f1879SPatrick Mooney 			 *
6361a5f1879SPatrick Mooney 			 * This is already hidden at a high level by masking of
6371a5f1879SPatrick Mooney 			 * leaf 0x7.  Even still, a guest may look here for
6381a5f1879SPatrick Mooney 			 * detailed capability information.
6391a5f1879SPatrick Mooney 			 */
6401a5f1879SPatrick Mooney 			regs[0] = 0;
6411a5f1879SPatrick Mooney 			regs[1] = 0;
6421a5f1879SPatrick Mooney 			regs[2] = 0;
6431a5f1879SPatrick Mooney 			regs[3] = 0;
6441a5f1879SPatrick Mooney 			break;
6451a5f1879SPatrick Mooney 
646154972afSPatrick Mooney 		case CPUID_0000_0015:
647154972afSPatrick Mooney 			/*
648154972afSPatrick Mooney 			 * Don't report CPU TSC/Crystal ratio and clock
649154972afSPatrick Mooney 			 * values since guests may use these to derive the
650154972afSPatrick Mooney 			 * local APIC frequency..
651154972afSPatrick Mooney 			 */
652154972afSPatrick Mooney 			regs[0] = 0;
653154972afSPatrick Mooney 			regs[1] = 0;
654154972afSPatrick Mooney 			regs[2] = 0;
655154972afSPatrick Mooney 			regs[3] = 0;
656154972afSPatrick Mooney 			break;
657154972afSPatrick Mooney 
658bf21cd93STycho Nightingale 		case 0x40000000:
659bf21cd93STycho Nightingale 			regs[0] = CPUID_VM_HIGH;
660bf21cd93STycho Nightingale 			bcopy(bhyve_id, &regs[1], 4);
661bf21cd93STycho Nightingale 			bcopy(bhyve_id + 4, &regs[2], 4);
662bf21cd93STycho Nightingale 			bcopy(bhyve_id + 8, &regs[3], 4);
663bf21cd93STycho Nightingale 			break;
664bf21cd93STycho Nightingale 
665bf21cd93STycho Nightingale 		default:
6664c87aefeSPatrick Mooney default_leaf:
667bf21cd93STycho Nightingale 			/*
668bf21cd93STycho Nightingale 			 * The leaf value has already been clamped so
669bf21cd93STycho Nightingale 			 * simply pass this through, keeping count of
670bf21cd93STycho Nightingale 			 * how many unhandled leaf values have been seen.
671bf21cd93STycho Nightingale 			 */
672bf21cd93STycho Nightingale 			atomic_add_long(&bhyve_xcpuids, 1);
6733c5f2a9dSPatrick Mooney 			cpuid_count(func, param, regs);
674bf21cd93STycho Nightingale 			break;
675bf21cd93STycho Nightingale 	}
676bf21cd93STycho Nightingale 
6773c5f2a9dSPatrick Mooney 	/*
6783c5f2a9dSPatrick Mooney 	 * CPUID clears the upper 32-bits of the long-mode registers.
6793c5f2a9dSPatrick Mooney 	 */
6803c5f2a9dSPatrick Mooney 	*rax = regs[0];
6813c5f2a9dSPatrick Mooney 	*rbx = regs[1];
6823c5f2a9dSPatrick Mooney 	*rcx = regs[2];
6833c5f2a9dSPatrick Mooney 	*rdx = regs[3];
684bf21cd93STycho Nightingale 
685bf21cd93STycho Nightingale 	return (1);
686bf21cd93STycho Nightingale }
6874c87aefeSPatrick Mooney 
688*54cf5b63SPatrick Mooney /*
689*54cf5b63SPatrick Mooney  * Return 'true' if the capability 'cap' is enabled in this virtual cpu
690*54cf5b63SPatrick Mooney  * and 'false' otherwise.
691*54cf5b63SPatrick Mooney  */
6924c87aefeSPatrick Mooney bool
vm_cpuid_capability(struct vm * vm,int vcpuid,enum vm_cpuid_capability cap)6934c87aefeSPatrick Mooney vm_cpuid_capability(struct vm *vm, int vcpuid, enum vm_cpuid_capability cap)
6944c87aefeSPatrick Mooney {
6954c87aefeSPatrick Mooney 	bool rv;
6964c87aefeSPatrick Mooney 
6974c87aefeSPatrick Mooney 	KASSERT(cap > 0 && cap < VCC_LAST, ("%s: invalid vm_cpu_capability %d",
6984c87aefeSPatrick Mooney 	    __func__, cap));
6994c87aefeSPatrick Mooney 
7004c87aefeSPatrick Mooney 	/*
7014c87aefeSPatrick Mooney 	 * Simply passthrough the capabilities of the host cpu for now.
7024c87aefeSPatrick Mooney 	 */
7034c87aefeSPatrick Mooney 	rv = false;
7044c87aefeSPatrick Mooney 	switch (cap) {
7054c87aefeSPatrick Mooney #ifdef __FreeBSD__
7064c87aefeSPatrick Mooney 	case VCC_NO_EXECUTE:
7074c87aefeSPatrick Mooney 		if (amd_feature & AMDID_NX)
7084c87aefeSPatrick Mooney 			rv = true;
7094c87aefeSPatrick Mooney 		break;
7104c87aefeSPatrick Mooney 	case VCC_FFXSR:
7114c87aefeSPatrick Mooney 		if (amd_feature & AMDID_FFXSR)
7124c87aefeSPatrick Mooney 			rv = true;
7134c87aefeSPatrick Mooney 		break;
7144c87aefeSPatrick Mooney 	case VCC_TCE:
7154c87aefeSPatrick Mooney 		if (amd_feature2 & AMDID2_TCE)
7164c87aefeSPatrick Mooney 			rv = true;
7174c87aefeSPatrick Mooney 		break;
7184c87aefeSPatrick Mooney #else
7194c87aefeSPatrick Mooney 	case VCC_NO_EXECUTE:
7204c87aefeSPatrick Mooney 		if (is_x86_feature(x86_featureset, X86FSET_NX))
7214c87aefeSPatrick Mooney 			rv = true;
7224c87aefeSPatrick Mooney 		break;
7234c87aefeSPatrick Mooney 	/* XXXJOY: No kernel detection for FFXR or TCE at present, so ignore */
7244c87aefeSPatrick Mooney 	case VCC_FFXSR:
7254c87aefeSPatrick Mooney 	case VCC_TCE:
7264c87aefeSPatrick Mooney 		break;
7274c87aefeSPatrick Mooney #endif
7284c87aefeSPatrick Mooney 	default:
7294c87aefeSPatrick Mooney 		panic("%s: unknown vm_cpu_capability %d", __func__, cap);
7304c87aefeSPatrick Mooney 	}
7314c87aefeSPatrick Mooney 	return (rv);
7324c87aefeSPatrick Mooney }
733*54cf5b63SPatrick Mooney 
734*54cf5b63SPatrick Mooney bool
validate_guest_xcr0(uint64_t val,uint64_t limit_mask)735*54cf5b63SPatrick Mooney validate_guest_xcr0(uint64_t val, uint64_t limit_mask)
736*54cf5b63SPatrick Mooney {
737*54cf5b63SPatrick Mooney 	/* x87 feature must be enabled */
738*54cf5b63SPatrick Mooney 	if ((val & XFEATURE_ENABLED_X87) == 0) {
739*54cf5b63SPatrick Mooney 		return (false);
740*54cf5b63SPatrick Mooney 	}
741*54cf5b63SPatrick Mooney 	/* AVX cannot be enabled without SSE */
742*54cf5b63SPatrick Mooney 	if ((val & (XFEATURE_ENABLED_SSE | XFEATURE_ENABLED_AVX)) ==
743*54cf5b63SPatrick Mooney 	    XFEATURE_ENABLED_SSE) {
744*54cf5b63SPatrick Mooney 		return (false);
745*54cf5b63SPatrick Mooney 	}
746*54cf5b63SPatrick Mooney 	/* No bits should be outside what we dictate to be allowed */
747*54cf5b63SPatrick Mooney 	if ((val & ~limit_mask) != 0) {
748*54cf5b63SPatrick Mooney 		return (false);
749*54cf5b63SPatrick Mooney 	}
750*54cf5b63SPatrick Mooney 
751*54cf5b63SPatrick Mooney 	return (true);
752*54cf5b63SPatrick Mooney }