cpu_x86.c 52.9 KB
Newer Older
J
Jiri Denemark 已提交
1 2 3
/*
 * cpu_x86.c: CPU driver for CPUs with x86 compatible CPUID instruction
 *
E
Eric Blake 已提交
4
 * Copyright (C) 2009-2011, 2013 Red Hat, Inc.
J
Jiri Denemark 已提交
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
J
Jiri Denemark 已提交
19 20 21 22 23 24 25 26 27
 *
 * Authors:
 *      Jiri Denemark <jdenemar@redhat.com>
 */

#include <config.h>

#include <stdint.h>

28
#include "virlog.h"
29
#include "viralloc.h"
J
Jiri Denemark 已提交
30 31 32
#include "cpu.h"
#include "cpu_map.h"
#include "cpu_x86.h"
33
#include "virbuffer.h"
E
Eric Blake 已提交
34
#include "virendian.h"
35
#include "virstring.h"
J
Jiri Denemark 已提交
36 37 38

#define VIR_FROM_THIS VIR_FROM_CPU

39 40
VIR_LOG_INIT("cpu.cpu_x86");

J
Jiri Denemark 已提交
41 42
#define VENDOR_STRING_LENGTH    12

43
static const virCPUx86CPUID cpuidNull = { 0, 0, 0, 0, 0 };
J
Jiri Denemark 已提交
44

45
static const virArch archs[] = { VIR_ARCH_I686, VIR_ARCH_X86_64 };
J
Jiri Denemark 已提交
46

J
Jiri Denemark 已提交
47 48
struct x86_vendor {
    char *name;
49
    virCPUx86CPUID cpuid;
J
Jiri Denemark 已提交
50 51 52 53

    struct x86_vendor *next;
};

J
Jiri Denemark 已提交
54 55
struct x86_feature {
    char *name;
56
    virCPUx86Data *data;
J
Jiri Denemark 已提交
57 58 59 60

    struct x86_feature *next;
};

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
struct x86_kvm_feature {
    const char *name;
    const virCPUx86CPUID cpuid;
};

static const struct x86_kvm_feature x86_kvm_features[] =
{
    {VIR_CPU_x86_KVM_CLOCKSOURCE,  { .function = 0x40000001, .eax = 0x00000001 }},
    {VIR_CPU_x86_KVM_NOP_IO_DELAY, { .function = 0x40000001, .eax = 0x00000002 }},
    {VIR_CPU_x86_KVM_MMU_OP,       { .function = 0x40000001, .eax = 0x00000004 }},
    {VIR_CPU_x86_KVM_CLOCKSOURCE2, { .function = 0x40000001, .eax = 0x00000008 }},
    {VIR_CPU_x86_KVM_ASYNC_PF,     { .function = 0x40000001, .eax = 0x00000010 }},
    {VIR_CPU_x86_KVM_STEAL_TIME,   { .function = 0x40000001, .eax = 0x00000020 }},
    {VIR_CPU_x86_KVM_PV_EOI,       { .function = 0x40000001, .eax = 0x00000040 }},
    {VIR_CPU_x86_KVM_PV_UNHALT,    { .function = 0x40000001, .eax = 0x00000080 }},
    {VIR_CPU_x86_KVM_CLOCKSOURCE_STABLE_BIT,
                                   { .function = 0x40000001, .eax = 0x01000000 }},
};

J
Jiri Denemark 已提交
80 81
struct x86_model {
    char *name;
J
Jiri Denemark 已提交
82
    const struct x86_vendor *vendor;
83
    virCPUx86Data *data;
J
Jiri Denemark 已提交
84 85 86 87 88

    struct x86_model *next;
};

struct x86_map {
J
Jiri Denemark 已提交
89
    struct x86_vendor *vendors;
J
Jiri Denemark 已提交
90 91 92 93
    struct x86_feature *features;
    struct x86_model *models;
};

94 95 96 97
static struct x86_map* virCPUx86Map = NULL;
int virCPUx86MapOnceInit(void);
VIR_ONCE_GLOBAL_INIT(virCPUx86Map);

J
Jiri Denemark 已提交
98 99 100 101 102 103 104 105 106

enum compare_result {
    SUBSET,
    EQUAL,
    SUPERSET,
    UNRELATED
};


107
struct virCPUx86DataIterator {
108
    const virCPUx86Data *data;
J
Jiri Denemark 已提交
109 110
    int pos;
};
J
Jiri Denemark 已提交
111 112


113
#define virCPUx86DataIteratorInit(data) \
114
    { data, -1 }
J
Jiri Denemark 已提交
115 116


117
static bool
118 119
x86cpuidMatch(const virCPUx86CPUID *cpuid1,
              const virCPUx86CPUID *cpuid2)
J
Jiri Denemark 已提交
120 121 122 123 124 125 126 127
{
    return (cpuid1->eax == cpuid2->eax &&
            cpuid1->ebx == cpuid2->ebx &&
            cpuid1->ecx == cpuid2->ecx &&
            cpuid1->edx == cpuid2->edx);
}


128
static bool
129 130
x86cpuidMatchMasked(const virCPUx86CPUID *cpuid,
                    const virCPUx86CPUID *mask)
J
Jiri Denemark 已提交
131 132 133 134 135 136 137 138
{
    return ((cpuid->eax & mask->eax) == mask->eax &&
            (cpuid->ebx & mask->ebx) == mask->ebx &&
            (cpuid->ecx & mask->ecx) == mask->ecx &&
            (cpuid->edx & mask->edx) == mask->edx);
}


J
Jiri Denemark 已提交
139
static void
140 141
x86cpuidSetBits(virCPUx86CPUID *cpuid,
                const virCPUx86CPUID *mask)
J
Jiri Denemark 已提交
142
{
143 144 145
    if (!mask)
        return;

J
Jiri Denemark 已提交
146 147 148 149 150 151 152
    cpuid->eax |= mask->eax;
    cpuid->ebx |= mask->ebx;
    cpuid->ecx |= mask->ecx;
    cpuid->edx |= mask->edx;
}


J
Jiri Denemark 已提交
153
static void
154 155
x86cpuidClearBits(virCPUx86CPUID *cpuid,
                  const virCPUx86CPUID *mask)
J
Jiri Denemark 已提交
156
{
157 158 159
    if (!mask)
        return;

J
Jiri Denemark 已提交
160 161 162 163 164 165 166
    cpuid->eax &= ~mask->eax;
    cpuid->ebx &= ~mask->ebx;
    cpuid->ecx &= ~mask->ecx;
    cpuid->edx &= ~mask->edx;
}


J
Jiri Denemark 已提交
167
static void
168 169
x86cpuidAndBits(virCPUx86CPUID *cpuid,
                const virCPUx86CPUID *mask)
170
{
171 172 173
    if (!mask)
        return;

174 175 176 177 178 179
    cpuid->eax &= mask->eax;
    cpuid->ebx &= mask->ebx;
    cpuid->ecx &= mask->ecx;
    cpuid->edx &= mask->edx;
}

180 181 182 183 184 185 186 187 188 189 190 191 192 193
static int
virCPUx86CPUIDSorter(const void *a, const void *b)
{
    virCPUx86CPUID *da = (virCPUx86CPUID *) a;
    virCPUx86CPUID *db = (virCPUx86CPUID *) b;

    if (da->function > db->function)
        return 1;
    else if (da->function < db->function)
        return -1;

    return 0;
}

194

J
Jiri Denemark 已提交
195
/* skips all zero CPUID leafs */
196
static virCPUx86CPUID *
197
x86DataCpuidNext(struct virCPUx86DataIterator *iterator)
J
Jiri Denemark 已提交
198
{
199
    const virCPUx86Data *data = iterator->data;
J
Jiri Denemark 已提交
200

201
    if (!data)
J
Jiri Denemark 已提交
202 203
        return NULL;

204 205 206 207
    while (++iterator->pos < data->len) {
        if (!x86cpuidMatch(data->data + iterator->pos, &cpuidNull))
            return data->data + iterator->pos;
    }
J
Jiri Denemark 已提交
208

209
    return NULL;
J
Jiri Denemark 已提交
210 211 212
}


213
static virCPUx86CPUID *
214
x86DataCpuid(const virCPUx86Data *data,
J
Jiri Denemark 已提交
215 216
             uint32_t function)
{
217
    size_t i;
J
Jiri Denemark 已提交
218

219 220 221
    for (i = 0; i < data->len; i++) {
        if (data->data[i].function == function)
            return data->data + i;
J
Jiri Denemark 已提交
222 223
    }

224
    return NULL;
J
Jiri Denemark 已提交
225 226
}

J
Jiri Denemark 已提交
227
void
228
virCPUx86DataFree(virCPUx86Data *data)
J
Jiri Denemark 已提交
229 230 231 232
{
    if (data == NULL)
        return;

233
    VIR_FREE(data->data);
J
Jiri Denemark 已提交
234 235 236 237
    VIR_FREE(data);
}


J
Jiri Denemark 已提交
238
virCPUDataPtr
239
virCPUx86MakeData(virArch arch, virCPUx86Data **data)
240
{
241
    virCPUDataPtr cpuData;
242 243 244 245

    if (VIR_ALLOC(cpuData) < 0)
        return NULL;

J
Jiri Denemark 已提交
246 247
    cpuData->arch = arch;
    cpuData->data.x86 = *data;
248 249 250 251 252 253
    *data = NULL;

    return cpuData;
}

