mirror of https://gitee.com/openkylin/libvirt.git
Support removing features when converting data to CPU
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.
This commit is contained in:
parent
60aef9e467
commit
53c4f9fa1c
src
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "util.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);
|
||||
|
||||
if (x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_REQUIRE, tmp, map))
|
||||
/* because feature policy is ignored for host CPU */
|
||||
cpu->type = VIR_CPU_TYPE_GUEST;
|
||||
|
||||
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;
|
||||
|
|
|
@ -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 {
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue