[libvirt] [PATCH 5/6] Support removing features when converting data to CPU

Jiri Denemark jdenemar at redhat.com
Fri Apr 16 17:01:43 UTC 2010


So far, when CPUID data were converted into CPU model and features, the
features can only be added to the model. As a result, when a guest asked
for something like "qemu64,-svm" it would get a qemu32 plus a bunch of
additional features instead.

This patch adds support for removing feature from the base model.
Selection algorithm remains the same: the best CPU model is the model
which requires lowest number of features to be added/removed from it.
---
 src/cpu/cpu_x86.c    |   71 ++++++++++++++++++++++++++++++++++++-------------
 src/qemu/qemu_conf.c |   12 +++++++-
 2 files changed, 62 insertions(+), 21 deletions(-)

diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index 205528d..014fe7d 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -27,6 +27,7 @@
 
 #include "logging.h"
 #include "memory.h"
+#include "utils.h"
 #include "cpu.h"
 #include "cpu_map.h"
 #include "cpu_x86.h"
@@ -211,6 +212,27 @@ x86DataCopy(const union cpuData *data)
 }
 
 
+static void
+x86DataSubtract(union cpuData *data1,
+                const union cpuData *data2)
+{
+    unsigned int i;
+    unsigned int len;
+
+    len = MIN(data1->x86.basic_len, data2->x86.basic_len);
+    for (i = 0; i < len; i++) {
+        x86cpuidClearBits(data1->x86.basic + i,
+                          data2->x86.basic + i);
+    }
+
+    len = MIN(data1->x86.extended_len, data2->x86.extended_len);
+    for (i = 0; i < len; i++) {
+        x86cpuidClearBits(data1->x86.extended + i,
+                          data2->x86.extended + i);
+    }
+}
+
+
 static union cpuData *
 x86DataFromModel(const struct x86_model *model)
 {
@@ -282,24 +304,28 @@ x86DataToCPU(const union cpuData *data,
              const struct x86_map *map)
 {
     virCPUDefPtr cpu;
-    union cpuData *tmp = NULL;
-    unsigned int i;
+    union cpuData *copy = NULL;
+    union cpuData *modelData = NULL;
 
     if (VIR_ALLOC(cpu) < 0 ||
-        (cpu->model = strdup(model->name)) == NULL ||
-        (tmp = x86DataCopy(data)) == NULL)
+        !(cpu->model = strdup(model->name)) ||
+        !(copy = x86DataCopy(data)) ||
+        !(modelData = x86DataFromModel(model)))
         goto no_memory;
 
-    for (i = 0; i < model->ncpuid; i++) {
-        x86cpuidClearBits(x86DataCpuid(tmp, model->cpuid[i].function),
-                          model->cpuid + i);
-    }
+    x86DataSubtract(copy, modelData);
+    x86DataSubtract(modelData, data);
+
+    /* because feature policy is ignored for host CPU */
+    cpu->type = VIR_CPU_TYPE_GUEST;
 
-    if (x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_REQUIRE, tmp, map))
+    if (x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_REQUIRE, copy, map) ||
+        x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_DISABLE, modelData, map))
         goto error;
 
 cleanup:
-    x86DataFree(tmp);
+    x86DataFree(modelData);
+    x86DataFree(copy);
     return cpu;
 
 no_memory:
@@ -1045,8 +1071,7 @@ x86Decode(virCPUDefPtr cpu,
     const struct x86_model *candidate;
     virCPUDefPtr cpuCandidate;
     virCPUDefPtr cpuModel = NULL;
-    struct cpuX86cpuid *cpuid;
-    int i;
+    unsigned int i;
 
     if (data == NULL || (map = x86LoadMap()) == NULL)
         return -1;
@@ -1055,13 +1080,6 @@ x86Decode(virCPUDefPtr cpu,
     while (candidate != NULL) {
         bool allowed = (models == NULL);
 
-        for (i = 0; i < candidate->ncpuid; i++) {
-            cpuid = x86DataCpuid(data, candidate->cpuid[i].function);
-            if (cpuid == NULL
-                || !x86cpuidMatchMasked(cpuid, candidate->cpuid + i))
-                goto next;
-        }
-
         for (i = 0; i < nmodels; i++) {
             if (models && models[i] && STREQ(models[i], candidate->name)) {
                 allowed = true;
@@ -1078,6 +1096,19 @@ x86Decode(virCPUDefPtr cpu,
         if (!(cpuCandidate = x86DataToCPU(data, candidate, map)))
             goto out;
 
+        if (cpu->type == VIR_CPU_TYPE_HOST) {
+            cpuCandidate->type = VIR_CPU_TYPE_HOST;
+            for (i = 0; i < cpuCandidate->nfeatures; i++) {
+                switch (cpuCandidate->features[i].policy) {
+                case VIR_CPU_FEATURE_DISABLE:
+                    virCPUDefFree(cpuCandidate);
+                    goto next;
+                default:
+                    cpuCandidate->features[i].policy = -1;
+                }
+            }
+        }
+
         if (cpuModel == NULL
             || cpuModel->nfeatures > cpuCandidate->nfeatures) {
             virCPUDefFree(cpuModel);
@@ -1310,6 +1341,8 @@ x86Baseline(virCPUDefPtr *cpus,
     if (VIR_ALLOC(cpu) < 0 ||
         !(cpu->arch = strdup(cpus[0]->arch)))
         goto no_memory;
+    cpu->type = VIR_CPU_TYPE_GUEST;
+    cpu->match = VIR_CPU_MATCH_EXACT;
 
     for (i = 1; i < ncpus; i++) {
         struct x86_model *model;
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 8577ff1..a1392fa 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -3309,12 +3309,20 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver,
         if (VIR_ALLOC(guest) < 0 || !(guest->arch = strdup(ut->machine)))
             goto no_memory;
 
+        guest->type = VIR_CPU_TYPE_GUEST;
         if (cpuDecode(guest, data, cpus, ncpus) < 0)
             goto cleanup;
 
         virBufferVSprintf(&buf, "%s", guest->model);
-        for (i = 0; i < guest->nfeatures; i++)
-            virBufferVSprintf(&buf, ",+%s", guest->features[i].name);
+        for (i = 0; i < guest->nfeatures; i++) {
+            char sign;
+            if (guest->features[i].policy == VIR_CPU_FEATURE_DISABLE)
+                sign = '-';
+            else
+                sign = '+';
+
+            virBufferVSprintf(&buf, ",%c%s", sign, guest->features[i].name);
+        }
     }
     else {
         /*
-- 
1.7.0.4




More information about the libvir-list mailing list