]> xenbits.xensource.com Git - libvirt.git/commitdiff
cpu_x86: Use signature in CPU detection code
authorJiri Denemark <jdenemar@redhat.com>
Thu, 25 Jun 2015 13:06:19 +0000 (15:06 +0200)
committerJiri Denemark <jdenemar@redhat.com>
Fri, 17 Jun 2016 09:46:31 +0000 (11:46 +0200)
Our current detection code uses just the number of CPU features which
need to be added/removed from the CPU model to fully describe the CPUID
data. The smallest number wins. But this may sometimes generate wrong
results as one can see from the fixed test cases. This patch modifies
the algorithm to prefer the CPU model with matching signature even if
this model results in a longer list of additional features.

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
src/cpu/cpu_map.xml
src/cpu/cpu_x86.c
tests/cputestdata/x86-cpuid-Core-i7-5600U-guest.xml
tests/cputestdata/x86-cpuid-Core2-E6850-guest.xml
tests/cputestdata/x86-cpuid-Core2-E6850-host.xml
tests/cputestdata/x86-cpuid-Xeon-5110-guest.xml
tests/cputestdata/x86-cpuid-Xeon-5110-host.xml
tests/cputestdata/x86-host+penryn-force-result.xml

index 0918f751e643b06f118b90d9e4a2959f95934b57..bf2dfc6a7648b6a6ff158cb795398a20c55813bf 100644 (file)
 
     <!-- Intel CPU models -->
     <model name='Conroe'>
+      <signature family='6' model='15'/>
       <vendor name='Intel'/>
       <feature name='apic'/>
       <feature name='clflush'/>
     </model>
 
     <model name='Penryn'>
+      <signature family='6' model='23'/>
       <vendor name='Intel'/>
       <feature name='apic'/>
       <feature name='clflush'/>
     </model>
 
     <model name='Nehalem'>
+      <signature family='6' model='26'/>
       <vendor name='Intel'/>
       <feature name='apic'/>
       <feature name='clflush'/>
     </model>
 
     <model name='Westmere'>
+      <signature family='6' model='44'/>
       <vendor name='Intel'/>
       <feature name='aes'/>
       <feature name='apic'/>
     </model>
 
     <model name='SandyBridge'>
+      <signature family='6' model='42'/>
       <vendor name='Intel'/>
       <feature name='aes'/>
       <feature name='apic'/>
     </model>
 
     <model name='IvyBridge'>
+      <signature family='6' model='58'/>
       <vendor name='Intel'/>
       <feature name='aes'/>
       <feature name='apic'/>
     </model>
 
     <model name='Haswell-noTSX'>
+      <signature family='6' model='60'/>
       <vendor name='Intel'/>
       <feature name='aes'/>
       <feature name='apic'/>
     </model>
 
     <model name='Haswell'>
+      <signature family='6' model='60'/>
       <vendor name='Intel'/>
       <feature name='aes'/>
       <feature name='apic'/>
     </model>
 
     <model name='Broadwell-noTSX'>
+      <signature family='6' model='61'/>
       <vendor name='Intel'/>
       <feature name='3dnowprefetch'/>
       <feature name='adx'/>
     </model>
 
     <model name='Broadwell'>
+      <signature family='6' model='61'/>
       <vendor name='Intel'/>
       <feature name='3dnowprefetch'/>
       <feature name='adx'/>
     </model>
 
     <model name='Skylake-Client'>
+      <signature family='6' model='94'/>
       <vendor name='Intel'/>
       <feature name='3dnowprefetch'/>
       <feature name='abm'/>
     </model>
 
     <model name='Opteron_G1'>
+      <signature family='15' model='6'/>
       <vendor name='AMD'/>
       <feature name='apic'/>
       <feature name='clflush'/>
     </model>
 
     <model name='Opteron_G2'>
+      <signature family='15' model='6'/>
       <vendor name='AMD'/>
       <feature name='apic'/>
       <feature name='clflush'/>
     </model>
 
     <model name='Opteron_G3'>
+      <signature family='15' model='6'/>
       <vendor name='AMD'/>
       <feature name='abm'/>
       <feature name='apic'/>
     </model>
 
     <model name='Opteron_G4'>
+      <signature family='21' model='1'/>
       <vendor name='AMD'/>
       <feature name='3dnowprefetch'/>
       <feature name='abm'/>
     </model>
 
     <model name='Opteron_G5'>
+      <signature family='21' model='2'/>
       <vendor name='AMD'/>
       <feature name='3dnowprefetch'/>
       <feature name='abm'/>
index 1d0e7a7d7c7e4aca93b9e4659f3edfa8317608f7..d9646eb1c3348702786fd8e6865eed3cb3e8c559 100644 (file)
@@ -135,6 +135,7 @@ typedef virCPUx86Model *virCPUx86ModelPtr;
 struct _virCPUx86Model {
     char *name;
     virCPUx86VendorPtr vendor;
+    uint32_t signature;
     virCPUx86Data data;
 };
 
