diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index ce75562445..5d101a40ea 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -730,6 +730,36 @@ ignore: } +static virCPUx86Data * +x86DataFromCPUFeatures(virCPUDefPtr cpu, + const struct x86_map *map) +{ + virCPUx86Data *data; + size_t i; + + if (VIR_ALLOC(data) < 0) + return NULL; + + for (i = 0; i < cpu->nfeatures; i++) { + const struct x86_feature *feature; + if (!(feature = x86FeatureFind(map, cpu->features[i].name))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown CPU feature %s"), cpu->features[i].name); + goto error; + } + + if (x86DataAdd(data, feature->data) < 0) + goto error; + } + + return data; + +error: + virCPUx86DataFree(data); + return NULL; +} + + static struct x86_model * x86ModelNew(void) { @@ -1447,35 +1477,6 @@ x86GuestData(virCPUDefPtr host, } -static int -x86AddFeatures(virCPUDefPtr cpu, - const struct x86_map *map) -{ - const struct x86_model *candidate; - const struct x86_feature *feature = map->features; - - candidate = map->models; - while (candidate != NULL) { - if (STREQ(cpu->model, candidate->name)) - break; - candidate = candidate->next; - } - if (!candidate) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("%s not a known CPU model"), cpu->model); - return -1; - } - while (feature != NULL) { - if (x86DataIsSubset(candidate->data, feature->data) && - virCPUDefAddFeature(cpu, feature->name, - VIR_CPU_FEATURE_REQUIRE) < 0) - return -1; - feature = feature->next; - } - return 0; -} - - static int x86Decode(virCPUDefPtr cpu, const virCPUx86Data *data, @@ -1489,6 +1490,9 @@ x86Decode(virCPUDefPtr cpu, const struct x86_model *candidate; virCPUDefPtr cpuCandidate; virCPUDefPtr cpuModel = NULL; + virCPUx86Data *copy = NULL; + virCPUx86Data *features = NULL; + const virCPUx86Data *cpuData = NULL; size_t i; virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1); @@ -1545,6 +1549,7 @@ x86Decode(virCPUDefPtr cpu, if (preferred && STREQ(cpuCandidate->model, preferred)) { virCPUDefFree(cpuModel); cpuModel = cpuCandidate; + cpuData = candidate->data; break; } @@ -1552,8 +1557,10 @@ x86Decode(virCPUDefPtr cpu, || cpuModel->nfeatures > cpuCandidate->nfeatures) { virCPUDefFree(cpuModel); cpuModel = cpuCandidate; - } else + cpuData = candidate->data; + } else { virCPUDefFree(cpuCandidate); + } next: candidate = candidate->next; @@ -1565,9 +1572,17 @@ x86Decode(virCPUDefPtr cpu, goto out; } - if (flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES && - x86AddFeatures(cpuModel, map) < 0) - goto out; + if (flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) { + if (!(copy = x86DataCopy(cpuData)) || + !(features = x86DataFromCPUFeatures(cpuModel, map))) + goto out; + + x86DataSubtract(copy, features); + if (x86DataToCPUFeatures(cpuModel, VIR_CPU_FEATURE_REQUIRE, + copy, map) < 0) + goto out; + } + cpu->model = cpuModel->model; cpu->vendor = cpuModel->vendor; cpu->nfeatures = cpuModel->nfeatures; @@ -1578,7 +1593,8 @@ x86Decode(virCPUDefPtr cpu, out: virCPUDefFree(cpuModel); - + virCPUx86DataFree(copy); + virCPUx86DataFree(features); return ret; }