static void
254
x86FreeCPUData(virCPUDataPtr data)
255 256 257 258
{
    if (!data)
        return;

259
    virCPUx86DataFree(data->data.x86);
260 261 262 263
    VIR_FREE(data);
}


264 265
static virCPUx86Data *
x86DataCopy(const virCPUx86Data *data)
J
Jiri Denemark 已提交
266
{
267
    virCPUx86Data *copy = NULL;
268
    size_t i;
J
Jiri Denemark 已提交
269

270 271
    if (VIR_ALLOC(copy) < 0 ||
        VIR_ALLOC_N(copy->data, data->len) < 0) {
272
        virCPUx86DataFree(copy);
J
Jiri Denemark 已提交
273 274 275
        return NULL;
    }

276 277 278
    copy->len = data->len;
    for (i = 0; i < data->len; i++)
        copy->data[i] = data->data[i];
J
Jiri Denemark 已提交
279 280 281 282 283

    return copy;
}


J
Jiri Denemark 已提交
284
int
285 286
virCPUx86DataAddCPUID(virCPUx86Data *data,
                      const virCPUx86CPUID *cpuid)
J
Jiri Denemark 已提交
287
{
288
    virCPUx86CPUID *existing;
J
Jiri Denemark 已提交
289

290 291 292 293 294 295
    if ((existing = x86DataCpuid(data, cpuid->function))) {
        x86cpuidSetBits(existing, cpuid);
    } else {
        if (VIR_APPEND_ELEMENT_COPY(data->data, data->len,
                                    *((virCPUx86CPUID *)cpuid)) < 0)
            return -1;
J
Jiri Denemark 已提交
296

297 298 299
        qsort(data->data, data->len,
              sizeof(virCPUx86CPUID), virCPUx86CPUIDSorter);
    }
J
Jiri Denemark 已提交
300

J
Jiri Denemark 已提交
301 302 303 304 305
    return 0;
}


static int
306 307
x86DataAdd(virCPUx86Data *data1,
           const virCPUx86Data *data2)
J
Jiri Denemark 已提交
308
{
309 310 311
    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data2);
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
J
Jiri Denemark 已提交
312

313 314
    while ((cpuid2 = x86DataCpuidNext(&iter))) {
        cpuid1 = x86DataCpuid(data1, cpuid2->function);
J
Jiri Denemark 已提交
315

316 317 318 319 320 321
        if (cpuid1) {
            x86cpuidSetBits(cpuid1, cpuid2);
        } else {
            if (virCPUx86DataAddCPUID(data1, cpuid2) < 0)
                return -1;
        }
J
Jiri Denemark 已提交
322
    }
J
Jiri Denemark 已提交
323 324 325 326 327

    return 0;
}


328
static void
329 330
x86DataSubtract(virCPUx86Data *data1,
                const virCPUx86Data *data2)
331
{
332 333 334
    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data1);
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
335

336 337 338
    while ((cpuid1 = x86DataCpuidNext(&iter))) {
        cpuid2 = x86DataCpuid(data2, cpuid1->function);
        x86cpuidClearBits(cpuid1, cpuid2);
339 340 341 342
    }
}


J
Jiri Denemark 已提交
343
static void
344 345
x86DataIntersect(virCPUx86Data *data1,
                 const virCPUx86Data *data2)
346
{
347
    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data1);
348 349
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
350

J
Jiri Denemark 已提交
351 352 353 354 355 356
    while ((cpuid1 = x86DataCpuidNext(&iter))) {
        cpuid2 = x86DataCpuid(data2, cpuid1->function);
        if (cpuid2)
            x86cpuidAndBits(cpuid1, cpuid2);
        else
            x86cpuidClearBits(cpuid1, cpuid1);
357 358 359 360
    }
}


J
Jiri Denemark 已提交
361
static bool
362
x86DataIsEmpty(virCPUx86Data *data)
J
Jiri Denemark 已提交
363
{
364
    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data);
J
Jiri Denemark 已提交
365

366
    return x86DataCpuidNext(&iter) == NULL;
J
Jiri Denemark 已提交
367
}
J
Jiri Denemark 已提交
368 369


J
Jiri Denemark 已提交
370
static bool
371 372
x86DataIsSubset(const virCPUx86Data *data,
                const virCPUx86Data *subset)
J
Jiri Denemark 已提交
373 374
{

375
    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit((virCPUx86Data *)subset);
376 377
    const virCPUx86CPUID *cpuid;
    const virCPUx86CPUID *cpuidSubset;
J
Jiri Denemark 已提交
378

J
Jiri Denemark 已提交
379 380 381 382
    while ((cpuidSubset = x86DataCpuidNext(&iter))) {
        if (!(cpuid = x86DataCpuid(data, cpuidSubset->function)) ||
            !x86cpuidMatchMasked(cpuid, cpuidSubset))
            return false;
J
Jiri Denemark 已提交
383 384
    }

J
Jiri Denemark 已提交
385
    return true;
J
Jiri Denemark 已提交
386 387 388
}


389 390 391 392
/* also removes all detected features from data */
static int
x86DataToCPUFeatures(virCPUDefPtr cpu,
                     int policy,
393
                     virCPUx86Data *data,
394 395 396 397 398
                     const struct x86_map *map)
{
    const struct x86_feature *feature = map->features;

    while (feature != NULL) {
J
Jiri Denemark 已提交
399 400 401 402
        if (x86DataIsSubset(data, feature->data)) {
            x86DataSubtract(data, feature->data);
            if (virCPUDefAddFeature(cpu, feature->name, policy) < 0)
                return -1;
403 404 405 406 407 408 409 410
        }
        feature = feature->next;
    }

    return 0;
}


J
Jiri Denemark 已提交
411 412
/* also removes bits corresponding to vendor string from data */
static const struct x86_vendor *
413
x86DataToVendor(virCPUx86Data *data,
J
Jiri Denemark 已提交
414 415 416
                const struct x86_map *map)
{
    const struct x86_vendor *vendor = map->vendors;
417
    virCPUx86CPUID *cpuid;
J
Jiri Denemark 已提交
418 419 420 421 422 423 424 425 426 427 428 429 430 431

    while (vendor) {
        if ((cpuid = x86DataCpuid(data, vendor->cpuid.function)) &&
            x86cpuidMatchMasked(cpuid, &vendor->cpuid)) {
            x86cpuidClearBits(cpuid, &vendor->cpuid);
            return vendor;
        }
        vendor = vendor->next;
    }

    return NULL;
}


432
static virCPUDefPtr
433
x86DataToCPU(const virCPUx86Data *data,
434 435 436 437
             const struct x86_model *model,
             const struct x86_map *map)
{
    virCPUDefPtr cpu;
438 439
    virCPUx86Data *copy = NULL;
    virCPUx86Data *modelData = NULL;
J
Jiri Denemark 已提交
440
    const struct x86_vendor *vendor;
441 442

    if (VIR_ALLOC(cpu) < 0 ||
443
        VIR_STRDUP(cpu->model, model->name) < 0 ||
444
        !(copy = x86DataCopy(data)) ||
J
Jiri Denemark 已提交
445
        !(modelData = x86DataCopy(model->data)))
446
        goto error;
447

J
Jiri Denemark 已提交
448
    if ((vendor = x86DataToVendor(copy, map)) &&
449
        VIR_STRDUP(cpu->vendor, vendor->name) < 0)
450
        goto error;
J
Jiri Denemark 已提交
451

452 453 454 455 456
    x86DataSubtract(copy, modelData);
    x86DataSubtract(modelData, data);

    /* because feature policy is ignored for host CPU */
    cpu->type = VIR_CPU_TYPE_GUEST;
457

458 459
    if (x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_REQUIRE, copy, map) ||
        x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_DISABLE, modelData, map))
460
        goto error;
461

462
 cleanup:
463 464
    virCPUx86DataFree(modelData);
    virCPUx86DataFree(copy);
465 466
    return cpu;

467
 error:
468 469 470 471 472 473
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
}


J
Jiri Denemark 已提交
474 475 476 477 478 479 480 481
static void
x86VendorFree(struct x86_vendor *vendor)
{
    if (!vendor)
        return;

    VIR_FREE(vendor->name);
    VIR_FREE(vendor);
J
Jiri Denemark 已提交
482
}
J
Jiri Denemark 已提交
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511


static struct x86_vendor *
x86VendorFind(const struct x86_map *map,
              const char *name)
{
    struct x86_vendor *vendor;

    vendor = map->vendors;
    while (vendor) {
        if (STREQ(vendor->name, name))
            return vendor;

        vendor = vendor->next;
    }

    return NULL;
}


static int
x86VendorLoad(xmlXPathContextPtr ctxt,
              struct x86_map *map)
{
    struct x86_vendor *vendor = NULL;
    char *string = NULL;
    int ret = 0;

    if (VIR_ALLOC(vendor) < 0)
512
        goto error;
J
Jiri Denemark 已提交
513 514 515

    vendor->name = virXPathString("string(@name)", ctxt);
    if (!vendor->name) {
516 517
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing CPU vendor name"));
J
Jiri Denemark 已提交
518 519 520 521
        goto ignore;
    }

    if (x86VendorFind(map, vendor->name)) {
522 523
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU vendor %s already defined"), vendor->name);
J
Jiri Denemark 已提交
524 525 526 527 528
        goto ignore;
    }