@@ -493,6 +494,81 @@ x86DataToVendor(const virCPUx86Data *data,
 }
 
 
+static uint32_t
+x86MakeSignature(unsigned int family,
+                 unsigned int model)
+{
+    uint32_t sig = 0;
+
+    /*
+     * CPU signature (eax from 0x1 CPUID leaf):
+     *
+     * |31 .. 28|27 .. 20|19 .. 16|15 .. 14|13 .. 12|11 .. 8|7 .. 4|3 .. 0|
+     * |   R    | extFam | extMod |   R    | PType  |  Fam  | Mod  | Step |
+     *
+     * R        reserved
+     * extFam   extended family (valid only if Fam == 0xf)
+     * extMod   extended model
+     * PType    processor type
+     * Fam      family
+     * Mod      model
+     * Step     stepping
+     *
+     * family = eax[27:20] + eax[11:8]
+     * model = eax[19:16] << 4 + eax[7:4]
+     */
+
+    /* extFam */
+    if (family > 0xf) {
+        sig |= (family - 0xf) << 20;
+        family = 0xf;
+    }
+
+    /* extMod */
+    sig |= (model >> 4) << 16;
+
+    /* PType is always 0 */
+
+    /* Fam */
+    sig |= family << 8;
+
+    /* Mod */
+    sig |= (model & 0xf) << 4;
+
+    /* Step is irrelevant, it is used to distinguish different revisions
+     * of the same CPU model
+     */
+
+    return sig;
+}
+
+
+/* Mask out irrelevant bits (R and Step) from processor signature. */
+#define SIGNATURE_MASK  0x0fff3ff0
+
+static uint32_t
+x86DataToSignature(const virCPUx86Data *data)
+{
+    virCPUx86CPUID leaf1 = { .eax_in = 0x1 };
+    virCPUx86CPUID *cpuid;
+
+    if (!(cpuid = x86DataCpuid(data, &leaf1)))
+        return 0;
+
+    return cpuid->eax & SIGNATURE_MASK;
+}
+
+
+static int
+x86DataAddSignature(virCPUx86Data *data,
+                    uint32_t signature)
+{
+    virCPUx86CPUID cpuid = { .eax_in = 0x1, .eax = signature };
+
+    return virCPUx86DataAddCPUID(data, &cpuid);
+}
+
+
 static virCPUDefPtr
 x86DataToCPU(const virCPUx86Data *data,
              virCPUx86ModelPtr model,
@@ -898,6 +974,7 @@ x86ModelCopy(virCPUx86ModelPtr model)
     }
 
     copy->vendor = model->vendor;
+    copy->signature = model->signature;
 
     return copy;
 }
@@ -1093,6 +1170,30 @@ x86ModelParse(xmlXPathContextPtr ctxt,
             goto error;
     }
 
