[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 1/4] x86/domctl: Move all CPUID update logic into update_domain_cpuid_info()



This simplifies the XEN_DOMCTL_set_cpuid handling, splitting the safety logic
away from the internals of how an update is completed.

The legacy cpuids[] logic is left in alone in a fuction, as it wont survive
very long.  update_domain_cpuid_info() gains a small performance optimisation
to skip all update activites for leaves which won't have any impact on the
guest.  This is temporary until the new hypercall API is completed.

Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
CC: Jan Beulich <JBeulich@xxxxxxxx>

The number hypercalls made by the toolstack is quite large, while the number
which we care about will reduce as Xen does more calculations itself, at the
same time as the cost of recaculations growing.
---
 xen/arch/x86/domctl.c | 140 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 86 insertions(+), 54 deletions(-)

diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index b01a1f9..a5a56ee 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -48,30 +48,98 @@ static int gdbsx_guest_mem_io(domid_t domid, struct 
xen_domctl_gdbsx_memio *iop)
     return iop->remain ? -EFAULT : 0;
 }
 
-static void update_domain_cpuid_info(struct domain *d,
+static int update_legacy_cpuid_array(struct domain *d,
                                      const xen_domctl_cpuid_t *ctl)
 {
+    cpuid_input_t *cpuid, *unused = NULL;
+    unsigned int i;
+
+    /* Try to insert ctl into d->arch.cpuids[] */
+    for ( i = 0; i < MAX_CPUID_INPUT; i++ )
+    {
+        cpuid = &d->arch.cpuids[i];
+
+        if ( cpuid->input[0] == XEN_CPUID_INPUT_UNUSED )
+        {
+            if ( !unused )
+                unused = cpuid;
+            continue;
+        }
+
+        if ( (cpuid->input[0] == ctl->input[0]) &&
+             ((cpuid->input[1] == XEN_CPUID_INPUT_UNUSED) ||
+              (cpuid->input[1] == ctl->input[1])) )
+            break;
+    }
+
+    if ( !(ctl->eax | ctl->ebx | ctl->ecx | ctl->edx) )
+    {
+        if ( i < MAX_CPUID_INPUT )
+            cpuid->input[0] = XEN_CPUID_INPUT_UNUSED;
+    }
+    else if ( i < MAX_CPUID_INPUT )
+        *cpuid = *ctl;
+    else if ( unused )
+        *unused = *ctl;
+    else
+        return -ENOENT;
+
+    return 0;
+}
+
+static int update_domain_cpuid_info(struct domain *d,
+                                    const xen_domctl_cpuid_t *ctl)
+{
     struct cpuid_policy *p = d->arch.cpuid;
     const struct cpuid_leaf leaf = { ctl->eax, ctl->ebx, ctl->ecx, ctl->edx };
+    int rc;
+
+    /*
+     * Skip update for leaves we don't care about.  This avoids the overhead
+     * of recalculate_cpuid_policy() and making d->arch.cpuids[] needlessly
+     * longer to search.
+     */
+    switch ( ctl->input[0] )
+    {
+    case 0x00000000 ... ARRAY_SIZE(p->basic.raw) - 1:
+        if ( ctl->input[0] == 7 &&
+             ctl->input[1] >= ARRAY_SIZE(p->feat.raw) )
+            return 0;
+        if ( ctl->input[0] == XSTATE_CPUID &&
+             ctl->input[1] >= ARRAY_SIZE(p->xstate.raw) )
+            return 0;
+        break;
+
+    case 0x40000000: case 0x40000100:
+        /* Only care about the max_leaf limit. */
+
+    case 0x80000000 ... 0x80000000 + ARRAY_SIZE(p->extd.raw) - 1:
+        break;
+
+    default:
+        return 0;
+    }
+
+    rc = update_legacy_cpuid_array(d, ctl);
+    if ( rc )
+        return rc;
 
     /* Insert ctl data into cpuid_policy. */
-    if ( ctl->input[0] < ARRAY_SIZE(p->basic.raw) )
+    switch ( ctl->input[0] )
     {
+    case 0x00000000 ... ARRAY_SIZE(p->basic.raw) - 1:
         if ( ctl->input[0] == 7 )
-        {
-            if ( ctl->input[1] < ARRAY_SIZE(p->feat.raw) )
-                p->feat.raw[ctl->input[1]] = leaf;
-        }
+            p->feat.raw[ctl->input[1]] = leaf;
         else if ( ctl->input[0] == XSTATE_CPUID )
-        {
-            if ( ctl->input[1] < ARRAY_SIZE(p->xstate.raw) )
-                p->xstate.raw[ctl->input[1]] = leaf;
-        }
+            p->xstate.raw[ctl->input[1]] = leaf;
         else
             p->basic.raw[ctl->input[0]] = leaf;
-    }
-    else if ( (ctl->input[0] - 0x80000000) < ARRAY_SIZE(p->extd.raw) )
+        break;
+
+    case 0x80000000 ... 0x80000000 + ARRAY_SIZE(p->extd.raw) - 1:
         p->extd.raw[ctl->input[0] - 0x80000000] = leaf;
+        break;
+    }
 
     recalculate_cpuid_policy(d);
 
@@ -243,6 +311,8 @@ static void update_domain_cpuid_info(struct domain *d,
         }
         break;
     }
+
+    return 0;
 }
 
 void arch_get_domain_info(const struct domain *d,
@@ -869,53 +939,15 @@ long arch_do_domctl(
     }
 
     case XEN_DOMCTL_set_cpuid:
-    {
-        const xen_domctl_cpuid_t *ctl = &domctl->u.cpuid;
-        cpuid_input_t *cpuid, *unused = NULL;
-
         if ( d == currd ) /* no domain_pause() */
-        {
             ret = -EINVAL;
-            break;
-        }
-
-        for ( i = 0; i < MAX_CPUID_INPUT; i++ )
-        {
-            cpuid = &d->arch.cpuids[i];
-
-            if ( cpuid->input[0] == XEN_CPUID_INPUT_UNUSED )
-            {
-                if ( !unused )
-                    unused = cpuid;
-                continue;
-            }
-
-            if ( (cpuid->input[0] == ctl->input[0]) &&
-                 ((cpuid->input[1] == XEN_CPUID_INPUT_UNUSED) ||
-                  (cpuid->input[1] == ctl->input[1])) )
-                break;
-        }
-
-        domain_pause(d);
-
-        if ( !(ctl->eax | ctl->ebx | ctl->ecx | ctl->edx) )
+        else
         {
-            if ( i < MAX_CPUID_INPUT )
-                cpuid->input[0] = XEN_CPUID_INPUT_UNUSED;
+            domain_pause(d);
+            ret = update_domain_cpuid_info(d, &domctl->u.cpuid);
+            domain_unpause(d);
         }
-        else if ( i < MAX_CPUID_INPUT )
-            *cpuid = *ctl;
-        else if ( unused )
-            *unused = *ctl;
-        else
-            ret = -ENOENT;
-
-        if ( !ret )
-            update_domain_cpuid_info(d, ctl);
-
-        domain_unpause(d);
         break;
-    }
 
     case XEN_DOMCTL_gettscinfo:
         if ( d == currd ) /* no domain_pause() */
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

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