    string = virXPathString("string(@string)", ctxt);
    if (!string) {
529
        virReportError(VIR_ERR_INTERNAL_ERROR,
530 531
                       _("Missing vendor string for CPU vendor %s"),
                       vendor->name);
J
Jiri Denemark 已提交
532 533 534
        goto ignore;
    }
    if (strlen(string) != VENDOR_STRING_LENGTH) {
535 536
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid CPU vendor string '%s'"), string);
J
Jiri Denemark 已提交
537 538 539 540
        goto ignore;
    }

    vendor->cpuid.function = 0;
E
Eric Blake 已提交
541 542 543 544 545
    vendor->cpuid.ebx = virReadBufInt32LE(string);
    vendor->cpuid.edx = virReadBufInt32LE(string + 4);
    vendor->cpuid.ecx = virReadBufInt32LE(string + 8);

    if (!map->vendors) {
J
Jiri Denemark 已提交
546
        map->vendors = vendor;
E
Eric Blake 已提交
547
    } else {
J
Jiri Denemark 已提交
548 549 550 551
        vendor->next = map->vendors;
        map->vendors = vendor;
    }

552
 out:
J
Jiri Denemark 已提交
553 554 555 556
    VIR_FREE(string);

    return ret;

557
 error:
J
Jiri Denemark 已提交
558
    ret = -1;
559
 ignore:
J
Jiri Denemark 已提交
560 561 562 563 564
    x86VendorFree(vendor);
    goto out;
}


J
Jiri Denemark 已提交
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
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;
}


J
Jiri Denemark 已提交
582 583 584 585 586 587 588
static void
x86FeatureFree(struct x86_feature *feature)
{
    if (feature == NULL)
        return;

    VIR_FREE(feature->name);
589
    virCPUx86DataFree(feature->data);
J
Jiri Denemark 已提交
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
    VIR_FREE(feature);
}


static struct x86_feature *
x86FeatureFind(const struct x86_map *map,
               const char *name)
{
    struct x86_feature *feature;

    feature = map->features;
    while (feature != NULL) {
        if (STREQ(feature->name, name))
            return feature;

        feature = feature->next;
    }

    return NULL;
}


612 613 614
static char *
x86FeatureNames(const struct x86_map *map,
                const char *separator,
615
                virCPUx86Data *data)
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
{
    virBuffer ret = VIR_BUFFER_INITIALIZER;
    bool first = true;

    struct x86_feature *next_feature = map->features;

    virBufferAdd(&ret, "", 0);

    while (next_feature) {
        if (x86DataIsSubset(data, next_feature->data)) {
            if (!first)
                virBufferAdd(&ret, separator, -1);
            else
                first = false;

            virBufferAdd(&ret, next_feature->name, -1);
        }
        next_feature = next_feature->next;
    }

    return virBufferContentAndReset(&ret);
}


640 641
static int
x86ParseCPUID(xmlXPathContextPtr ctxt,
642
              virCPUx86CPUID *cpuid)
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
{
    unsigned long fun, eax, ebx, ecx, edx;
    int ret_fun, ret_eax, ret_ebx, ret_ecx, ret_edx;

    memset(cpuid, 0, sizeof(*cpuid));

    fun = eax = ebx = ecx = edx = 0;
    ret_fun = virXPathULongHex("string(@function)", ctxt, &fun);
    ret_eax = virXPathULongHex("string(@eax)", ctxt, &eax);
    ret_ebx = virXPathULongHex("string(@ebx)", ctxt, &ebx);
    ret_ecx = virXPathULongHex("string(@ecx)", ctxt, &ecx);
    ret_edx = virXPathULongHex("string(@edx)", ctxt, &edx);

    if (ret_fun < 0 || ret_eax == -2 || ret_ebx == -2
        || ret_ecx == -2 || ret_edx == -2)
        return -1;

    cpuid->function = fun;
    cpuid->eax = eax;
    cpuid->ebx = ebx;
    cpuid->ecx = ecx;
    cpuid->edx = edx;
    return 0;
}


J
Jiri Denemark 已提交
669 670
static int
x86FeatureLoad(xmlXPathContextPtr ctxt,
J
Jiri Denemark 已提交
671
               struct x86_map *map)
J
Jiri Denemark 已提交
672 673
{
    xmlNodePtr *nodes = NULL;
674
    xmlNodePtr ctxt_node = ctxt->node;
J
Jiri Denemark 已提交
675
    struct x86_feature *feature;
676
    virCPUx86CPUID cpuid;
J
Jiri Denemark 已提交
677
    int ret = 0;
678
    size_t i;
J
Jiri Denemark 已提交
679 680
    int n;

J
Jiri Denemark 已提交
681
    if (!(feature = x86FeatureNew()))
682
        goto error;
J
Jiri Denemark 已提交
683

684
    feature->name = virXPathString("string(@name)", ctxt);
J
Jiri Denemark 已提交
685
    if (feature->name == NULL) {
686 687
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing CPU feature name"));
J
Jiri Denemark 已提交
688 689 690 691
        goto ignore;
    }

    if (x86FeatureFind(map, feature->name)) {
692 693
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU feature %s already defined"), feature->name);
J
Jiri Denemark 已提交
694 695 696
        goto ignore;
    }

697
    n = virXPathNodeSet("./cpuid", ctxt, &nodes);
J
Jiri Denemark 已提交
698 699 700 701 702
    if (n < 0)
        goto ignore;

    for (i = 0; i < n; i++) {
        ctxt->node = nodes[i];
703
        if (x86ParseCPUID(ctxt, &cpuid) < 0) {
704
            virReportError(VIR_ERR_INTERNAL_ERROR,
705 706
                           _("Invalid cpuid[%zu] in %s feature"),
                           i, feature->name);
J
Jiri Denemark 已提交
707 708
            goto ignore;
        }
709
        if (virCPUx86DataAddCPUID(feature->data, &cpuid))
710
            goto error;
J
Jiri Denemark 已提交
711 712 713 714 715 716 717 718 719
    }

    if (map->features == NULL)
        map->features = feature;
    else {
        feature->next = map->features;
        map->features = feature;
    }

720
 out:
721 722 723
    ctxt->node = ctxt_node;
    VIR_FREE(nodes);

J
Jiri Denemark 已提交
724 725
    return ret;

726
 error:
J
Jiri Denemark 已提交
727 728
    ret = -1;

729
 ignore:
J
Jiri Denemark 已提交
730 731 732 733 734
    x86FeatureFree(feature);
    goto out;
}


735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
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;

759
 error:
760 761 762 763 764
    virCPUx86DataFree(data);
    return NULL;
}


J
Jiri Denemark 已提交
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
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;
}


J
Jiri Denemark 已提交
782 783 784 785 786 787 788
static void
x86ModelFree(struct x86_model *model)
{
    if (model == NULL)
        return;

    VIR_FREE(model->name);
789
    virCPUx86DataFree(model->data);
J
Jiri Denemark 已提交
790 791 792 793 794 795 796 797 798
    VIR_FREE(model);
}


static struct x86_model *
x86ModelCopy(const struct x86_model *model)
{
    struct x86_model *copy;

799 800 801
    if (VIR_ALLOC(copy) < 0 ||
        VIR_STRDUP(copy->name, model->name) < 0 ||
        !(copy->data = x86DataCopy(model->data))) {
J
Jiri Denemark 已提交
802 803 804 805
        x86ModelFree(copy);
        return NULL;
    }

J
Jiri Denemark 已提交
806
    copy->vendor = model->vendor;
J
Jiri Denemark 已提交
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830

    return copy;
}


static struct x86_model *
x86ModelFind(const struct x86_map *map,
             const char *name)
{
    struct x86_model *model;

    model = map->models;
    while (model != NULL) {
        if (STREQ(model->name, name))
            return model;

        model = model->next;
    }

    return NULL;
}


static struct x86_model *
831
x86ModelFromCPU(const virCPUDef *cpu,
J
Jiri Denemark 已提交
832 833 834 835
                const struct x86_map *map,
                int policy)
{
    struct x86_model *model = NULL;
836
    size_t i;
J
Jiri Denemark 已提交
837

838
    if (policy == VIR_CPU_FEATURE_REQUIRE) {
J
Jiri Denemark 已提交
839
        if ((model = x86ModelFind(map, cpu->model)) == NULL) {
840 841
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU model %s"), cpu->model);
J
Jiri Denemark 已提交
842 843 844 845
            goto error;
        }

        if ((model = x86ModelCopy(model)) == NULL)
846
            goto error;
J
Jiri Denemark 已提交
847
    } else if (!(model = x86ModelNew())) {
848
        goto error;
J
Jiri Denemark 已提交
849
    } else if (cpu->type == VIR_CPU_TYPE_HOST) {
850
        return model;
J
Jiri Denemark 已提交
851
    }
J
Jiri Denemark 已提交
852 853 854 855 856 857 858 859 860

    for (i = 0; i < cpu->nfeatures; i++) {
        const struct x86_feature *feature;

        if (cpu->type == VIR_CPU_TYPE_GUEST
            && cpu->features[i].policy != policy)
            continue;

        if ((feature = x86FeatureFind(map, cpu->features[i].name)) == NULL) {
861 862
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU feature %s"), cpu->features[i].name);
J
Jiri Denemark 已提交
863 864 865
            goto error;
        }

J
Jiri Denemark 已提交
866
        if (x86DataAdd(model->data, feature->data))
867
            goto error;
J
Jiri Denemark 已提交
868 869 870 871
    }

    return model;

872
 error:
J
Jiri Denemark 已提交
873 874 875 876 877
    x86ModelFree(model);
    return NULL;
}