+    if (virXPathBoolean("boolean(./signature)", ctxt)) {
+        unsigned int sigFamily = 0;
+        unsigned int sigModel = 0;
+        int rc;
+
+        rc = virXPathUInt("string(./signature/@family)", ctxt, &sigFamily);
+        if (rc < 0 || sigFamily == 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Invalid CPU signature family in model %s"),
+                           model->name);
+            goto cleanup;
+        }
+
+        rc = virXPathUInt("string(./signature/@model)", ctxt, &sigModel);
+        if (rc < 0 || sigModel == 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Invalid CPU signature model in model %s"),
+                           model->name);
+            goto cleanup;
+        }
+
+        model->signature = x86MakeSignature(sigFamily, sigModel);
+    }
+
     if (virXPathBoolean("boolean(./vendor)", ctxt)) {
         vendor = virXPathString("string(./vendor/@name)", ctxt);
         if (!vendor) {
@@ -1480,6 +1581,9 @@ x86Compute(virCPUDefPtr host,
                                   &host_model->vendor->cpuid) < 0)
             goto error;
 
+        if (x86DataAddSignature(&guest_model->data, host_model->signature) < 0)
+            goto error;
+
         if (cpu->type == VIR_CPU_TYPE_GUEST
             && cpu->match == VIR_CPU_MATCH_EXACT)
             x86DataSubtract(&guest_model->data, &diff->data);
@@ -1549,16 +1653,19 @@ x86GuestData(virCPUDefPtr host,
 
 
 /*
- * Checks whether cpuCandidate is a better fit for the CPU data than the
- * currently selected one from cpuCurrent.
+ * Checks whether a candidate model is a better fit for the CPU data than the
+ * current model.
  *
- * Returns 0 if cpuCurrent is better,
- *         1 if cpuCandidate is better,
- *         2 if cpuCandidate is the best one (search should stop now).
+ * Returns 0 if current is better,
+ *         1 if candidate is better,
+ *         2 if candidate is the best one (search should stop now).
  */
 static int
-x86DecodeUseCandidate(virCPUDefPtr cpuCurrent,
+x86DecodeUseCandidate(virCPUx86ModelPtr current,
+                      virCPUDefPtr cpuCurrent,
+                      virCPUx86ModelPtr candidate,
                       virCPUDefPtr cpuCandidate,
+                      uint32_t signature,
                       const char *preferred,
                       bool checkPolicy)
 {
@@ -1578,9 +1685,26 @@ x86DecodeUseCandidate(virCPUDefPtr cpuCurrent,
     if (!cpuCurrent)
         return 1;
 
+    /* Ideally we want to select a model with family/model equal to
+     * family/model of the real CPU. Once we found such model, we only
+     * consider candidates with matching family/model.
+     */
+    if (signature &&
+        current->signature == signature &&
+        candidate->signature != signature)
+        return 0;
+
     if (cpuCurrent->nfeatures > cpuCandidate->nfeatures)
         return 1;
 
+    /* Prefer a candidate with matching signature even though it would
+     * result in longer list of features.
+     */
+    if (signature &&
+        candidate->signature == signature &&
+        current->signature != signature)
+        return 1;
+
     return 0;
 }
 
@@ -1597,11 +1721,12 @@ x86Decode(virCPUDefPtr cpu,
     virCPUx86MapPtr map;
     virCPUx86ModelPtr candidate;
     virCPUDefPtr cpuCandidate;
+    virCPUx86ModelPtr model = NULL;
     virCPUDefPtr cpuModel = NULL;
     virCPUx86Data copy = VIR_CPU_X86_DATA_INIT;
     virCPUx86Data features = VIR_CPU_X86_DATA_INIT;
-    const virCPUx86Data *cpuData = NULL;
     virCPUx86VendorPtr vendor;
+    uint32_t signature;
     ssize_t i;
     int rc;
 
@@ -1612,6 +1737,7 @@ x86Decode(virCPUDefPtr cpu,
         return -1;
 
     vendor = x86DataToVendor(data, map);
+    signature = x86DataToSignature(data);
 
     /* Walk through the CPU models in reverse order to check newest
      * models first.
@@ -1650,11 +1776,13 @@ x86Decode(virCPUDefPtr cpu,
             goto cleanup;
         cpuCandidate->type = cpu->type;
 
-        if ((rc = x86DecodeUseCandidate(cpuModel, cpuCandidate, preferred,
+        if ((rc = x86DecodeUseCandidate(model, cpuModel,
+                                        candidate, cpuCandidate,
+                                        signature, preferred,
                                         cpu->type == VIR_CPU_TYPE_HOST))) {
             virCPUDefFree(cpuModel);
             cpuModel = cpuCandidate;
-            cpuData = &candidate->data;
+            model = candidate;
             if (rc == 2)
                 break;
         } else {
@@ -1686,7 +1814,7 @@ x86Decode(virCPUDefPtr cpu,
     }
 
     if (flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) {
-        if (x86DataCopy(&copy, cpuData) < 0 ||
+        if (x86DataCopy(&copy, &model->data) < 0 ||
             x86DataFromCPUFeatures(&features, cpuModel, map) < 0)
             goto cleanup;
 
index 78bc0a64a81fd24c4cabf4e5e37ed2cd697852ae..cd7b4bb8e2fdd45e8543dfc9f39b8311f96fe9d6 100644 (file)
@@ -1,7 +1,8 @@
 <cpu mode='custom' match='exact'>
   <arch>x86_64</arch>
-  <model fallback='forbid'>Skylake-Client</model>
+  <model fallback='forbid'>Broadwell</model>
   <vendor>Intel</vendor>
+  <feature policy='require' name='vme'/>
   <feature policy='require' name='ds'/>
   <feature policy='require' name='acpi'/>
   <feature policy='require' name='ss'/>
   <feature policy='require' name='xtpr'/>
   <feature policy='require' name='pdcm'/>
   <feature policy='require' name='osxsave'/>
+  <feature policy='require' name='f16c'/>
+  <feature policy='require' name='rdrand'/>
+  <feature policy='require' name='arat'/>
   <feature policy='require' name='tsc_adjust'/>
+  <feature policy='require' name='xsaveopt'/>
   <feature policy='require' name='pdpe1gb'/>
+  <feature policy='require' name='abm'/>
   <feature policy='require' name='invtsc'/>
-  <feature policy='disable' name='mpx'/>
-  <feature policy='disable' name='xsavec'/>
-  <feature policy='disable' name='xgetbv1'/>
 </cpu>
index d9df03e6832106eda93f0bb53a9df9bd92e4404b..dfcbe24dad3fd1dbbcfc3fc1783351bd90cd048d 100644 (file)
@@ -1,7 +1,8 @@
 <cpu mode='custom' match='exact'>
   <arch>x86_64</arch>
-  <model fallback='forbid'>core2duo</model>
+  <model fallback='forbid'>Conroe</model>
   <vendor>Intel</vendor>
+  <feature policy='require' name='vme'/>
   <feature policy='require' name='ds'/>
   <feature policy='require' name='acpi'/>
   <feature policy='require' name='ss'/>
@@ -9,6 +10,7 @@
   <feature policy='require' name='tm'/>
   <feature policy='require' name='pbe'/>
   <feature policy='require' name='dtes64'/>
+  <feature policy='require' name='monitor'/>
   <feature policy='require' name='ds_cpl'/>
   <feature policy='require' name='vmx'/>
   <feature policy='require' name='smx'/>
@@ -17,5 +19,4 @@
   <feature policy='require' name='cx16'/>
   <feature policy='require' name='xtpr'/>
   <feature policy='require' name='pdcm'/>
-  <feature policy='require' name='lahf_lm'/>
 </cpu>
index c5ca1cb16c14f2381a7bc22dd7fdd2b5a79f0d56..e7ddc39cebb0409df0f0519570976646b326c3e8 100644 (file)
@@ -1,7 +1,8 @@
 <cpu>
   <arch>x86_64</arch>
-  <model>core2duo</model>
+  <model>Conroe</model>
   <vendor>Intel</vendor>
+  <feature name='vme'/>
   <feature name='ds'/>
   <feature name='acpi'/>
   <feature name='ss'/>
@@ -9,6 +10,7 @@
   <feature name='tm'/>
   <feature name='pbe'/>
   <feature name='dtes64'/>
+  <feature name='monitor'/>
   <feature name='ds_cpl'/>
   <feature name='vmx'/>
   <feature name='smx'/>
@@ -17,5 +19,4 @@
   <feature name='cx16'/>
   <feature name='xtpr'/>
   <feature name='pdcm'/>
-  <feature name='lahf_lm'/>
 </cpu>
index 0b9e3f6cf2f4d62d5a7b588a83ff784f32a296cd..28d112b341e977dcd74e85e521736c9a63c83158 100644 (file)
@@ -1,7 +1,8 @@
 <cpu mode='custom' match='exact'>
   <arch>x86_64</arch>
-  <model fallback='forbid'>core2duo</model>
+  <model fallback='forbid'>Conroe</model>
   <vendor>Intel</vendor>
+  <feature policy='require' name='vme'/>
   <feature policy='require' name='ds'/>
   <feature policy='require' name='acpi'/>
   <feature policy='require' name='ss'/>
@@ -9,6 +10,7 @@
   <feature policy='require' name='tm'/>
   <feature policy='require' name='pbe'/>
   <feature policy='require' name='dtes64'/>
+  <feature policy='require' name='monitor'/>
   <feature policy='require' name='ds_cpl'/>
   <feature policy='require' name='vmx'/>
   <feature policy='require' name='tm2'/>
@@ -16,5 +18,4 @@
   <feature policy='require' name='xtpr'/>
   <feature policy='require' name='pdcm'/>
   <feature policy='require' name='dca'/>
-  <feature policy='require' name='lahf_lm'/>
 </cpu>
index 88c61c40ff380be66c529e516449428caac87ce6..ca3a84cc5ca94cb2dbeb2c53b6988726e04e3324 100644 (file)
@@ -1,7 +1,8 @@
 <cpu>
   <arch>x86_64</arch>
-  <model>core2duo</model>
+  <model>Conroe</model>
   <vendor>Intel</vendor>
+  <feature name='vme'/>
   <feature name='ds'/>
   <feature name='acpi'/>
   <feature name='ss'/>
@@ -9,6 +10,7 @@
   <feature name='tm'/>
   <feature name='pbe'/>
   <feature name='dtes64'/>
+  <feature name='monitor'/>
   <feature name='ds_cpl'/>
   <feature name='vmx'/>
   <feature name='tm2'/>
@@ -16,5 +18,4 @@
   <feature name='xtpr'/>
   <feature name='pdcm'/>
   <feature name='dca'/>
-  <feature name='lahf_lm'/>
 </cpu>
index 000bc0d61bc8b2033e42c7cadab722230e3ef598..ef0a2c0504d65ded53a11c8f591479a364ee4649 100644 (file)
@@ -1,4 +1,6 @@
 <cpu mode='custom' match='exact'>
   <arch>x86_64</arch>
-  <model fallback='allow'>Nehalem</model>
+  <model fallback='allow'>Penryn</model>
+  <feature policy='require' name='sse4.2'/>
+  <feature policy='require' name='popcnt'/>
 </cpu>