cpu: Unify CPUID data structures

So far, CPUID data were stored in two different data structures. First
of them was a structure allowing direct access for CPUID data according
to function number and the second was a plain array of struct
cpuX86cpuid. This was a silly design which resulted in converting data
from one type to the other and back again or implementing similar
functionality for both data structures.

The patch leaves only the direct access structure. This makes the code
both smaller and more maintainable since operations on different objects
can use common low-level operations.

All 57 tests for cpu subsystem still pass after this rewrite.
This commit is contained in:
Jiri Denemark 2010-06-30 13:08:57 +02:00
parent 4262ff45e1
commit 8806c0db63
2 changed files with 265 additions and 327 deletions

View File

@ -37,6 +37,7 @@
#define VENDOR_STRING_LENGTH 12
static const struct cpuX86cpuid cpuidNull = { 0, 0, 0, 0, 0 };
static const char *archs[] = { "i686", "x86_64" };
@ -49,8 +50,7 @@ struct x86_vendor {
struct x86_feature {
char *name;
unsigned int ncpuid;
struct cpuX86cpuid *cpuid;
union cpuData *data;
struct x86_feature *next;
};
@ -58,8 +58,7 @@ struct x86_feature {
struct x86_model {
char *name;
const struct x86_vendor *vendor;
unsigned int ncpuid;
struct cpuX86cpuid *cpuid;
union cpuData *data;
struct x86_model *next;
};
@ -79,23 +78,28 @@ enum compare_result {
};
static struct cpuX86cpuid *
x86cpuidFind(struct cpuX86cpuid *cpuids,
unsigned int ncpuids,
uint32_t function)
struct data_iterator {
union cpuData *data;
int pos;
bool extended;
};
#define DATA_ITERATOR_INIT(data) \
{ data, -1, false }
static void
x86DataIteratorInit(struct data_iterator *iter,
union cpuData *data)
{
unsigned int i;
struct data_iterator init = DATA_ITERATOR_INIT(data);
for (i = 0; i < ncpuids; i++) {
if (cpuids[i].function == function)
return cpuids + i;
}
return NULL;
*iter = init;
}
static inline int
static int
x86cpuidMatch(const struct cpuX86cpuid *cpuid1,
const struct cpuX86cpuid *cpuid2)
{
@ -106,7 +110,7 @@ x86cpuidMatch(const struct cpuX86cpuid *cpuid1,
}
static inline int
static int
x86cpuidMatchMasked(const struct cpuX86cpuid *cpuid,
const struct cpuX86cpuid *mask)
{
@ -117,7 +121,7 @@ x86cpuidMatchMasked(const struct cpuX86cpuid *cpuid,
}
static inline int
static int
x86cpuidMatchAny(const struct cpuX86cpuid *cpuid,
const struct cpuX86cpuid *mask)
{
@ -128,7 +132,7 @@ x86cpuidMatchAny(const struct cpuX86cpuid *cpuid,
}
static inline void
static void
x86cpuidSetBits(struct cpuX86cpuid *cpuid,
const struct cpuX86cpuid *mask)
{
@ -139,7 +143,7 @@ x86cpuidSetBits(struct cpuX86cpuid *cpuid,
}
static inline void
static void
x86cpuidClearBits(struct cpuX86cpuid *cpuid,
const struct cpuX86cpuid *mask)
{
@ -150,7 +154,7 @@ x86cpuidClearBits(struct cpuX86cpuid *cpuid,
}
static inline void
static void
x86cpuidAndBits(struct cpuX86cpuid *cpuid,
const struct cpuX86cpuid *mask)
{
@ -161,6 +165,40 @@ x86cpuidAndBits(struct cpuX86cpuid *cpuid,
}
/* skips all zero CPUID leafs */
static struct cpuX86cpuid *
x86DataCpuidNext(struct data_iterator *iterator)
{
struct cpuX86cpuid *ret;
struct cpuX86Data *data;
if (!iterator->data)
return NULL;
data = &iterator->data->x86;
do {
ret = NULL;
iterator->pos++;
if (!iterator->extended) {
if (iterator->pos < data->basic_len)
ret = data->basic + iterator->pos;
else {
iterator->extended = true;
iterator->pos = 0;
}
}
if (iterator->extended && iterator->pos < data->extended_len) {
ret = data->extended + iterator->pos;
}
} while (ret && x86cpuidMatch(ret, &cpuidNull));
return ret;
}
static struct cpuX86cpuid *
x86DataCpuid(const union cpuData *data,
uint32_t function)
@ -180,7 +218,7 @@ x86DataCpuid(const union cpuData *data,
i = function - CPUX86_EXTENDED;
}
if (i < len)
if (i < len && !x86cpuidMatch(cpuids + i, &cpuidNull))
return cpuids + i;
else
return NULL;
@ -224,37 +262,60 @@ x86DataCopy(const union cpuData *data)
}
static int
x86DataExpand(union cpuData *data,
int basic_by,
int extended_by)
{
size_t i;
if (basic_by > 0) {
size_t len = data->x86.basic_len;
if (VIR_EXPAND_N(data->x86.basic, data->x86.basic_len, basic_by) < 0)
goto no_memory;
for (i = 0; i < basic_by; i++)
data->x86.basic[len + i].function = len + i;
}
if (extended_by > 0) {
size_t len = data->x86.extended_len;
if (VIR_EXPAND_N(data->x86.extended, data->x86.extended_len, extended_by) < 0)
goto no_memory;
for (i = 0; i < extended_by; i++)
data->x86.extended[len + i].function = len + i + CPUX86_EXTENDED;
}
return 0;
no_memory:
virReportOOMError();
return -1;
}
static int
x86DataAddCpuid(union cpuData *data,
const struct cpuX86cpuid *cpuid)
{
unsigned int basic_by = 0;
unsigned int extended_by = 0;
struct cpuX86cpuid **cpuids;
int *len;
unsigned int pos;
unsigned int ext;
if (cpuid->function < CPUX86_EXTENDED) {
pos = cpuid->function;
ext = 0;
len = &data->x86.basic_len;
basic_by = pos + 1 - data->x86.basic_len;
cpuids = &data->x86.basic;
} else {
pos = cpuid->function - CPUX86_EXTENDED;
ext = CPUX86_EXTENDED;
len = &data->x86.extended_len;
extended_by = pos + 1 - data->x86.extended_len;
cpuids = &data->x86.extended;
}
if (pos >= *len) {
unsigned int i;
if (VIR_ALLOC_N(*cpuids, pos + 1) < 0)
return -1;
for (i = *len; i <= pos; i++)
(*cpuids)[i].function = i + ext;
*len = pos + 1;
}
if (x86DataExpand(data, basic_by, extended_by) < 0)
return -1;
x86cpuidSetBits((*cpuids) + pos, cpuid);
@ -262,6 +323,31 @@ x86DataAddCpuid(union cpuData *data,
}
static int
x86DataAdd(union cpuData *data1,
const union cpuData *data2)
{
unsigned int i;
if (x86DataExpand(data1,
data2->x86.basic_len - data1->x86.basic_len,
data2->x86.extended_len - data1->x86.extended_len) < 0)
return -1;
for (i = 0; i < data2->x86.basic_len; i++) {
x86cpuidSetBits(data1->x86.basic + i,
data2->x86.basic + i);
}
for (i = 0; i < data2->x86.extended_len; i++) {
x86cpuidSetBits(data1->x86.extended + i,
data2->x86.extended + i);
}
return 0;
}
static void
x86DataSubtract(union cpuData *data1,
const union cpuData *data2)
@ -283,19 +369,45 @@ x86DataSubtract(union cpuData *data1,
}
static void
x86DataIntersect(union cpuData *data1,
const union cpuData *data2)
{
struct data_iterator iter = DATA_ITERATOR_INIT(data1);
struct cpuX86cpuid *cpuid1;
struct cpuX86cpuid *cpuid2;
while ((cpuid1 = x86DataCpuidNext(&iter))) {
cpuid2 = x86DataCpuid(data2, cpuid1->function);
if (cpuid2)
x86cpuidAndBits(cpuid1, cpuid2);
else
x86cpuidClearBits(cpuid1, cpuid1);
}
}
static bool
x86DataIsEmpty(union cpuData *data)
{
struct cpuX86cpuid zero = { 0, 0, 0, 0, 0 };
unsigned int i;
struct data_iterator iter = DATA_ITERATOR_INIT(data);
for (i = 0; i < data->x86.basic_len; i++) {
if (!x86cpuidMatch(data->x86.basic + i, &zero))
return false;
}
return (x86DataCpuidNext(&iter) == NULL);
}
for (i = 0; i < data->x86.extended_len; i++) {
if (!x86cpuidMatch(data->x86.extended + i, &zero))
static bool
x86DataIsSubset(const union cpuData *data,
const union cpuData *subset)
{
struct data_iterator iter = DATA_ITERATOR_INIT((union cpuData *) subset);
const struct cpuX86cpuid *cpuid;
const struct cpuX86cpuid *cpuidSubset;
while ((cpuidSubset = x86DataCpuidNext(&iter))) {
if (!(cpuid = x86DataCpuid(data, cpuidSubset->function)) ||
!x86cpuidMatchMasked(cpuid, cpuidSubset))
return false;
}
@ -303,44 +415,6 @@ x86DataIsEmpty(union cpuData *data)
}
static union cpuData *
x86DataFromModel(const struct x86_model *model)
{
union cpuData *data = NULL;
uint32_t basic_len = 0;
uint32_t extended_len = 0;
struct cpuX86cpuid *cpuid;
int i;
for (i = 0; i < model->ncpuid; i++) {
cpuid = model->cpuid + i;
if (cpuid->function < CPUX86_EXTENDED) {
if (cpuid->function >= basic_len)
basic_len = cpuid->function + 1;
}
else if (cpuid->function - CPUX86_EXTENDED >= extended_len)
extended_len = cpuid->function - CPUX86_EXTENDED + 1;
}
if (VIR_ALLOC(data) < 0
|| VIR_ALLOC_N(data->x86.basic, basic_len) < 0
|| VIR_ALLOC_N(data->x86.extended, extended_len) < 0) {
x86DataFree(data);
return NULL;
}
data->x86.basic_len = basic_len;
data->x86.extended_len = extended_len;
for (i = 0; i < model->ncpuid; i++) {
cpuid = x86DataCpuid(data, model->cpuid[i].function);
*cpuid = model->cpuid[i];
}
return data;
}
/* also removes all detected features from data */
static int
x86DataToCPUFeatures(virCPUDefPtr cpu,
@ -349,17 +423,12 @@ x86DataToCPUFeatures(virCPUDefPtr cpu,
const struct x86_map *map)
{
const struct x86_feature *feature = map->features;
struct cpuX86cpuid *cpuid;
unsigned int i;
while (feature != NULL) {
for (i = 0; i < feature->ncpuid; i++) {
if ((cpuid = x86DataCpuid(data, feature->cpuid[i].function))
&& x86cpuidMatchMasked(cpuid, feature->cpuid + i)) {
x86cpuidClearBits(cpuid, feature->cpuid + i);
if (virCPUDefAddFeature(cpu, feature->name, policy) < 0)
return -1;
}
if (x86DataIsSubset(data, feature->data)) {
x86DataSubtract(data, feature->data);
if (virCPUDefAddFeature(cpu, feature->name, policy) < 0)
return -1;
}
feature = feature->next;
}
@ -402,7 +471,7 @@ x86DataToCPU(const union cpuData *data,
if (VIR_ALLOC(cpu) < 0 ||
!(cpu->model = strdup(model->name)) ||
!(copy = x86DataCopy(data)) ||
!(modelData = x86DataFromModel(model)))
!(modelData = x86DataCopy(model->data)))
goto no_memory;
if ((vendor = x86DataToVendor(copy, map)) &&
@ -441,7 +510,7 @@ x86VendorFree(struct x86_vendor *vendor)
VIR_FREE(vendor->name);
VIR_FREE(vendor);
};
}
static struct x86_vendor *
@ -533,6 +602,23 @@ ignore:
}
static struct x86_feature *
x86FeatureNew(void)
{
struct x86_feature *feature;
if (VIR_ALLOC(feature) < 0)
return NULL;
if (VIR_ALLOC(feature->data) < 0) {
VIR_FREE(feature);
return NULL;
}
return feature;
}
static void
x86FeatureFree(struct x86_feature *feature)
{
@ -540,7 +626,7 @@ x86FeatureFree(struct x86_feature *feature)
return;
VIR_FREE(feature->name);
VIR_FREE(feature->cpuid);
x86DataFree(feature->data);
VIR_FREE(feature);
}
@ -569,12 +655,12 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
{
xmlNodePtr *nodes = NULL;
xmlNodePtr ctxt_node = ctxt->node;
struct x86_feature *feature = NULL;
struct x86_feature *feature;
int ret = 0;
int i;
int n;
if (VIR_ALLOC(feature) < 0)
if (!(feature = x86FeatureNew()))
goto no_memory;
feature->name = virXPathString("string(@name)", ctxt);
@ -594,14 +680,8 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
if (n < 0)
goto ignore;
if (n > 0) {
if (VIR_ALLOC_N(feature->cpuid, n) < 0)
goto no_memory;
feature->ncpuid = n;
}
for (i = 0; i < n; i++) {
struct cpuX86cpuid *cpuid = feature->cpuid + i;
struct cpuX86cpuid cpuid;
unsigned long fun, eax, ebx, ecx, edx;
int ret_fun, ret_eax, ret_ebx, ret_ecx, ret_edx;
@ -620,11 +700,14 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
goto ignore;
}
cpuid->function = fun;
cpuid->eax = eax;
cpuid->ebx = ebx;
cpuid->ecx = ecx;
cpuid->edx = edx;
cpuid.function = fun;
cpuid.eax = eax;
cpuid.ebx = ebx;
cpuid.ecx = ecx;
cpuid.edx = edx;
if (x86DataAddCpuid(feature->data, &cpuid))
goto no_memory;
}
if (map->features == NULL)
@ -650,6 +733,23 @@ ignore:
}
static struct x86_model *
x86ModelNew(void)
{
struct x86_model *model;
if (VIR_ALLOC(model) < 0)
return NULL;
if (VIR_ALLOC(model->data) < 0) {
VIR_FREE(model);
return NULL;
}
return model;
}
static void
x86ModelFree(struct x86_model *model)
{
@ -657,7 +757,7 @@ x86ModelFree(struct x86_model *model)
return;
VIR_FREE(model->name);
VIR_FREE(model->cpuid);
x86DataFree(model->data);
VIR_FREE(model);
}
@ -666,99 +766,20 @@ static struct x86_model *
x86ModelCopy(const struct x86_model *model)
{
struct x86_model *copy;
int i;
if (VIR_ALLOC(copy) < 0
|| (copy->name = strdup(model->name)) == NULL
|| VIR_ALLOC_N(copy->cpuid, model->ncpuid) < 0) {
|| !(copy->name = strdup(model->name))
|| !(copy->data = x86DataCopy(model->data))) {
x86ModelFree(copy);
return NULL;
}
copy->vendor = model->vendor;
copy->ncpuid = model->ncpuid;
for (i = 0; i < model->ncpuid; i++)
copy->cpuid[i] = model->cpuid[i];
return copy;
}
static int
x86ModelAddCpuid(struct x86_model *model,
const struct cpuX86cpuid *cpuid)
{
struct cpuX86cpuid *model_cpuid;
model_cpuid = x86cpuidFind(model->cpuid, model->ncpuid, cpuid->function);
if (model_cpuid != NULL)
x86cpuidSetBits(model_cpuid, cpuid);
else {
if (VIR_REALLOC_N(model->cpuid, model->ncpuid + 1) < 0)
return -1;
model->cpuid[model->ncpuid] = *cpuid;
model->ncpuid++;
}
return 0;
}
static void
x86ModelSubtract(struct x86_model *model1,
const struct x86_model *model2)
{
int i;
struct cpuX86cpuid *cpuid;
for (i = 0; i < model2->ncpuid; i++) {
cpuid = x86cpuidFind(model1->cpuid,
model1->ncpuid,
model2->cpuid[i].function);
if (cpuid != NULL)
x86cpuidClearBits(cpuid, model2->cpuid + i);
}
}
static void
x86ModelIntersect(struct x86_model *model1,
const struct x86_model *model2)
{
int i;
struct cpuX86cpuid *cpuid;
for (i = 0; i < model1->ncpuid; i++) {
struct cpuX86cpuid *intersection = model1->cpuid + i;
cpuid = x86cpuidFind(model2->cpuid,
model2->ncpuid,
intersection->function);
if (cpuid != NULL)
x86cpuidAndBits(intersection, cpuid);
else
x86cpuidClearBits(intersection, intersection);
}
}
static int
x86ModelAdd(struct x86_model *model1,
const struct x86_model *model2)
{
int i;
for (i = 0; i < model2->ncpuid; i++) {
if (x86ModelAddCpuid(model1, model2->cpuid + i))
return -1;
}
return 0;
}
static struct x86_model *
x86ModelFind(const struct x86_map *map,
const char *name)
@ -777,47 +798,6 @@ x86ModelFind(const struct x86_map *map,
}
static int
x86ModelMergeFeature(struct x86_model *model,
const struct x86_feature *feature)
{
int i;
if (feature == NULL)
return 0;
for (i = 0; i < feature->ncpuid; i++) {
if (x86ModelAddCpuid(model, feature->cpuid + i))
return -1;
}
return 0;
}
static bool
x86ModelHasFeature(struct x86_model *model,
const struct x86_feature *feature)
{
unsigned int i;
struct cpuX86cpuid *cpuid;
struct cpuX86cpuid *model_cpuid;
if (feature == NULL)
return false;
for (i = 0; i < feature->ncpuid; i++) {
cpuid = feature->cpuid + i;
model_cpuid = x86cpuidFind(model->cpuid, model->ncpuid,
cpuid->function);
if (!model_cpuid || !x86cpuidMatchMasked(model_cpuid, cpuid))
return false;
}
return true;
}
static struct x86_model *
x86ModelFromCPU(const virCPUDefPtr cpu,
const struct x86_map *map,
@ -835,11 +815,11 @@ x86ModelFromCPU(const virCPUDefPtr cpu,
if ((model = x86ModelCopy(model)) == NULL)
goto no_memory;
}
else if (VIR_ALLOC(model) < 0)
} else if (!(model = x86ModelNew())) {
goto no_memory;
else if (cpu->type == VIR_CPU_TYPE_HOST)
} else if (cpu->type == VIR_CPU_TYPE_HOST) {
return model;
}
for (i = 0; i < cpu->nfeatures; i++) {
const struct x86_feature *feature;
@ -854,7 +834,7 @@ x86ModelFromCPU(const virCPUDefPtr cpu,
goto error;
}
if (x86ModelMergeFeature(model, feature))
if (x86DataAdd(model->data, feature->data))
goto no_memory;
}
@ -884,11 +864,10 @@ x86ModelSubtractCPU(struct x86_model *model,
return -1;
}
x86ModelSubtract(model, cpu_model);
x86DataSubtract(model->data, cpu_model->data);
for (i = 0; i < cpu->nfeatures; i++) {
const struct x86_feature *feature;
unsigned int j;
if (!(feature = x86FeatureFind(map, cpu->features[i].name))) {
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
@ -897,13 +876,7 @@ x86ModelSubtractCPU(struct x86_model *model,
return -1;
}
for (j = 0; j < feature->ncpuid; j++) {
struct cpuX86cpuid *cpuid;
cpuid = x86cpuidFind(model->cpuid, model->ncpuid,
feature->cpuid[j].function);
if (cpuid)
x86cpuidClearBits(cpuid, feature->cpuid + j);
}
x86DataSubtract(model->data, feature->data);
}
return 0;
@ -915,18 +888,15 @@ x86ModelCompare(const struct x86_model *model1,
const struct x86_model *model2)
{
enum compare_result result = EQUAL;
struct data_iterator iter1 = DATA_ITERATOR_INIT(model1->data);
struct data_iterator iter2 = DATA_ITERATOR_INIT(model2->data);
struct cpuX86cpuid *cpuid1;
struct cpuX86cpuid *cpuid2;
int i;
for (i = 0; i < model1->ncpuid; i++) {
while ((cpuid1 = x86DataCpuidNext(&iter1))) {
enum compare_result match = SUPERSET;
cpuid1 = model1->cpuid + i;
cpuid2 = x86cpuidFind(model2->cpuid,
model2->ncpuid,
cpuid1->function);
if (cpuid2 != NULL) {
if ((cpuid2 = x86DataCpuid(model2->data, cpuid1->function))) {
if (x86cpuidMatch(cpuid1, cpuid2))
continue;
else if (!x86cpuidMatchMasked(cpuid1, cpuid2))
@ -939,14 +909,10 @@ x86ModelCompare(const struct x86_model *model1,
return UNRELATED;
}
for (i = 0; i < model2->ncpuid; i++) {
while ((cpuid2 = x86DataCpuidNext(&iter2))) {
enum compare_result match = SUBSET;
cpuid2 = model2->cpuid + i;
cpuid1 = x86cpuidFind(model1->cpuid,
model1->ncpuid,
cpuid2->function);
if (cpuid1 != NULL) {
if ((cpuid1 = x86DataCpuid(model1->data, cpuid2->function))) {
if (x86cpuidMatch(cpuid2, cpuid1))
continue;
else if (!x86cpuidMatchMasked(cpuid2, cpuid1))
@ -968,13 +934,13 @@ x86ModelLoad(xmlXPathContextPtr ctxt,
struct x86_map *map)
{
xmlNodePtr *nodes = NULL;
struct x86_model *model = NULL;
struct x86_model *model;
char *vendor = NULL;
int ret = 0;
int i;
int n;
if (VIR_ALLOC(model) < 0)
if (!(model = x86ModelNew()))
goto no_memory;
model->name = virXPathString("string(@name)", ctxt);
@ -1006,13 +972,9 @@ x86ModelLoad(xmlXPathContextPtr ctxt,
VIR_FREE(name);
if (VIR_ALLOC_N(model->cpuid, ancestor->ncpuid) < 0)
goto no_memory;
model->vendor = ancestor->vendor;
model->ncpuid = ancestor->ncpuid;
memcpy(model->cpuid, ancestor->cpuid,
sizeof(*model->cpuid) * model->ncpuid);
if (!(model->data = x86DataCopy(ancestor->data)))
goto no_memory;
}
if (virXPathBoolean("boolean(./vendor)", ctxt)) {
@ -1055,7 +1017,7 @@ x86ModelLoad(xmlXPathContextPtr ctxt,
}
VIR_FREE(name);
if (x86ModelMergeFeature(model, feature))
if (x86DataAdd(model->data, feature->data))
goto no_memory;
}
@ -1157,7 +1119,6 @@ x86Compute(virCPUDefPtr host,
virCPUDefPtr cpu,
union cpuData **guest)
{
struct cpuX86cpuid cpuid_zero = { 0, 0, 0, 0, 0 };
struct x86_map *map = NULL;
struct x86_model *host_model = NULL;
struct x86_model *cpu_force = NULL;
@ -1167,6 +1128,8 @@ x86Compute(virCPUDefPtr host,
struct x86_model *cpu_forbid = NULL;
struct x86_model *diff = NULL;
struct x86_model *guest_model = NULL;
struct data_iterator iter;
const struct cpuX86cpuid *cpuid;
virCPUCompareResult ret;
enum compare_result result;
unsigned int i;
@ -1203,24 +1166,20 @@ x86Compute(virCPUDefPtr host,
!(cpu_forbid = x86ModelFromCPU(cpu, map, VIR_CPU_FEATURE_FORBID)))
goto error;
for (i = 0; i < cpu_forbid->ncpuid; i++) {
const struct cpuX86cpuid *cpuid1;
x86DataIteratorInit(&iter, cpu_forbid->data);
while ((cpuid = x86DataCpuidNext(&iter))) {
const struct cpuX86cpuid *cpuid2;
cpuid1 = cpu_forbid->cpuid + i;
cpuid2 = x86cpuidFind(host_model->cpuid,
host_model->ncpuid,
cpuid1->function);
if (cpuid2 != NULL && x86cpuidMatchAny(cpuid2, cpuid1)) {
cpuid2 = x86DataCpuid(host_model->data, cpuid->function);
if (cpuid2 != NULL && x86cpuidMatchAny(cpuid2, cpuid)) {
VIR_DEBUG("Host CPU provides forbidden features in CPUID function 0x%x",
cpuid1->function);
cpuid->function);
ret = VIR_CPU_COMPARE_INCOMPATIBLE;
goto out;
}
}
x86ModelSubtract(cpu_require, cpu_disable);
x86DataSubtract(cpu_require->data, cpu_disable->data);
result = x86ModelCompare(host_model, cpu_require);
if (result == SUBSET || result == UNRELATED) {
VIR_DEBUG0("Host CPU does not provide all required features");
@ -1233,17 +1192,13 @@ x86Compute(virCPUDefPtr host,
if ((diff = x86ModelCopy(host_model)) == NULL)
goto no_memory;
x86ModelSubtract(diff, cpu_optional);
x86ModelSubtract(diff, cpu_require);
x86ModelSubtract(diff, cpu_disable);
x86ModelSubtract(diff, cpu_force);
x86DataSubtract(diff->data, cpu_optional->data);
x86DataSubtract(diff->data, cpu_require->data);
x86DataSubtract(diff->data, cpu_disable->data);
x86DataSubtract(diff->data, cpu_force->data);
for (i = 0; i < diff->ncpuid; i++) {
if (!x86cpuidMatch(diff->cpuid + i, &cpuid_zero)) {
ret = VIR_CPU_COMPARE_SUPERSET;
break;
}
}
if (!x86DataIsEmpty(diff->data))
ret = VIR_CPU_COMPARE_SUPERSET;
if (ret == VIR_CPU_COMPARE_SUPERSET
&& cpu->type == VIR_CPU_TYPE_GUEST
@ -1259,14 +1214,14 @@ x86Compute(virCPUDefPtr host,
if (cpu->type == VIR_CPU_TYPE_GUEST
&& cpu->match == VIR_CPU_MATCH_EXACT)
x86ModelSubtract(guest_model, diff);
x86DataSubtract(guest_model->data, diff->data);
if (x86ModelAdd(guest_model, cpu_force))
if (x86DataAdd(guest_model->data, cpu_force->data))
goto no_memory;
x86ModelSubtract(guest_model, cpu_disable);
x86DataSubtract(guest_model->data, cpu_disable->data);
if ((*guest = x86DataFromModel(guest_model)) == NULL)
if ((*guest = x86DataCopy(guest_model->data)) == NULL)
goto no_memory;
}
@ -1418,9 +1373,8 @@ x86EncodePolicy(const virCPUDefPtr cpu,
if (!(model = x86ModelFromCPU(cpu, map, policy)))
return NULL;
if (!(data = x86DataFromModel(model)))
virReportOOMError();
data = model->data;
model->data = NULL;
x86ModelFree(model);
return data;
@ -1584,19 +1538,20 @@ static union cpuData *
x86NodeData(void)
{
union cpuData *data;
int ret;
if (VIR_ALLOC(data) < 0) {
virReportOOMError();
return NULL;
}
data->x86.basic_len = cpuidSet(CPUX86_BASIC, &data->x86.basic);
if (data->x86.basic_len < 0)
if ((ret = cpuidSet(CPUX86_BASIC, &data->x86.basic)) < 0)
goto error;
data->x86.basic_len = ret;
data->x86.extended_len = cpuidSet(CPUX86_EXTENDED, &data->x86.extended);
if (data->x86.extended_len < 0)
if ((ret = cpuidSet(CPUX86_EXTENDED, &data->x86.extended)) < 0)
goto error;
data->x86.extended_len = ret;
return data;
@ -1616,7 +1571,6 @@ x86Baseline(virCPUDefPtr *cpus,
{
struct x86_map *map = NULL;
struct x86_model *base_model = NULL;
union cpuData *data = NULL;
virCPUDefPtr cpu = NULL;
unsigned int i;
const struct x86_vendor *vendor = NULL;
@ -1679,24 +1633,21 @@ x86Baseline(virCPUDefPtr *cpus,
}
}
x86ModelIntersect(base_model, model);
x86DataIntersect(base_model->data, model->data);
x86ModelFree(model);
model = NULL;
}
if (!(data = x86DataFromModel(base_model)))
goto no_memory;
if (x86DataIsEmpty(data)) {
if (x86DataIsEmpty(base_model->data)) {
virCPUReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("CPUs are incompatible"));
goto error;
}
if (vendor && x86DataAddCpuid(data, &vendor->cpuid) < 0)
if (vendor && x86DataAddCpuid(base_model->data, &vendor->cpuid) < 0)
goto no_memory;
if (x86Decode(cpu, data, models, nmodels, NULL) < 0)
if (x86Decode(cpu, base_model->data, models, nmodels, NULL) < 0)
goto error;
if (!outputVendor)
@ -1705,7 +1656,6 @@ x86Baseline(virCPUDefPtr *cpus,
VIR_FREE(cpu->arch);
cleanup:
x86DataFree(data);
x86ModelFree(base_model);
x86MapFree(map);
@ -1729,7 +1679,6 @@ x86Update(virCPUDefPtr guest,
unsigned int i;
struct x86_map *map;
struct x86_model *host_model = NULL;
union cpuData *data = NULL;
if (!(map = x86LoadMap()) ||
!(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)))
@ -1745,7 +1694,7 @@ x86Update(virCPUDefPtr guest,
goto cleanup;
}
if (x86ModelHasFeature(host_model, feature))
if (x86DataIsSubset(host_model->data, feature->data))
guest->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
else
guest->features[i].policy = VIR_CPU_FEATURE_DISABLE;
@ -1755,8 +1704,8 @@ x86Update(virCPUDefPtr guest,
if (guest->match == VIR_CPU_MATCH_MINIMUM) {
guest->match = VIR_CPU_MATCH_EXACT;
if (x86ModelSubtractCPU(host_model, guest, map)
|| !(data = x86DataFromModel(host_model))
|| x86DataToCPUFeatures(guest, VIR_CPU_FEATURE_REQUIRE, data, map))
|| x86DataToCPUFeatures(guest, VIR_CPU_FEATURE_REQUIRE,
host_model->data, map))
goto cleanup;
}
@ -1765,7 +1714,6 @@ x86Update(virCPUDefPtr guest,
cleanup:
x86MapFree(map);
x86ModelFree(host_model);
x86DataFree(data);
return ret;
}
@ -1775,7 +1723,6 @@ static int x86HasFeature(const union cpuData *data,
struct x86_map *map;
struct x86_feature *feature;
int ret = -1;
int i;
if (!(map = x86LoadMap()))
return -1;
@ -1783,16 +1730,7 @@ static int x86HasFeature(const union cpuData *data,
if (!(feature = x86FeatureFind(map, name)))
goto cleanup;
for (i = 0 ; i < feature->ncpuid ; i++) {
struct cpuX86cpuid *cpuid;
cpuid = x86DataCpuid(data, feature->cpuid[i].function);
if (cpuid && x86cpuidMatchMasked(cpuid, feature->cpuid + i)) {
ret = 1;
goto cleanup;
}
}
ret = 0;
ret = x86DataIsSubset(data, feature->data) ? 1 : 0;
cleanup:
x86MapFree(map);

View File

@ -38,9 +38,9 @@ struct cpuX86cpuid {
# define CPUX86_EXTENDED 0x80000000
struct cpuX86Data {
int basic_len;
size_t basic_len;
struct cpuX86cpuid *basic;
int extended_len;
size_t extended_len;
struct cpuX86cpuid *extended;
};