878 879
static int
x86ModelSubtractCPU(struct x86_model *model,
880
                    const virCPUDef *cpu,
881 882 883
                    const struct x86_map *map)
{
    const struct x86_model *cpu_model;
884
    size_t i;
885 886

    if (!(cpu_model = x86ModelFind(map, cpu->model))) {
887 888 889
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown CPU model %s"),
                       cpu->model);
890 891 892
        return -1;
    }

J
Jiri Denemark 已提交
893
    x86DataSubtract(model->data, cpu_model->data);
894 895 896 897 898

    for (i = 0; i < cpu->nfeatures; i++) {
        const struct x86_feature *feature;

        if (!(feature = x86FeatureFind(map, cpu->features[i].name))) {
899 900 901
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU feature %s"),
                           cpu->features[i].name);
902 903 904
            return -1;
        }

J
Jiri Denemark 已提交
905
        x86DataSubtract(model->data, feature->data);
906 907 908 909 910 911
    }

    return 0;
}


J
Jiri Denemark 已提交
912 913 914 915 916
static enum compare_result
x86ModelCompare(const struct x86_model *model1,
                const struct x86_model *model2)
{
    enum compare_result result = EQUAL;
917 918
    struct virCPUx86DataIterator iter1 = virCPUx86DataIteratorInit(model1->data);
    struct virCPUx86DataIterator iter2 = virCPUx86DataIteratorInit(model2->data);
919 920
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
J
Jiri Denemark 已提交
921

J
Jiri Denemark 已提交
922
    while ((cpuid1 = x86DataCpuidNext(&iter1))) {
J
Jiri Denemark 已提交
923 924
        enum compare_result match = SUPERSET;

J
Jiri Denemark 已提交
925
        if ((cpuid2 = x86DataCpuid(model2->data, cpuid1->function))) {
J
Jiri Denemark 已提交
926 927 928 929 930 931 932 933 934 935 936 937
            if (x86cpuidMatch(cpuid1, cpuid2))
                continue;
            else if (!x86cpuidMatchMasked(cpuid1, cpuid2))
                match = SUBSET;
        }

        if (result == EQUAL)
            result = match;
        else if (result != match)
            return UNRELATED;
    }

J
Jiri Denemark 已提交
938
    while ((cpuid2 = x86DataCpuidNext(&iter2))) {
J
Jiri Denemark 已提交
939 940
        enum compare_result match = SUBSET;

J
Jiri Denemark 已提交
941
        if ((cpuid1 = x86DataCpuid(model1->data, cpuid2->function))) {
J
Jiri Denemark 已提交
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959
            if (x86cpuidMatch(cpuid2, cpuid1))
                continue;
            else if (!x86cpuidMatchMasked(cpuid2, cpuid1))
                match = SUPERSET;
        }

        if (result == EQUAL)
            result = match;
        else if (result != match)
            return UNRELATED;
    }

    return result;
}


static int
x86ModelLoad(xmlXPathContextPtr ctxt,
J
Jiri Denemark 已提交
960
             struct x86_map *map)
J
Jiri Denemark 已提交
961 962
{
    xmlNodePtr *nodes = NULL;
J
Jiri Denemark 已提交
963
    struct x86_model *model;
J
Jiri Denemark 已提交
964
    char *vendor = NULL;
J
Jiri Denemark 已提交
965
    int ret = 0;
966
    size_t i;
J
Jiri Denemark 已提交
967 968
    int n;

J
Jiri Denemark 已提交
969
    if (!(model = x86ModelNew()))
970
        goto error;
J
Jiri Denemark 已提交
971

972
    model->name = virXPathString("string(@name)", ctxt);
J
Jiri Denemark 已提交
973
    if (model->name == NULL) {
974 975
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing CPU model name"));
J
Jiri Denemark 已提交
976 977 978
        goto ignore;
    }

979
    if (virXPathNode("./model", ctxt) != NULL) {
J
Jiri Denemark 已提交
980 981 982
        const struct x86_model *ancestor;
        char *name;

983
        name = virXPathString("string(./model/@name)", ctxt);
J
Jiri Denemark 已提交
984
        if (name == NULL) {
985 986 987
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing ancestor's name in CPU model %s"),
                           model->name);
J
Jiri Denemark 已提交
988 989 990 991
            goto ignore;
        }

        if ((ancestor = x86ModelFind(map, name)) == NULL) {
992 993 994
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Ancestor model %s not found for CPU model %s"),
                           name, model->name);
J
Jiri Denemark 已提交
995 996 997 998 999 1000
            VIR_FREE(name);
            goto ignore;
        }

        VIR_FREE(name);

J
Jiri Denemark 已提交
1001
        model->vendor = ancestor->vendor;
1002
        virCPUx86DataFree(model->data);
J
Jiri Denemark 已提交
1003
        if (!(model->data = x86DataCopy(ancestor->data)))
1004
            goto error;
J
Jiri Denemark 已提交
1005 1006
    }

1007 1008 1009
    if (virXPathBoolean("boolean(./vendor)", ctxt)) {
        vendor = virXPathString("string(./vendor/@name)", ctxt);
        if (!vendor) {
1010 1011 1012
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid vendor element in CPU model %s"),
                           model->name);
1013 1014 1015
            goto ignore;
        }

J
Jiri Denemark 已提交
1016
        if (!(model->vendor = x86VendorFind(map, vendor))) {
1017 1018 1019
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown vendor %s referenced by CPU model %s"),
                           vendor, model->name);
J
Jiri Denemark 已提交
1020 1021 1022 1023
            goto ignore;
        }
    }

1024
    n = virXPathNodeSet("./feature", ctxt, &nodes);
J
Jiri Denemark 已提交
1025 1026 1027 1028 1029 1030 1031 1032
    if (n < 0)
        goto ignore;

    for (i = 0; i < n; i++) {
        const struct x86_feature *feature;
        char *name;

        if ((name = virXMLPropString(nodes[i], "name")) == NULL) {
1033 1034
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing feature name for CPU model %s"), model->name);
J
Jiri Denemark 已提交
1035 1036 1037 1038
            goto ignore;
        }

        if ((feature = x86FeatureFind(map, name)) == NULL) {
1039 1040 1041
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Feature %s required by CPU model %s not found"),
                           name, model->name);
J
Jiri Denemark 已提交
1042 1043 1044 1045 1046
            VIR_FREE(name);
            goto ignore;
        }
        VIR_FREE(name);

J
Jiri Denemark 已提交
1047
        if (x86DataAdd(model->data, feature->data))
1048
            goto error;
J
Jiri Denemark 已提交
1049 1050 1051 1052 1053 1054 1055 1056 1057
    }

    if (map->models == NULL)
        map->models = model;
    else {
        model->next = map->models;
        map->models = model;
    }

1058
 out:
J
Jiri Denemark 已提交
1059
    VIR_FREE(vendor);
1060
    VIR_FREE(nodes);
J
Jiri Denemark 已提交
1061 1062
    return ret;

1063
 error:
J
Jiri Denemark 已提交
1064 1065
    ret = -1;

1066
 ignore:
J
Jiri Denemark 已提交
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
    x86ModelFree(model);
    goto out;
}


static void
x86MapFree(struct x86_map *map)
{
    if (map == NULL)
        return;

    while (map->features != NULL) {
        struct x86_feature *feature = map->features;
        map->features = feature->next;
        x86FeatureFree(feature);
    }

    while (map->models != NULL) {
        struct x86_model *model = map->models;
        map->models = model->next;
        x86ModelFree(model);
    }

1090 1091 1092 1093 1094 1095
    while (map->vendors != NULL) {
        struct x86_vendor *vendor = map->vendors;
        map->vendors = vendor->next;
        x86VendorFree(vendor);
    }

J
Jiri Denemark 已提交
1096 1097 1098 1099
    VIR_FREE(map);
}


J
Jiri Denemark 已提交
1100
static int
1101
x86MapLoadCallback(cpuMapElement element,
J
Jiri Denemark 已提交
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
                   xmlXPathContextPtr ctxt,
                   void *data)
{
    struct x86_map *map = data;

    switch (element) {
    case CPU_MAP_ELEMENT_VENDOR:
        return x86VendorLoad(ctxt, map);
    case CPU_MAP_ELEMENT_FEATURE:
        return x86FeatureLoad(ctxt, map);
    case CPU_MAP_ELEMENT_MODEL:
        return x86ModelLoad(ctxt, map);
    case CPU_MAP_ELEMENT_LAST:
        break;
    }

    return 0;
}


1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
static int
x86MapLoadInternalFeatures(struct x86_map *map)
{
    size_t i;
    struct x86_feature *feature = NULL;

    for (i = 0; i < ARRAY_CARDINALITY(x86_kvm_features); i++) {
        const char *name = x86_kvm_features[i].name;

        if (x86FeatureFind(map, name)) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("CPU feature %s already defined"), name);
            return -1;
        }

        if (!(feature = x86FeatureNew()))
            goto error;

        if (VIR_STRDUP(feature->name, name) < 0)
            goto error;

        if (virCPUx86DataAddCPUID(feature->data, &x86_kvm_features[i].cpuid))
            goto error;

        if (map->features == NULL) {
            map->features = feature;
        } else {
            feature->next = map->features;
            map->features = feature;
        }

        feature = NULL;
    }

    return 0;

