|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH 8/8] x86/cpuid: emulate extended topology enumeration leaf
This patch sets policy for guest's CPUID.0xb. eax return value can be infered
from the number of core/thread in one socket/core. ebx cannot be zero
otherwise it means CPUID.0xb isn't supported. edx is the x2apic id of each
vcpu, which would be adjusted in Xen according the context. ecx[7:0] should be
the same value in ecx input . ecx[15:8] should be the level type.
This patch also sets policy for guest's CPUID.4:EAX[25:14]. Rather than
passing the host value to guest, we set this field to the number of thread
in each core to be consistent with CPU topology.
Signed-off-by: Chao Gao <chao.gao@xxxxxxxxx>
---
tools/libxc/include/xenctrl.h | 8 ++++
tools/libxc/xc_cpuid_x86.c | 86 ++++++++++++++++++++++++++++++++++++++++---
tools/libxc/xc_domain.c | 35 ++++++++++++++++++
xen/arch/x86/cpuid.c | 25 +++++++++++++
xen/arch/x86/domctl.c | 8 ++++
xen/include/asm-x86/cpuid.h | 12 ++++++
6 files changed, 168 insertions(+), 6 deletions(-)
diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index e897e5d..2eab621 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -1348,6 +1348,14 @@ int xc_set_cpu_topology(xc_interface *xch,
uint32_t size,
uint8_t thread_per_core,
uint8_t core_per_socket);
+
+int xc_get_cpu_topology(xc_interface *xch,
+ uint32_t domid,
+ uint32_t size,
+ uint32_t *tid,
+ uint8_t *thread_per_core,
+ uint8_t *core_per_socket);
+
#endif
int xc_reserved_device_memory_map(xc_interface *xch,
diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c
index 25b922e..0891ace 100644
--- a/tools/libxc/xc_cpuid_x86.c
+++ b/tools/libxc/xc_cpuid_x86.c
@@ -178,6 +178,10 @@ struct cpuid_domain_info
/* HVM-only information. */
bool pae;
bool nestedhvm;
+ /* CPU topology information. */
+ bool topology_supported;
+ uint8_t core_per_socket;
+ uint8_t thread_per_core;
};
static void cpuid(const unsigned int *input, unsigned int *regs)
@@ -280,6 +284,14 @@ static int get_cpuid_domain_info(xc_interface *xch,
uint32_t domid,
if ( rc )
return rc;
}
+
+ /* retrieve CPU topology information */
+ rc = xc_get_cpu_topology(xch, domid, 0, NULL,
+ &info->thread_per_core,
+ &info->core_per_socket);
+ info->topology_supported = !rc;
+ if ( rc )
+ return rc;
}
else
{
@@ -365,6 +377,17 @@ static void amd_xc_cpuid_policy(xc_interface *xch,
}
}
+static inline int fls(unsigned int x)
+{
+ int r;
+
+ asm ( "bsr %1,%0\n\t"
+ "jnz 1f\n\t"
+ "mov $-1,%0\n"
+ "1:" : "=r" (r) : "rm" (x));
+ return r + 1;
+}
+
static void intel_xc_cpuid_policy(xc_interface *xch,
const struct cpuid_domain_info *info,
const unsigned int *input, unsigned int
*regs)
@@ -379,6 +402,38 @@ static void intel_xc_cpuid_policy(xc_interface *xch,
regs[0] = (((regs[0] & 0x7c000000u) << 1) | 0x04000000u |
(regs[0] & 0x3ffu));
regs[3] &= 0x3ffu;
+
+ if ( !info->topology_supported )
+ break;
+ /* only emulate cache topology when host supports this level */
+ if ( (input[1] == 2 || input[1] == 3) && regs[0] )
+ regs[0] = (regs[0] & 0x3fffu) | (info->core_per_socket << 26) |
+ ((info->thread_per_core - 1) << 14);
+ break;
+
+ case 0x0000000b:
+ if ( !info->topology_supported )
+ break;
+
+ switch ( input[1] )
+ {
+ case 0:
+ regs[0] = fls(info->thread_per_core - 1);
+ regs[1] = 1;
+ regs[2] = 1 << 8;
+ break;
+
+ case 1:
+ regs[0] = fls(info->thread_per_core - 1) +
+ fls(info->core_per_socket - 1);
+ regs[1] = 1;
+ regs[2] = 2 << 8;
+ break;
+
+ default:
+ regs[0] = regs[1] = regs[2] = regs[3] = 0;
+ break;
+ }
break;
case 0x80000000:
@@ -409,16 +464,27 @@ static void xc_cpuid_hvm_policy(xc_interface *xch,
break;
case 0x00000001:
- /*
- * EBX[23:16] is Maximum Logical Processors Per Package.
- * Update to reflect vLAPIC_ID = vCPU_ID * 2.
- */
- regs[1] = (regs[1] & 0x0000ffffu) | ((regs[1] & 0x007f0000u) << 1);
+ {
+ if ( info->topology_supported )
+ {
+ int bit = fls(info->thread_per_core - 1) +
+ fls(info->core_per_socket - 1);
+
+ regs[1] = (regs[1] & 0x0000ffffu) |
+ (((bit < 8) ? (1 << bit) : 0xff) << 16);
+ }
+ else
+ /*
+ * EBX[23:16] is Maximum Logical Processors Per Package.
+ * Update to reflect vLAPIC_ID = vCPU_ID * 2.
+ */
+ regs[1] = (regs[1] & 0x0000ffffu) | ((regs[1] & 0x007f0000u) << 1);
regs[2] = info->featureset[featureword_of(X86_FEATURE_SSE3)];
regs[3] = (info->featureset[featureword_of(X86_FEATURE_FPU)] |
bitmaskof(X86_FEATURE_HTT));
break;
+ }
case 0x00000007: /* Intel-defined CPU features */
if ( input[1] == 0 )
@@ -470,6 +536,7 @@ static void xc_cpuid_hvm_policy(xc_interface *xch,
case 0x00000002: /* Intel cache info (dumped by AMD policy) */
case 0x00000004: /* Intel cache info (dumped by AMD policy) */
+ case 0x0000000b: /* Intel Extended Topology Enumeration Leaf */
case 0x0000000a: /* Architectural Performance Monitor Features */
case 0x80000002: /* Processor name string */
case 0x80000003: /* ... continued */
@@ -757,12 +824,19 @@ int xc_cpuid_apply_policy(xc_interface *xch, uint32_t
domid,
continue;
}
+ if ( input[0] == 0xb )
+ {
+ input[1]++;
+ if ( regs[0] || regs[1] || regs[2] || regs[3] )
+ continue;
+ }
+
input[0]++;
if ( !(input[0] & 0x80000000u) && (input[0] > base_max ) )
input[0] = 0x80000000u;
input[1] = XEN_CPUID_INPUT_UNUSED;
- if ( (input[0] == 4) || (input[0] == 7) )
+ if ( (input[0] == 4) || (input[0] == 7) || (input[0] == 0xb) )
input[1] = 0;
else if ( input[0] == 0xd )
input[1] = 1; /* Xen automatically calculates almost everything. */
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index f8bb1eb..2ececbe 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -2471,6 +2471,41 @@ int xc_set_cpu_topology(xc_interface *xch,
return rc;
}
+
+int xc_get_cpu_topology(xc_interface *xch,
+ uint32_t domid,
+ uint32_t size,
+ uint32_t *tid,
+ uint8_t *thread_per_core,
+ uint8_t *core_per_socket)
+{
+ int rc;
+ DECLARE_HYPERCALL_BOUNCE(tid, sizeof(*tid) * size,
+ XC_HYPERCALL_BUFFER_BOUNCE_OUT);
+ struct xen_cpu_topology_info cpu_topology =
+ { .domid = domid, .size = size };
+
+ if ( xc_hypercall_bounce_pre(xch, tid) )
+ {
+ rc = -1;
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ set_xen_guest_handle(cpu_topology.tid.h, tid);
+ rc = do_memory_op(xch, XENMEM_get_cpu_topology, &cpu_topology,
+ sizeof(cpu_topology));
+ if ( !rc )
+ {
+ *thread_per_core = cpu_topology.thread_per_core;
+ *core_per_socket = cpu_topology.core_per_socket;
+ }
+
+ failed:
+ xc_hypercall_buffer_free(xch, tid);
+
+ return rc;
+}
/*
* Local variables:
* mode: C
diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c
index b47dc86..4d8b20e 100644
--- a/xen/arch/x86/cpuid.c
+++ b/xen/arch/x86/cpuid.c
@@ -563,6 +563,24 @@ void recalculate_cpuid_policy(struct domain *d)
}
}
+ for ( i = 0; i < ARRAY_SIZE(p->ext_topo.raw); ++i )
+ {
+ printk("level_type %x\n", p->ext_topo.subleaf[i].level_type);
+ if ( p->ext_topo.subleaf[i].level_type == 1 ||
+ p->ext_topo.subleaf[i].level_type == 2 )
+ {
+ /* Subleaf has a valid level type. Zero reserved fields. */
+ p->ext_topo.raw[i].a &= 0x0000001f;
+ p->ext_topo.raw[i].b &= 0x0000ffff;
+ p->ext_topo.raw[i].c &= 0x0000ffff;
+ }
+ else
+ {
+ zero_leaves(p->ext_topo.raw, i, ARRAY_SIZE(p->cache.raw) - 1);
+ break;
+ }
+ }
+
if ( !p->extd.svm )
p->extd.raw[0xa] = EMPTY_LEAF;
@@ -634,6 +652,13 @@ void guest_cpuid(const struct vcpu *v, uint32_t leaf,
*res = p->feat.raw[subleaf];
break;
+ case 0xb:
+ if ( subleaf >= ARRAY_SIZE(p->ext_topo.raw) )
+ return;
+
+ *res = p->ext_topo.raw[subleaf];
+ break;
+
case XSTATE_CPUID:
if ( !p->basic.xsave || subleaf >= ARRAY_SIZE(p->xstate.raw) )
return;
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 4e1bbd5..b7e4f44 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -70,6 +70,10 @@ static int update_domain_cpuid_info(struct domain *d,
ctl->input[1] >= ARRAY_SIZE(p->feat.raw) )
return 0;
+ if ( ctl->input[0] == 0xb &&
+ ctl->input[1] >= ARRAY_SIZE(p->ext_topo.raw) )
+ return 0;
+
BUILD_BUG_ON(ARRAY_SIZE(p->xstate.raw) < 2);
if ( ctl->input[0] == XSTATE_CPUID &&
ctl->input[1] != 1 ) /* Everything else automatically calculated.
*/
@@ -100,6 +104,10 @@ static int update_domain_cpuid_info(struct domain *d,
p->feat.raw[ctl->input[1]] = leaf;
break;
+ case 0xb:
+ p->ext_topo.raw[ctl->input[1]] = leaf;
+ break;
+
case XSTATE_CPUID:
p->xstate.raw[ctl->input[1]] = leaf;
break;
diff --git a/xen/include/asm-x86/cpuid.h b/xen/include/asm-x86/cpuid.h
index d2dd841..54e36bd 100644
--- a/xen/include/asm-x86/cpuid.h
+++ b/xen/include/asm-x86/cpuid.h
@@ -64,6 +64,7 @@ DECLARE_PER_CPU(bool, cpuid_faulting_enabled);
#define CPUID_GUEST_NR_BASIC (0xdu + 1)
#define CPUID_GUEST_NR_FEAT (0u + 1)
#define CPUID_GUEST_NR_CACHE (5u + 1)
+#define CPUID_GUEST_NR_EXT_TOPO (2u + 1)
#define CPUID_GUEST_NR_XSTATE (62u + 1)
#define CPUID_GUEST_NR_EXTD_INTEL (0x8u + 1)
#define CPUID_GUEST_NR_EXTD_AMD (0x1cu + 1)
@@ -145,6 +146,17 @@ struct cpuid_policy
};
} feat;
+ /* Structured Extended Topology Enumeration Leaf */
+ union {
+ struct cpuid_leaf raw[CPUID_GUEST_NR_EXT_TOPO];
+ struct cpuid_ext_topo_leaf {
+ uint32_t shift:5, :27;
+ uint32_t proc_num:16, :16;
+ uint32_t level_num:8, level_type:8, :16;
+ uint32_t x2apic_id;
+ } subleaf[CPUID_GUEST_NR_EXT_TOPO];
+ } ext_topo;
+
/* Xstate feature leaf: 0x0000000D[xx] */
union {
struct cpuid_leaf raw[CPUID_GUEST_NR_XSTATE];
--
1.8.3.1
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |