[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 |