1158
 error:
1159 1160 1161 1162 1163
    x86FeatureFree(feature);
    return -1;
}


J
Jiri Denemark 已提交
1164
static struct x86_map *
1165
virCPUx86LoadMap(void)
J
Jiri Denemark 已提交
1166 1167 1168
{
    struct x86_map *map;

1169
    if (VIR_ALLOC(map) < 0)
J
Jiri Denemark 已提交
1170 1171
        return NULL;

J
Jiri Denemark 已提交
1172
    if (cpuMapLoad("x86", x86MapLoadCallback, map) < 0)
J
Jiri Denemark 已提交
1173 1174
        goto error;

1175 1176 1177
    if (x86MapLoadInternalFeatures(map) < 0)
        goto error;

J
Jiri Denemark 已提交
1178 1179
    return map;

1180
 error:
J
Jiri Denemark 已提交
1181 1182 1183 1184 1185
    x86MapFree(map);
    return NULL;
}


1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
int
virCPUx86MapOnceInit(void)
{
    if (!(virCPUx86Map = virCPUx86LoadMap()))
        return -1;

    return 0;
}


static const struct x86_map *
virCPUx86GetMap(void)
{
    if (virCPUx86MapInitialize() < 0)
        return NULL;

    return virCPUx86Map;
}


1206 1207 1208
static char *
x86CPUDataFormat(const virCPUData *data)
{
1209
    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data->data.x86);
1210
    virCPUx86CPUID *cpuid;
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virBufferAddLit(&buf, "<cpudata arch='x86'>\n");
    while ((cpuid = x86DataCpuidNext(&iter))) {
        virBufferAsprintf(&buf,
                          "  <cpuid function='0x%08x'"
                          " eax='0x%08x' ebx='0x%08x'"
                          " ecx='0x%08x' edx='0x%08x'/>\n",
                          cpuid->function,
                          cpuid->eax, cpuid->ebx, cpuid->ecx, cpuid->edx);
    }
    virBufferAddLit(&buf, "</cpudata>\n");

1224
    if (virBufferCheckError(&buf) < 0)
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
        return NULL;

    return virBufferContentAndReset(&buf);
}


static virCPUDataPtr
x86CPUDataParse(const char *xmlStr)
{
    xmlDocPtr xml = NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlNodePtr *nodes = NULL;
    virCPUDataPtr cpuData = NULL;
1238
    virCPUx86Data *data = NULL;
1239
    virCPUx86CPUID cpuid;
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
    size_t i;
    int n;

    if (VIR_ALLOC(data) < 0)
        goto cleanup;

    if (!(xml = virXMLParseStringCtxt(xmlStr, _("CPU data"), &ctxt))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot parse CPU data"));
        goto cleanup;
    }
    ctxt->node = xmlDocGetRootElement(xml);

    n = virXPathNodeSet("/cpudata[@arch='x86']/data", ctxt, &nodes);
    if (n < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("no x86 CPU data found"));
        goto cleanup;
    }

    for (i = 0; i < n; i++) {
        ctxt->node = nodes[i];
        if (x86ParseCPUID(ctxt, &cpuid) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("failed to parse cpuid[%zu]"), i);
            goto cleanup;
        }
1267
        if (virCPUx86DataAddCPUID(data, &cpuid) < 0)
1268 1269 1270
            goto cleanup;
    }

1271
    cpuData = virCPUx86MakeData(VIR_ARCH_X86_64, &data);
1272

1273
 cleanup:
1274 1275 1276
    VIR_FREE(nodes);
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(xml);
1277
    virCPUx86DataFree(data);
1278 1279 1280 1281
    return cpuData;
}


1282 1283 1284
/* A helper macro to exit the cpu computation function without writing
 * redundant code:
 * MSG: error message
1285
 * CPU_DEF: a virCPUx86Data pointer with flags that are conflicting
1286 1287 1288 1289 1290 1291 1292
 * RET: return code to set
 *
 * This macro generates the error string outputs it into logs.
 */
#define virX86CpuIncompatible(MSG, CPU_DEF)                             \
        do {                                                            \
            char *flagsStr = NULL;                                      \
1293 1294 1295 1296
            if (!(flagsStr = x86FeatureNames(map, ", ", (CPU_DEF)))) {  \
                virReportOOMError();                                    \
                goto error;                                             \
            }                                                           \
1297 1298 1299
            if (message &&                                              \
                virAsprintf(message, "%s: %s", _(MSG), flagsStr) < 0) { \
                VIR_FREE(flagsStr);                                     \
1300
                goto error;                                             \
1301 1302 1303 1304 1305 1306
            }                                                           \
            VIR_DEBUG("%s: %s", MSG, flagsStr);                         \
            VIR_FREE(flagsStr);                                         \
            ret = VIR_CPU_COMPARE_INCOMPATIBLE;                         \
        } while (0)

1307

J
Jiri Denemark 已提交
1308 1309 1310
static virCPUCompareResult
x86Compute(virCPUDefPtr host,
           virCPUDefPtr cpu,
1311
           virCPUDataPtr *guest,
1312
           char **message)
J
Jiri Denemark 已提交
1313
{
1314
    const struct x86_map *map = NULL;
J
Jiri Denemark 已提交
1315 1316 1317 1318 1319 1320 1321 1322 1323 1324
    struct x86_model *host_model = NULL;
    struct x86_model *cpu_force = NULL;
    struct x86_model *cpu_require = NULL;
    struct x86_model *cpu_optional = NULL;
    struct x86_model *cpu_disable = NULL;
    struct x86_model *cpu_forbid = NULL;
    struct x86_model *diff = NULL;
    struct x86_model *guest_model = NULL;
    virCPUCompareResult ret;
    enum compare_result result;
J
Jiri Denemark 已提交
1325
    virArch arch;
1326
    size_t i;
J
Jiri Denemark 已提交
1327

1328
    if (cpu->arch != VIR_ARCH_NONE) {
J
Jiri Denemark 已提交
1329 1330 1331
        bool found = false;

        for (i = 0; i < ARRAY_CARDINALITY(archs); i++) {
1332
            if (archs[i] == cpu->arch) {
J
Jiri Denemark 已提交
1333 1334 1335 1336 1337
                found = true;
                break;
            }
        }

1338
        if (!found) {
1339 1340
            VIR_DEBUG("CPU arch %s does not match host arch",
                      virArchToString(cpu->arch));
1341 1342 1343
            if (message &&
                virAsprintf(message,
                            _("CPU arch %s does not match host arch"),
1344
                            virArchToString(cpu->arch)) < 0)
1345
                goto error;
J
Jiri Denemark 已提交
1346
            return VIR_CPU_COMPARE_INCOMPATIBLE;
1347
        }
J
Jiri Denemark 已提交
1348 1349 1350
        arch = cpu->arch;
    } else {
        arch = host->arch;
J
Jiri Denemark 已提交
1351 1352
    }

J
Jiri Denemark 已提交
1353 1354 1355 1356
    if (cpu->vendor &&
        (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) {
        VIR_DEBUG("host CPU vendor does not match required CPU vendor %s",
                  cpu->vendor);
1357 1358 1359 1360 1361
        if (message &&
            virAsprintf(message,
                        _("host CPU vendor does not match required "
                          "CPU vendor %s"),
                        cpu->vendor) < 0)
1362
            goto error;
1363

J
Jiri Denemark 已提交
1364 1365 1366
        return VIR_CPU_COMPARE_INCOMPATIBLE;
    }

1367
    if (!(map = virCPUx86GetMap()) ||
1368
        !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)) ||
J
Jiri Denemark 已提交
1369 1370 1371 1372 1373
        !(cpu_force = x86ModelFromCPU(cpu, map, VIR_CPU_FEATURE_FORCE)) ||
        !(cpu_require = x86ModelFromCPU(cpu, map, VIR_CPU_FEATURE_REQUIRE)) ||
        !(cpu_optional = x86ModelFromCPU(cpu, map, VIR_CPU_FEATURE_OPTIONAL)) ||
        !(cpu_disable = x86ModelFromCPU(cpu, map, VIR_CPU_FEATURE_DISABLE)) ||
        !(cpu_forbid = x86ModelFromCPU(cpu, map, VIR_CPU_FEATURE_FORBID)))
J
Jiri Denemark 已提交
1374 1375
        goto error;

1376 1377 1378 1379
    x86DataIntersect(cpu_forbid->data, host_model->data);
    if (!x86DataIsEmpty(cpu_forbid->data)) {
        virX86CpuIncompatible(N_("Host CPU provides forbidden features"),
                              cpu_forbid->data);
1380
        goto cleanup;
J
Jiri Denemark 已提交
1381 1382
    }

1383 1384 1385 1386 1387
    /* first remove features that were inherited from the CPU model and were
     * explicitly forced, disabled, or made optional
     */
    x86DataSubtract(cpu_require->data, cpu_force->data);
    x86DataSubtract(cpu_require->data, cpu_optional->data);
J
Jiri Denemark 已提交
1388
    x86DataSubtract(cpu_require->data, cpu_disable->data);
