[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.