summaryrefslogtreecommitdiffstats
path: root/sys/amd64/vmm
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2014-08-24 01:10:06 +0000
committerneel <neel@FreeBSD.org>2014-08-24 01:10:06 +0000
commitca77633f85ec8d4de0c78650f26f450b0eba2d79 (patch)
tree275e117a5df398fc630b53fd2ecdcefc7f1865f2 /sys/amd64/vmm
parent33474e62d390df5950ef68ffdb5a20736c8da51c (diff)
downloadFreeBSD-src-ca77633f85ec8d4de0c78650f26f450b0eba2d79.zip
FreeBSD-src-ca77633f85ec8d4de0c78650f26f450b0eba2d79.tar.gz
Add "hw.vmm.topology.threads_per_core" and "hw.vmm.topology.cores_per_package"
tunables to modify the default cpu topology advertised by bhyve. Also add a tunable "hw.vmm.topology.cpuid_leaf_b" to disable the CPUID leaf 0xb. This is intended for testing guest behavior when it falls back on using CPUID leaf 0x4 to deduce CPU topology. The default behavior is to advertise each vcpu as a core in a separate soket.
Diffstat (limited to 'sys/amd64/vmm')
-rw-r--r--sys/amd64/vmm/x86.c101
1 files changed, 77 insertions, 24 deletions
diff --git a/sys/amd64/vmm/x86.c b/sys/amd64/vmm/x86.c
index 071c727..c7515cf 100644
--- a/sys/amd64/vmm/x86.c
+++ b/sys/amd64/vmm/x86.c
@@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include <sys/pcpu.h>
#include <sys/systm.h>
#include <sys/cpuset.h>
+#include <sys/sysctl.h>
#include <machine/clock.h>
#include <machine/cpufunc.h>
@@ -45,20 +46,49 @@ __FBSDID("$FreeBSD$");
#include "vmm_host.h"
#include "x86.h"
+SYSCTL_DECL(_hw_vmm);
+static SYSCTL_NODE(_hw_vmm, OID_AUTO, topology, CTLFLAG_RD, 0, NULL);
+
#define CPUID_VM_HIGH 0x40000000
static const char bhyve_id[12] = "bhyve bhyve ";
static uint64_t bhyve_xcpuids;
+/*
+ * The default CPU topology is a single thread per package.
+ */
+static u_int threads_per_core = 1;
+SYSCTL_UINT(_hw_vmm_topology, OID_AUTO, threads_per_core, CTLFLAG_RDTUN,
+ &threads_per_core, 0, NULL);
+
+static u_int cores_per_package = 1;
+SYSCTL_UINT(_hw_vmm_topology, OID_AUTO, cores_per_package, CTLFLAG_RDTUN,
+ &cores_per_package, 0, NULL);
+
+static int cpuid_leaf_b = 1;
+SYSCTL_INT(_hw_vmm_topology, OID_AUTO, cpuid_leaf_b, CTLFLAG_RDTUN,
+ &cpuid_leaf_b, 0, NULL);
+
+/*
+ * Round up to the next power of two, if necessary, and then take log2.
+ * Returns -1 if argument is zero.
+ */
+static __inline int
+log2(u_int x)
+{
+
+ return (fls(x << (1 - powerof2(x))) - 1);
+}
+
int
x86_emulate_cpuid(struct vm *vm, int vcpu_id,
uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
{
const struct xsave_limits *limits;
uint64_t cr4;
- int error, enable_invpcid;
- unsigned int func, regs[4];
+ int error, enable_invpcid, level, width, x2apic_id;
+ unsigned int func, regs[4], logical_cpus;
enum x2apic_state x2apic_state;
/*
@@ -207,30 +237,31 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id,
*/
regs[3] &= ~CPUID_DS;
- /*
- * Disable multi-core.
- */
+ logical_cpus = threads_per_core * cores_per_package;
regs[1] &= ~CPUID_HTT_CORES;
- regs[3] &= ~CPUID_HTT;
+ regs[1] |= (logical_cpus & 0xff) << 16;
+ regs[3] |= CPUID_HTT;
break;
case CPUID_0000_0004:
cpuid_count(*eax, *ecx, regs);
- /*
- * Do not expose topology.
- *
- * The maximum number of processor cores in
- * this physical processor package and the
- * maximum number of threads sharing this
- * cache are encoded with "plus 1" encoding.
- * Adding one to the value in this register
- * field to obtains the actual value.
- *
- * Therefore 0 for both indicates 1 core per
- * package and no cache sharing.
- */
- regs[0] &= 0x3ff;
+ if (regs[0] || regs[1] || regs[2] || regs[3]) {
+ regs[0] &= 0x3ff;
+ regs[0] |= (cores_per_package - 1) << 26;
+ /*
+ * Cache topology:
+ * - L1 and L2 are shared only by the logical
+ * processors in a single core.
+ * - L3 and above are shared by all logical
+ * processors in the package.
+ */
+ logical_cpus = threads_per_core;
+ level = (regs[0] >> 5) & 0x7;
+ if (level >= 3)
+ logical_cpus *= cores_per_package;
+ regs[0] |= (logical_cpus - 1) << 14;
+ }
break;
case CPUID_0000_0007:
@@ -284,10 +315,32 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id,
/*
* Processor topology enumeration
*/
- regs[0] = 0;
- regs[1] = 0;
- regs[2] = *ecx & 0xff;
- regs[3] = vcpu_id;
+ if (*ecx == 0) {
+ logical_cpus = threads_per_core;
+ width = log2(logical_cpus);
+ level = CPUID_TYPE_SMT;
+ x2apic_id = vcpu_id;
+ }
+
+ if (*ecx == 1) {
+ logical_cpus = threads_per_core *
+ cores_per_package;
+ width = log2(logical_cpus);
+ level = CPUID_TYPE_CORE;
+ x2apic_id = vcpu_id;
+ }
+
+ if (!cpuid_leaf_b || *ecx >= 2) {
+ width = 0;
+ logical_cpus = 0;
+ level = 0;
+ x2apic_id = 0;
+ }
+
+ regs[0] = width & 0x1f;
+ regs[1] = logical_cpus & 0xffff;
+ regs[2] = (level << 8) | (*ecx & 0xff);
+ regs[3] = x2apic_id;
break;
case CPUID_0000_000D:
OpenPOWER on IntegriCloud