J
Jiri Denemark 已提交
1389 1390
    result = x86ModelCompare(host_model, cpu_require);
    if (result == SUBSET || result == UNRELATED) {
1391 1392 1393 1394
        x86DataSubtract(cpu_require->data, host_model->data);
        virX86CpuIncompatible(N_("Host CPU does not provide required "
                                 "features"),
                              cpu_require->data);
1395
        goto cleanup;
J
Jiri Denemark 已提交
1396 1397 1398 1399
    }

    ret = VIR_CPU_COMPARE_IDENTICAL;

J
Jiri Denemark 已提交
1400
    if ((diff = x86ModelCopy(host_model)) == NULL)
1401
        goto error;
J
Jiri Denemark 已提交
1402

J
Jiri Denemark 已提交
1403 1404 1405 1406
    x86DataSubtract(diff->data, cpu_optional->data);
    x86DataSubtract(diff->data, cpu_require->data);
    x86DataSubtract(diff->data, cpu_disable->data);
    x86DataSubtract(diff->data, cpu_force->data);
J
Jiri Denemark 已提交
1407

J
Jiri Denemark 已提交
1408 1409
    if (!x86DataIsEmpty(diff->data))
        ret = VIR_CPU_COMPARE_SUPERSET;
J
Jiri Denemark 已提交
1410 1411 1412 1413

    if (ret == VIR_CPU_COMPARE_SUPERSET
        && cpu->type == VIR_CPU_TYPE_GUEST
        && cpu->match == VIR_CPU_MATCH_STRICT) {
1414 1415 1416
        virX86CpuIncompatible(N_("Host CPU does not strictly match guest CPU: "
                                 "Extra features"),
                              diff->data);
1417
        goto cleanup;
J
Jiri Denemark 已提交
1418 1419 1420
    }

    if (guest != NULL) {
1421
        virCPUx86Data *guestData;
1422

J
Jiri Denemark 已提交
1423
        if ((guest_model = x86ModelCopy(host_model)) == NULL)
1424
            goto error;
J
Jiri Denemark 已提交
1425 1426 1427

        if (cpu->type == VIR_CPU_TYPE_GUEST
            && cpu->match == VIR_CPU_MATCH_EXACT)
J
Jiri Denemark 已提交
1428
            x86DataSubtract(guest_model->data, diff->data);
J
Jiri Denemark 已提交
1429

J
Jiri Denemark 已提交
1430
        if (x86DataAdd(guest_model->data, cpu_force->data))
1431
            goto error;
J
Jiri Denemark 已提交
1432

J
Jiri Denemark 已提交
1433
        x86DataSubtract(guest_model->data, cpu_disable->data);
J
Jiri Denemark 已提交
1434

1435
        if (!(guestData = x86DataCopy(guest_model->data)) ||
1436
            !(*guest = virCPUx86MakeData(arch, &guestData))) {
1437
            virCPUx86DataFree(guestData);
1438
            goto error;
1439
        }
J
Jiri Denemark 已提交
1440 1441
    }

1442
 cleanup:
J
Jiri Denemark 已提交
1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
    x86ModelFree(host_model);
    x86ModelFree(diff);
    x86ModelFree(cpu_force);
    x86ModelFree(cpu_require);
    x86ModelFree(cpu_optional);
    x86ModelFree(cpu_disable);
    x86ModelFree(cpu_forbid);
    x86ModelFree(guest_model);

    return ret;

1454
 error:
J
Jiri Denemark 已提交
1455
    ret = VIR_CPU_COMPARE_ERROR;
1456
    goto cleanup;
J
Jiri Denemark 已提交
1457
}
1458
#undef virX86CpuIncompatible
J
Jiri Denemark 已提交
1459 1460 1461 1462


static virCPUCompareResult
x86Compare(virCPUDefPtr host,
1463 1464
           virCPUDefPtr cpu,
           bool failIncomaptible)
J
Jiri Denemark 已提交
1465
{
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
    virCPUCompareResult ret;
    char *message = NULL;

    ret = x86Compute(host, cpu, NULL, &message);

    if (failIncomaptible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) {
        ret = VIR_CPU_COMPARE_ERROR;
        if (message) {
            virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", message);
        } else {
            virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL);
        }
    }
    VIR_FREE(message);

    return ret;
J
Jiri Denemark 已提交
1482 1483 1484 1485 1486 1487
}


static virCPUCompareResult
x86GuestData(virCPUDefPtr host,
             virCPUDefPtr guest,
1488
             virCPUDataPtr *data,
1489
             char **message)
J
Jiri Denemark 已提交
1490
{
1491
    return x86Compute(host, guest, data, message);
J
Jiri Denemark 已提交
1492 1493
}

1494

J
Jiri Denemark 已提交
1495 1496
static int
x86Decode(virCPUDefPtr cpu,
1497
          const virCPUx86Data *data,
1498
          const char **models,
1499
          unsigned int nmodels,
1500 1501
          const char *preferred,
          unsigned int flags)
J
Jiri Denemark 已提交
1502 1503
{
    int ret = -1;
1504
    const struct x86_map *map;
J
Jiri Denemark 已提交
1505
    const struct x86_model *candidate;
1506 1507
    virCPUDefPtr cpuCandidate;
    virCPUDefPtr cpuModel = NULL;
1508 1509 1510
    virCPUx86Data *copy = NULL;
    virCPUx86Data *features = NULL;
    const virCPUx86Data *cpuData = NULL;
1511
    size_t i;
J
Jiri Denemark 已提交
1512

1513 1514
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1);

1515
    if (!data || !(map = virCPUx86GetMap()))
J
Jiri Denemark 已提交
1516 1517 1518 1519
        return -1;

    candidate = map->models;
    while (candidate != NULL) {
1520
        if (!cpuModelIsAllowed(candidate->name, models, nmodels)) {
1521 1522
            if (preferred && STREQ(candidate->name, preferred)) {
                if (cpu->fallback != VIR_CPU_FALLBACK_ALLOW) {
1523 1524 1525
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("CPU model %s is not supported by hypervisor"),
                                   preferred);
1526 1527 1528 1529 1530 1531 1532 1533 1534 1535
                    goto out;
                } else {
                    VIR_WARN("Preferred CPU model %s not allowed by"
                             " hypervisor; closest supported model will be"
                             " used", preferred);
                }
            } else {
                VIR_DEBUG("CPU model %s not allowed by hypervisor; ignoring",
                          candidate->name);
            }
1536
            goto next;
J
Jiri Denemark 已提交
1537 1538
        }

1539 1540 1541
        if (!(cpuCandidate = x86DataToCPU(data, candidate, map)))
            goto out;

J
Jiri Denemark 已提交
1542 1543 1544 1545 1546 1547 1548 1549 1550
        if (candidate->vendor && cpuCandidate->vendor &&
            STRNEQ(candidate->vendor->name, cpuCandidate->vendor)) {
            VIR_DEBUG("CPU vendor %s of model %s differs from %s; ignoring",
                      candidate->vendor->name, candidate->name,
                      cpuCandidate->vendor);
            virCPUDefFree(cpuCandidate);
            goto next;
        }

1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
        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;
                }
            }
        }

1564 1565 1566
        if (preferred && STREQ(cpuCandidate->model, preferred)) {
            virCPUDefFree(cpuModel);
            cpuModel = cpuCandidate;
1567
            cpuData = candidate->data;
1568 1569 1570
            break;
        }

1571 1572 1573 1574
        if (cpuModel == NULL
            || cpuModel->nfeatures > cpuCandidate->nfeatures) {
            virCPUDefFree(cpuModel);
            cpuModel = cpuCandidate;
1575 1576
            cpuData = candidate->data;
        } else {
1577
            virCPUDefFree(cpuCandidate);
1578
        }
1579

J
Jiri Denemark 已提交
1580 1581 1582 1583
    next:
        candidate = candidate->next;
    }

1584
    if (cpuModel == NULL) {
1585 1586
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Cannot find suitable CPU model for given data"));
J
Jiri Denemark 已提交
1587 1588 1589
        goto out;
    }

1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600
    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;
    }

1601
    cpu->model = cpuModel->model;
J
Jiri Denemark 已提交
1602
    cpu->vendor = cpuModel->vendor;
1603 1604 1605
    cpu->nfeatures = cpuModel->nfeatures;
    cpu->features = cpuModel->features;
    VIR_FREE(cpuModel);
J
Jiri Denemark 已提交
1606 1607 1608

    ret = 0;

1609
 out:
1610
    virCPUDefFree(cpuModel);
1611 1612
    virCPUx86DataFree(copy);
    virCPUx86DataFree(features);
J
Jiri Denemark 已提交
1613 1614 1615
    return ret;
}

1616 1617
static int
x86DecodeCPUData(virCPUDefPtr cpu,
1618
                 const virCPUData *data,
1619 1620
                 const char **models,
                 unsigned int nmodels,
1621 1622
                 const char *preferred,
                 unsigned int flags)
1623
{
1624
    return x86Decode(cpu, data->data.x86, models, nmodels, preferred, flags);
1625
}
J
Jiri Denemark 已提交
1626

1627

1628
static virCPUx86Data *
1629
x86EncodePolicy(const virCPUDef *cpu,
J
Jiri Denemark 已提交
1630
                const struct x86_map *map,
1631
                virCPUFeaturePolicy policy)
