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