J
Jiri Denemark 已提交
1632 1633
{
    struct x86_model *model;
1634
    virCPUx86Data *data = NULL;
J
Jiri Denemark 已提交
1635 1636 1637 1638

    if (!(model = x86ModelFromCPU(cpu, map, policy)))
        return NULL;

J
Jiri Denemark 已提交
1639 1640
    data = model->data;
    model->data = NULL;
J
Jiri Denemark 已提交
1641 1642 1643 1644 1645 1646 1647
    x86ModelFree(model);

    return data;
}


static int
J
Jiri Denemark 已提交
1648
x86Encode(virArch arch,
1649
          const virCPUDef *cpu,
1650 1651 1652 1653 1654 1655
          virCPUDataPtr *forced,
          virCPUDataPtr *required,
          virCPUDataPtr *optional,
          virCPUDataPtr *disabled,
          virCPUDataPtr *forbidden,
          virCPUDataPtr *vendor)
J
Jiri Denemark 已提交
1656
{
1657
    const struct x86_map *map = NULL;
1658 1659 1660 1661 1662 1663
    virCPUx86Data *data_forced = NULL;
    virCPUx86Data *data_required = NULL;
    virCPUx86Data *data_optional = NULL;
    virCPUx86Data *data_disabled = NULL;
    virCPUx86Data *data_forbidden = NULL;
    virCPUx86Data *data_vendor = NULL;
J
Jiri Denemark 已提交
1664

1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677
    if (forced)
        *forced = NULL;
    if (required)
        *required = NULL;
    if (optional)
        *optional = NULL;
    if (disabled)
        *disabled = NULL;
    if (forbidden)
        *forbidden = NULL;
    if (vendor)
        *vendor = NULL;

1678
    if ((map = virCPUx86GetMap()) == NULL)
J
Jiri Denemark 已提交
1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710
        goto error;

    if (forced) {
        data_forced = x86EncodePolicy(cpu, map, VIR_CPU_FEATURE_FORCE);
        if (!data_forced)
            goto error;
    }

    if (required) {
        data_required = x86EncodePolicy(cpu, map, VIR_CPU_FEATURE_REQUIRE);
        if (!data_required)
            goto error;
    }

    if (optional) {
        data_optional = x86EncodePolicy(cpu, map, VIR_CPU_FEATURE_OPTIONAL);
        if (!data_optional)
            goto error;
    }

    if (disabled) {
        data_disabled = x86EncodePolicy(cpu, map, VIR_CPU_FEATURE_DISABLE);
        if (!data_disabled)
            goto error;
    }

    if (forbidden) {
        data_forbidden = x86EncodePolicy(cpu, map, VIR_CPU_FEATURE_FORBID);
        if (!data_forbidden)
            goto error;
    }

J
Jiri Denemark 已提交
1711 1712 1713 1714
    if (vendor) {
        const struct x86_vendor *v = NULL;

        if (cpu->vendor && !(v = x86VendorFind(map, cpu->vendor))) {
1715 1716
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("CPU vendor %s not found"), cpu->vendor);
J
Jiri Denemark 已提交
1717 1718 1719 1720 1721
            goto error;
        }

        if (v &&
            (VIR_ALLOC(data_vendor) < 0 ||
1722
             virCPUx86DataAddCPUID(data_vendor, &v->cpuid) < 0)) {
J
Jiri Denemark 已提交
1723 1724 1725 1726
            goto error;
        }
    }

1727
    if (forced &&
1728
        !(*forced = virCPUx86MakeData(arch, &data_forced)))
1729 1730
        goto error;
    if (required &&
1731
        !(*required = virCPUx86MakeData(arch, &data_required)))
1732 1733
        goto error;
    if (optional &&
1734
        !(*optional = virCPUx86MakeData(arch, &data_optional)))
1735 1736
        goto error;
    if (disabled &&
1737
        !(*disabled = virCPUx86MakeData(arch, &data_disabled)))
1738 1739
        goto error;
    if (forbidden &&
1740
        !(*forbidden = virCPUx86MakeData(arch, &data_forbidden)))
1741 1742
        goto error;
    if (vendor &&
1743
        !(*vendor = virCPUx86MakeData(arch, &data_vendor)))
1744
        goto error;
J
Jiri Denemark 已提交
1745

1746
    return 0;
J
Jiri Denemark 已提交
1747

1748
 error:
1749 1750 1751 1752 1753 1754
    virCPUx86DataFree(data_forced);
    virCPUx86DataFree(data_required);
    virCPUx86DataFree(data_optional);
    virCPUx86DataFree(data_disabled);
    virCPUx86DataFree(data_forbidden);
    virCPUx86DataFree(data_vendor);
1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766
    if (forced)
        x86FreeCPUData(*forced);
    if (required)
        x86FreeCPUData(*required);
    if (optional)
        x86FreeCPUData(*optional);
    if (disabled)
        x86FreeCPUData(*disabled);
    if (forbidden)
        x86FreeCPUData(*forbidden);
    if (vendor)
        x86FreeCPUData(*vendor);
1767
    return -1;
J
Jiri Denemark 已提交
1768 1769 1770 1771 1772
}


#if HAVE_CPUID
static inline void
1773
cpuidCall(virCPUx86CPUID *cpuid)
J
Jiri Denemark 已提交
1774
{
1775
# if __x86_64__
1776 1777 1778 1779
    asm("xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */
        "xor %%ecx, %%ecx;" /* functions may use them as additional */
        "xor %%edx, %%edx;" /* arguments */
        "cpuid;"
J
Jiri Denemark 已提交
1780 1781 1782 1783 1784
        : "=a" (cpuid->eax),
          "=b" (cpuid->ebx),
          "=c" (cpuid->ecx),
          "=d" (cpuid->edx)
        : "a" (cpuid->function));
1785
# else
J
Jiri Denemark 已提交
1786 1787 1788 1789
    /* we need to avoid direct use of ebx for CPUID output as it is used
     * for global offset table on i386 with -fPIC
     */
    asm("push %%ebx;"
1790 1791 1792
        "xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */
        "xor %%ecx, %%ecx;" /* functions may use them as additional */
        "xor %%edx, %%edx;" /* arguments */
J
Jiri Denemark 已提交
1793 1794 1795 1796 1797 1798 1799 1800 1801
        "cpuid;"
        "mov %%ebx, %1;"
        "pop %%ebx;"
        : "=a" (cpuid->eax),
          "=r" (cpuid->ebx),
          "=c" (cpuid->ecx),
          "=d" (cpuid->edx)
        : "a" (cpuid->function)
        : "cc");
1802
# endif
J
Jiri Denemark 已提交
1803 1804 1805 1806
}


static int
1807
cpuidSet(uint32_t base, virCPUx86Data *data)
J
Jiri Denemark 已提交
1808 1809 1810
{
    uint32_t max;
    uint32_t i;
1811
    virCPUx86CPUID cpuid = { base, 0, 0, 0, 0 };
J
Jiri Denemark 已提交
1812 1813

    cpuidCall(&cpuid);
1814
    max = cpuid.eax;
J
Jiri Denemark 已提交
1815

1816 1817
    for (i = base; i <= max; i++) {
        cpuid.function = i;
J
Jiri Denemark 已提交
1818
        cpuidCall(&cpuid);
1819 1820
        if (virCPUx86DataAddCPUID(data, &cpuid) < 0)
            return -1;
J
Jiri Denemark 已提交
1821 1822
    }

1823
    return 0;
J
Jiri Denemark 已提交
1824 1825 1826
}


1827
static virCPUDataPtr
1828
x86NodeData(virArch arch)
J
Jiri Denemark 已提交
1829
{
1830
    virCPUDataPtr cpuData = NULL;
1831
    virCPUx86Data *data;
J
Jiri Denemark 已提交
1832

1833
    if (VIR_ALLOC(data) < 0)
J
Jiri Denemark 已提交
1834 1835
        return NULL;

1836
    if (cpuidSet(CPUX86_BASIC, data) < 0)
J
Jiri Denemark 已提交
1837 1838
        goto error;

1839
    if (cpuidSet(CPUX86_EXTENDED, data) < 0)
J
Jiri Denemark 已提交
1840 1841
        goto error;

1842
    if (!(cpuData = virCPUx86MakeData(arch, &data)))
1843 1844 1845
        goto error;

    return cpuData;
J
Jiri Denemark 已提交
1846

1847
 error:
1848
    virCPUx86DataFree(data);
J
Jiri Denemark 已提交
1849 1850 1851 1852 1853 1854

    return NULL;
}
#endif


1855 1856 1857 1858
static virCPUDefPtr
x86Baseline(virCPUDefPtr *cpus,
            unsigned int ncpus,
            const char **models,
1859 1860
            unsigned int nmodels,
            unsigned int flags)
1861
{
1862
    const struct x86_map *map = NULL;
1863 1864
    struct x86_model *base_model = NULL;
    virCPUDefPtr cpu = NULL;
1865
    size_t i;
J
Jiri Denemark 已提交
1866 1867
    const struct x86_vendor *vendor = NULL;
    struct x86_model *model = NULL;
1868
    bool outputVendor = true;
1869 1870
    const char *modelName;
    bool matchingNames = true;
1871

1872
    if (!(map = virCPUx86GetMap()))
1873 1874
        goto error;

1875
    if (!(base_model = x86ModelFromCPU(cpus[0], map, VIR_CPU_FEATURE_REQUIRE)))
1876 1877
        goto error;

1878
    if (VIR_ALLOC(cpu) < 0)
1879
        goto error;
1880 1881

    cpu->arch = cpus[0]->arch;
1882 1883
    cpu->type = VIR_CPU_TYPE_GUEST;
    cpu->match = VIR_CPU_MATCH_EXACT;
1884

1885 1886 1887
    if (!cpus[0]->vendor)
        outputVendor = false;
    else if (!(vendor = x86VendorFind(map, cpus[0]->vendor))) {
1888 1889
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Unknown CPU vendor %s"), cpus[0]->vendor);
J
Jiri Denemark 已提交
1890 1891 1892
        goto error;
    }

1893
    modelName = cpus[0]->model;
1894
    for (i = 1; i < ncpus; i++) {
J
Jiri Denemark 已提交
1895 1896
        const char *vn = NULL;

1897 1898 1899 1900 1901 1902 1903 1904 1905
        if (matchingNames && cpus[i]->model) {
            if (!modelName) {
                modelName = cpus[i]->model;
            } else if (STRNEQ(modelName, cpus[i]->model)) {
                modelName = NULL;
                matchingNames = false;
            }
        }

1906
        if (!(model = x86ModelFromCPU(cpus[i], map, VIR_CPU_FEATURE_REQUIRE)))
1907 1908
            goto error;

J
Jiri Denemark 已提交
1909 1910
        if (cpus[i]->vendor && model->vendor &&
            STRNEQ(cpus[i]->vendor, model->vendor->name)) {
1911 1912 1913
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("CPU vendor %s of model %s differs from vendor %s"),
                           model->vendor->name, model->name, cpus[i]->vendor);
J
Jiri Denemark 已提交
1914 1915 1916 1917 1918
            goto error;
        }

        if (cpus[i]->vendor)
            vn = cpus[i]->vendor;
1919 1920 1921 1922 1923
        else {
            outputVendor = false;
            if (model->vendor)
                vn = model->vendor->name;
        }
J
Jiri Denemark 已提交
1924 1925 1926 1927

        if (vn) {
            if (!vendor) {
                if (!(vendor = x86VendorFind(map, vn))) {
1928 1929
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("Unknown CPU vendor %s"), vn);
J
Jiri Denemark 已提交
1930 1931 1932
                    goto error;
                }
            } else if (STRNEQ(vendor->name, vn)) {
1933 1934
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("CPU vendors do not match"));
J
Jiri Denemark 已提交
1935 1936 1937 1938
                goto error;
            }
        }

J
Jiri Denemark 已提交
1939
        x86DataIntersect(base_model->data, model->data);
1940
        x86ModelFree(model);
J
Jiri Denemark 已提交
1941
        model = NULL;
1942 1943
    }

J
Jiri Denemark 已提交
1944
    if (x86DataIsEmpty(base_model->data)) {
1945 1946
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("CPUs are incompatible"));
1947 1948 1949
        goto error;
    }

1950
    if (vendor && virCPUx86DataAddCPUID(base_model->data, &vendor->cpuid) < 0)
1951
        goto error;
J
Jiri Denemark 已提交
1952

1953
    if (x86Decode(cpu, base_model->data, models, nmodels, modelName, flags) < 0)
1954 1955
        goto error;

1956 1957 1958
    if (STREQ_NULLABLE(cpu->model, modelName))
        cpu->fallback = VIR_CPU_FALLBACK_FORBID;

1959 1960 1961
    if (!outputVendor)
        VIR_FREE(cpu->vendor);

1962 1963
    cpu->arch = VIR_ARCH_NONE;

1964
 cleanup:
1965 1966 1967 1968
    x86ModelFree(base_model);

    return cpu;

1969
 error:
J
Jiri Denemark 已提交
1970
    x86ModelFree(model);
1971 1972 1973 1974 1975 1976
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
}


1977
static int
1978
x86UpdateCustom(virCPUDefPtr guest,
1979
                const virCPUDef *host)
1980 1981
{
    int ret = -1;
1982
    size_t i;
1983
    const struct x86_map *map;
1984 1985
    struct x86_model *host_model = NULL;

1986
    if (!(map = virCPUx86GetMap()) ||
1987
        !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)))
1988 1989 1990 1991 1992 1993
        goto cleanup;

    for (i = 0; i < guest->nfeatures; i++) {
        if (guest->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) {
            const struct x86_feature *feature;
            if (!(feature = x86FeatureFind(map, guest->features[i].name))) {
1994 1995 1996
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unknown CPU feature %s"),
                               guest->features[i].name);
1997 1998 1999
                goto cleanup;
            }

J
Jiri Denemark 已提交
2000
            if (x86DataIsSubset(host_model->data, feature->data))
2001 2002 2003 2004 2005 2006 2007 2008
                guest->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
            else
                guest->features[i].policy = VIR_CPU_FEATURE_DISABLE;
        }
    }

    if (guest->match == VIR_CPU_MATCH_MINIMUM) {
        guest->match = VIR_CPU_MATCH_EXACT;
P
Peter Krempa 已提交
2009 2010 2011
        if (x86ModelSubtractCPU(host_model, guest, map) ||
            x86DataToCPUFeatures(guest, VIR_CPU_FEATURE_REQUIRE,
                                 host_model->data, map))
2012 2013 2014 2015 2016
            goto cleanup;
    }

    ret = 0;

2017
 cleanup:
2018 2019 2020 2021
    x86ModelFree(host_model);
    return ret;
}

2022 2023 2024

static int
x86UpdateHostModel(virCPUDefPtr guest,
2025
                   const virCPUDef *host)
2026
{
2027
    virCPUDefPtr oldguest = NULL;
2028
    size_t i;
2029
    int ret = -1;
2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040

    guest->match = VIR_CPU_MATCH_EXACT;

    /* no updates are required */
    if (guest->nfeatures == 0) {
        virCPUDefFreeModel(guest);
        return virCPUDefCopyModel(guest, host, true);
    }

    /* update the host model according to the desired configuration */
    if (!(oldguest = virCPUDefCopy(guest)))
2041
        goto cleanup;
2042 2043 2044

    virCPUDefFreeModel(guest);
    if (virCPUDefCopyModel(guest, host, true) < 0)
2045
        goto cleanup;
2046 2047 2048 2049 2050

    for (i = 0; i < oldguest->nfeatures; i++) {
        if (virCPUDefUpdateFeature(guest,
                                   oldguest->features[i].name,
                                   oldguest->features[i].policy) < 0)
2051
            goto cleanup;
2052 2053
    }

2054 2055 2056 2057 2058
    ret = 0;

 cleanup:
    virCPUDefFree(oldguest);
    return ret;
2059 2060 2061
}


2062 2063
static int
x86Update(virCPUDefPtr guest,
2064
          const virCPUDef *host)
2065
{
2066
    switch ((virCPUMode) guest->mode) {
2067 2068 2069 2070
    case VIR_CPU_MODE_CUSTOM:
        return x86UpdateCustom(guest, host);

    case VIR_CPU_MODE_HOST_MODEL:
2071 2072
        return x86UpdateHostModel(guest, host);

2073
    case VIR_CPU_MODE_HOST_PASSTHROUGH:
2074
        guest->match = VIR_CPU_MATCH_MINIMUM;
2075 2076 2077 2078 2079 2080 2081
        virCPUDefFreeModel(guest);
        return virCPUDefCopyModel(guest, host, true);

    case VIR_CPU_MODE_LAST:
        break;
    }

2082 2083
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Unexpected CPU mode: %d"), guest->mode);
2084 2085 2086
    return -1;
}

2087 2088 2089 2090

static int
x86HasFeature(const virCPUData *data,
              const char *name)
D
Daniel P. Berrange 已提交
2091
{
2092
    const struct x86_map *map;
D
Daniel P. Berrange 已提交
2093 2094 2095
    struct x86_feature *feature;
    int ret = -1;

2096
    if (!(map = virCPUx86GetMap()))
D
Daniel P. Berrange 已提交
2097 2098 2099 2100 2101
        return -1;

    if (!(feature = x86FeatureFind(map, name)))
        goto cleanup;

J
Jiri Denemark 已提交
2102
    ret = x86DataIsSubset(data->data.x86, feature->data) ? 1 : 0;
D
Daniel P. Berrange 已提交
2103

2104
 cleanup:
D
Daniel P. Berrange 已提交
2105 2106
    return ret;
}
2107

2108

J
Jiri Denemark 已提交
2109 2110 2111 2112 2113
struct cpuArchDriver cpuDriverX86 = {
    .name = "x86",
    .arch = archs,
    .narch = ARRAY_CARDINALITY(archs),
    .compare    = x86Compare,
2114
    .decode     = x86DecodeCPUData,
J
Jiri Denemark 已提交
2115
    .encode     = x86Encode,
2116
    .free       = x86FreeCPUData,
J
Jiri Denemark 已提交
2117 2118 2119 2120 2121
#if HAVE_CPUID
    .nodeData   = x86NodeData,
#else
    .nodeData   = NULL,
#endif
2122
    .guestData  = x86GuestData,
2123
    .baseline   = x86Baseline,
2124
    .update     = x86Update,
D
Daniel P. Berrange 已提交
2125
    .hasFeature = x86HasFeature,
2126 2127
    .dataFormat = x86CPUDataFormat,
    .dataParse  = x86CPUDataParse,
J
Jiri Denemark 已提交
2128
};