cpu_x86.c 52.5 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 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
static int
x86MapLoadCallback(enum cpuMapElement element,
                   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 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240
    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");

    if (virBufferError(&buf)) {
        virBufferFreeAndReset(&buf);
        virReportOOMError();
        return NULL;
    }

    return virBufferContentAndReset(&buf);
}


static virCPUDataPtr
x86CPUDataParse(const char *xmlStr)
{
    xmlDocPtr xml = NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlNodePtr *nodes = NULL;
    virCPUDataPtr cpuData = NULL;
1241
    virCPUx86Data *data = NULL;
1242
    virCPUx86CPUID cpuid;
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
    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;
        }
1270
        if (virCPUx86DataAddCPUID(data, &cpuid) < 0)
1271 1272 1273
            goto cleanup;
    }

1274
    cpuData = virCPUx86MakeData(VIR_ARCH_X86_64, &data);
1275

1276
 cleanup:
1277 1278 1279
    VIR_FREE(nodes);
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(xml);
1280
    virCPUx86DataFree(data);
1281 1282 1283 1284
    return cpuData;
}


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

1310

J
Jiri Denemark 已提交
1311 1312 1313
static virCPUCompareResult
x86Compute(virCPUDefPtr host,
           virCPUDefPtr cpu,
1314
           virCPUDataPtr *guest,
1315
           char **message)
J
Jiri Denemark 已提交
1316
{
1317
    const struct x86_map *map = NULL;
J
Jiri Denemark 已提交
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
    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 已提交
1328
    virArch arch;
1329
    size_t i;
J
Jiri Denemark 已提交
1330

1331
    if (cpu->arch != VIR_ARCH_NONE) {
J
Jiri Denemark 已提交
1332 1333 1334
        bool found = false;

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

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

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

J
Jiri Denemark 已提交
1367 1368 1369
        return VIR_CPU_COMPARE_INCOMPATIBLE;
    }

1370
    if (!(map = virCPUx86GetMap()) ||
1371
        !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)) ||
J
Jiri Denemark 已提交
1372 1373 1374 1375 1376
        !(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 已提交
1377 1378
        goto error;

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

1386 1387 1388 1389 1390
    /* 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 已提交
1391
    x86DataSubtract(cpu_require->data, cpu_disable->data);
J
Jiri Denemark 已提交
1392 1393
    result = x86ModelCompare(host_model, cpu_require);
    if (result == SUBSET || result == UNRELATED) {
1394 1395 1396 1397
        x86DataSubtract(cpu_require->data, host_model->data);
        virX86CpuIncompatible(N_("Host CPU does not provide required "
                                 "features"),
                              cpu_require->data);
1398
        goto cleanup;
J
Jiri Denemark 已提交
1399 1400 1401 1402
    }

    ret = VIR_CPU_COMPARE_IDENTICAL;

J
Jiri Denemark 已提交
1403
    if ((diff = x86ModelCopy(host_model)) == NULL)
1404
        goto error;
J
Jiri Denemark 已提交
1405

J
Jiri Denemark 已提交
1406 1407 1408 1409
    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 已提交
1410

J
Jiri Denemark 已提交
1411 1412
    if (!x86DataIsEmpty(diff->data))
        ret = VIR_CPU_COMPARE_SUPERSET;
J
Jiri Denemark 已提交
1413 1414 1415 1416

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

    if (guest != NULL) {
1424
        virCPUx86Data *guestData;
1425

J
Jiri Denemark 已提交
1426
        if ((guest_model = x86ModelCopy(host_model)) == NULL)
1427
            goto error;
J
Jiri Denemark 已提交
1428 1429 1430

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

J
Jiri Denemark 已提交
1433
        if (x86DataAdd(guest_model->data, cpu_force->data))
1434
            goto error;
J
Jiri Denemark 已提交
1435

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

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

1445
 cleanup:
J
Jiri Denemark 已提交
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456
    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;

1457
 error:
J
Jiri Denemark 已提交
1458
    ret = VIR_CPU_COMPARE_ERROR;
1459
    goto cleanup;
J
Jiri Denemark 已提交
1460
}
1461
#undef virX86CpuIncompatible
J
Jiri Denemark 已提交
1462 1463 1464 1465 1466 1467


static virCPUCompareResult
x86Compare(virCPUDefPtr host,
           virCPUDefPtr cpu)
{
1468
    return x86Compute(host, cpu, NULL, NULL);
J
Jiri Denemark 已提交
1469 1470 1471 1472 1473 1474
}


static virCPUCompareResult
x86GuestData(virCPUDefPtr host,
             virCPUDefPtr guest,
1475
             virCPUDataPtr *data,
1476
             char **message)
J
Jiri Denemark 已提交
1477
{
1478
    return x86Compute(host, guest, data, message);
J
Jiri Denemark 已提交
1479 1480
}

1481

J
Jiri Denemark 已提交
1482 1483
static int
x86Decode(virCPUDefPtr cpu,
1484
          const virCPUx86Data *data,
1485
          const char **models,
1486
          unsigned int nmodels,
1487 1488
          const char *preferred,
          unsigned int flags)
J
Jiri Denemark 已提交
1489 1490
{
    int ret = -1;
1491
    const struct x86_map *map;
J
Jiri Denemark 已提交
1492
    const struct x86_model *candidate;
1493 1494
    virCPUDefPtr cpuCandidate;
    virCPUDefPtr cpuModel = NULL;
1495 1496 1497
    virCPUx86Data *copy = NULL;
    virCPUx86Data *features = NULL;
    const virCPUx86Data *cpuData = NULL;
1498
    size_t i;
J
Jiri Denemark 已提交
1499

1500 1501
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1);

1502
    if (!data || !(map = virCPUx86GetMap()))
J
Jiri Denemark 已提交
1503 1504 1505 1506
        return -1;

    candidate = map->models;
    while (candidate != NULL) {
1507
        if (!cpuModelIsAllowed(candidate->name, models, nmodels)) {
1508 1509
            if (preferred && STREQ(candidate->name, preferred)) {
                if (cpu->fallback != VIR_CPU_FALLBACK_ALLOW) {
1510 1511 1512
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("CPU model %s is not supported by hypervisor"),
                                   preferred);
1513 1514 1515 1516 1517 1518 1519 1520 1521 1522
                    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);
            }
1523
            goto next;
J
Jiri Denemark 已提交
1524 1525
        }

1526 1527 1528
        if (!(cpuCandidate = x86DataToCPU(data, candidate, map)))
            goto out;

J
Jiri Denemark 已提交
1529 1530 1531 1532 1533 1534 1535 1536 1537
        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;
        }

1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550
        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;
                }
            }
        }

1551 1552 1553
        if (preferred && STREQ(cpuCandidate->model, preferred)) {
            virCPUDefFree(cpuModel);
            cpuModel = cpuCandidate;
1554
            cpuData = candidate->data;
1555 1556 1557
            break;
        }

1558 1559 1560 1561
        if (cpuModel == NULL
            || cpuModel->nfeatures > cpuCandidate->nfeatures) {
            virCPUDefFree(cpuModel);
            cpuModel = cpuCandidate;
1562 1563
            cpuData = candidate->data;
        } else {
1564
            virCPUDefFree(cpuCandidate);
1565
        }
1566

J
Jiri Denemark 已提交
1567 1568 1569 1570
    next:
        candidate = candidate->next;
    }

1571
    if (cpuModel == NULL) {
1572 1573
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Cannot find suitable CPU model for given data"));
J
Jiri Denemark 已提交
1574 1575 1576
        goto out;
    }

1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587
    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;
    }

1588
    cpu->model = cpuModel->model;
J
Jiri Denemark 已提交
1589
    cpu->vendor = cpuModel->vendor;
1590 1591 1592
    cpu->nfeatures = cpuModel->nfeatures;
    cpu->features = cpuModel->features;
    VIR_FREE(cpuModel);
J
Jiri Denemark 已提交
1593 1594 1595

    ret = 0;

1596
 out:
1597
    virCPUDefFree(cpuModel);
1598 1599
    virCPUx86DataFree(copy);
    virCPUx86DataFree(features);
J
Jiri Denemark 已提交
1600 1601 1602
    return ret;
}

1603 1604
static int
x86DecodeCPUData(virCPUDefPtr cpu,
1605
                 const virCPUData *data,
1606 1607
                 const char **models,
                 unsigned int nmodels,
1608 1609
                 const char *preferred,
                 unsigned int flags)
1610
{
1611
    return x86Decode(cpu, data->data.x86, models, nmodels, preferred, flags);
1612
}
J
Jiri Denemark 已提交
1613

1614

1615
static virCPUx86Data *
1616
x86EncodePolicy(const virCPUDef *cpu,
J
Jiri Denemark 已提交
1617
                const struct x86_map *map,
1618
                virCPUFeaturePolicy policy)
J
Jiri Denemark 已提交
1619 1620
{
    struct x86_model *model;
1621
    virCPUx86Data *data = NULL;
J
Jiri Denemark 已提交
1622 1623 1624 1625

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

J
Jiri Denemark 已提交
1626 1627
    data = model->data;
    model->data = NULL;
J
Jiri Denemark 已提交
1628 1629 1630 1631 1632 1633 1634
    x86ModelFree(model);

    return data;
}


static int
J
Jiri Denemark 已提交
1635
x86Encode(virArch arch,
1636
          const virCPUDef *cpu,
1637 1638 1639 1640 1641 1642
          virCPUDataPtr *forced,
          virCPUDataPtr *required,
          virCPUDataPtr *optional,
          virCPUDataPtr *disabled,
          virCPUDataPtr *forbidden,
          virCPUDataPtr *vendor)
J
Jiri Denemark 已提交
1643
{
1644
    const struct x86_map *map = NULL;
1645 1646 1647 1648 1649 1650
    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 已提交
1651

1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664
    if (forced)
        *forced = NULL;
    if (required)
        *required = NULL;
    if (optional)
        *optional = NULL;
    if (disabled)
        *disabled = NULL;
    if (forbidden)
        *forbidden = NULL;
    if (vendor)
        *vendor = NULL;

1665
    if ((map = virCPUx86GetMap()) == NULL)
J
Jiri Denemark 已提交
1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697
        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 已提交
1698 1699 1700 1701
    if (vendor) {
        const struct x86_vendor *v = NULL;

        if (cpu->vendor && !(v = x86VendorFind(map, cpu->vendor))) {
1702 1703
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("CPU vendor %s not found"), cpu->vendor);
J
Jiri Denemark 已提交
1704 1705 1706 1707 1708
            goto error;
        }

        if (v &&
            (VIR_ALLOC(data_vendor) < 0 ||
1709
             virCPUx86DataAddCPUID(data_vendor, &v->cpuid) < 0)) {
J
Jiri Denemark 已提交
1710 1711 1712 1713
            goto error;
        }
    }

1714
    if (forced &&
1715
        !(*forced = virCPUx86MakeData(arch, &data_forced)))
1716 1717
        goto error;
    if (required &&
1718
        !(*required = virCPUx86MakeData(arch, &data_required)))
1719 1720
        goto error;
    if (optional &&
1721
        !(*optional = virCPUx86MakeData(arch, &data_optional)))
1722 1723
        goto error;
    if (disabled &&
1724
        !(*disabled = virCPUx86MakeData(arch, &data_disabled)))
1725 1726
        goto error;
    if (forbidden &&
1727
        !(*forbidden = virCPUx86MakeData(arch, &data_forbidden)))
1728 1729
        goto error;
    if (vendor &&
1730
        !(*vendor = virCPUx86MakeData(arch, &data_vendor)))
1731
        goto error;
J
Jiri Denemark 已提交
1732

1733
    return 0;
J
Jiri Denemark 已提交
1734

1735
 error:
1736 1737 1738 1739 1740 1741
    virCPUx86DataFree(data_forced);
    virCPUx86DataFree(data_required);
    virCPUx86DataFree(data_optional);
    virCPUx86DataFree(data_disabled);
    virCPUx86DataFree(data_forbidden);
    virCPUx86DataFree(data_vendor);
1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753
    if (forced)
        x86FreeCPUData(*forced);
    if (required)
        x86FreeCPUData(*required);
    if (optional)
        x86FreeCPUData(*optional);
    if (disabled)
        x86FreeCPUData(*disabled);
    if (forbidden)
        x86FreeCPUData(*forbidden);
    if (vendor)
        x86FreeCPUData(*vendor);
1754
    return -1;
J
Jiri Denemark 已提交
1755 1756 1757 1758 1759
}


#if HAVE_CPUID
static inline void
1760
cpuidCall(virCPUx86CPUID *cpuid)
J
Jiri Denemark 已提交
1761
{
1762
# if __x86_64__
1763 1764 1765 1766
    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 已提交
1767 1768 1769 1770 1771
        : "=a" (cpuid->eax),
          "=b" (cpuid->ebx),
          "=c" (cpuid->ecx),
          "=d" (cpuid->edx)
        : "a" (cpuid->function));
1772
# else
J
Jiri Denemark 已提交
1773 1774 1775 1776
    /* 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;"
1777 1778 1779
        "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 已提交
1780 1781 1782 1783 1784 1785 1786 1787 1788
        "cpuid;"
        "mov %%ebx, %1;"
        "pop %%ebx;"
        : "=a" (cpuid->eax),
          "=r" (cpuid->ebx),
          "=c" (cpuid->ecx),
          "=d" (cpuid->edx)
        : "a" (cpuid->function)
        : "cc");
1789
# endif
J
Jiri Denemark 已提交
1790 1791 1792 1793
}


static int
1794
cpuidSet(uint32_t base, virCPUx86Data *data)
J
Jiri Denemark 已提交
1795 1796 1797
{
    uint32_t max;
    uint32_t i;
1798
    virCPUx86CPUID cpuid = { base, 0, 0, 0, 0 };
J
Jiri Denemark 已提交
1799 1800

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

1803 1804
    for (i = base; i <= max; i++) {
        cpuid.function = i;
J
Jiri Denemark 已提交
1805
        cpuidCall(&cpuid);
1806 1807
        if (virCPUx86DataAddCPUID(data, &cpuid) < 0)
            return -1;
J
Jiri Denemark 已提交
1808 1809
    }

1810
    return 0;
J
Jiri Denemark 已提交
1811 1812 1813
}


1814
static virCPUDataPtr
1815
x86NodeData(virArch arch)
J
Jiri Denemark 已提交
1816
{
1817
    virCPUDataPtr cpuData = NULL;
1818
    virCPUx86Data *data;
J
Jiri Denemark 已提交
1819

1820
    if (VIR_ALLOC(data) < 0)
J
Jiri Denemark 已提交
1821 1822
        return NULL;

1823
    if (cpuidSet(CPUX86_BASIC, data) < 0)
J
Jiri Denemark 已提交
1824 1825
        goto error;

1826
    if (cpuidSet(CPUX86_EXTENDED, data) < 0)
J
Jiri Denemark 已提交
1827 1828
        goto error;

1829
    if (!(cpuData = virCPUx86MakeData(arch, &data)))
1830 1831 1832
        goto error;

    return cpuData;
J
Jiri Denemark 已提交
1833

1834
 error:
1835
    virCPUx86DataFree(data);
J
Jiri Denemark 已提交
1836 1837 1838 1839 1840 1841

    return NULL;
}
#endif


1842 1843 1844 1845
static virCPUDefPtr
x86Baseline(virCPUDefPtr *cpus,
            unsigned int ncpus,
            const char **models,
1846 1847
            unsigned int nmodels,
            unsigned int flags)
1848
{
1849
    const struct x86_map *map = NULL;
1850 1851
    struct x86_model *base_model = NULL;
    virCPUDefPtr cpu = NULL;
1852
    size_t i;
J
Jiri Denemark 已提交
1853 1854
    const struct x86_vendor *vendor = NULL;
    struct x86_model *model = NULL;
1855
    bool outputVendor = true;
1856 1857
    const char *modelName;
    bool matchingNames = true;
1858

1859
    if (!(map = virCPUx86GetMap()))
1860 1861
        goto error;

1862
    if (!(base_model = x86ModelFromCPU(cpus[0], map, VIR_CPU_FEATURE_REQUIRE)))
1863 1864
        goto error;

1865
    if (VIR_ALLOC(cpu) < 0)
1866
        goto error;
1867 1868

    cpu->arch = cpus[0]->arch;
1869 1870
    cpu->type = VIR_CPU_TYPE_GUEST;
    cpu->match = VIR_CPU_MATCH_EXACT;
1871

1872 1873 1874
    if (!cpus[0]->vendor)
        outputVendor = false;
    else if (!(vendor = x86VendorFind(map, cpus[0]->vendor))) {
1875 1876
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Unknown CPU vendor %s"), cpus[0]->vendor);
J
Jiri Denemark 已提交
1877 1878 1879
        goto error;
    }

1880
    modelName = cpus[0]->model;
1881
    for (i = 1; i < ncpus; i++) {
J
Jiri Denemark 已提交
1882 1883
        const char *vn = NULL;

1884 1885 1886 1887 1888 1889 1890 1891 1892
        if (matchingNames && cpus[i]->model) {
            if (!modelName) {
                modelName = cpus[i]->model;
            } else if (STRNEQ(modelName, cpus[i]->model)) {
                modelName = NULL;
                matchingNames = false;
            }
        }

1893
        if (!(model = x86ModelFromCPU(cpus[i], map, VIR_CPU_FEATURE_REQUIRE)))
1894 1895
            goto error;

J
Jiri Denemark 已提交
1896 1897
        if (cpus[i]->vendor && model->vendor &&
            STRNEQ(cpus[i]->vendor, model->vendor->name)) {
1898 1899 1900
            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 已提交
1901 1902 1903 1904 1905
            goto error;
        }

        if (cpus[i]->vendor)
            vn = cpus[i]->vendor;
1906 1907 1908 1909 1910
        else {
            outputVendor = false;
            if (model->vendor)
                vn = model->vendor->name;
        }
J
Jiri Denemark 已提交
1911 1912 1913 1914

        if (vn) {
            if (!vendor) {
                if (!(vendor = x86VendorFind(map, vn))) {
1915 1916
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("Unknown CPU vendor %s"), vn);
J
Jiri Denemark 已提交
1917 1918 1919
                    goto error;
                }
            } else if (STRNEQ(vendor->name, vn)) {
1920 1921
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("CPU vendors do not match"));
J
Jiri Denemark 已提交
1922 1923 1924 1925
                goto error;
            }
        }

J
Jiri Denemark 已提交
1926
        x86DataIntersect(base_model->data, model->data);
1927
        x86ModelFree(model);
J
Jiri Denemark 已提交
1928
        model = NULL;
1929 1930
    }

J
Jiri Denemark 已提交
1931
    if (x86DataIsEmpty(base_model->data)) {
1932 1933
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("CPUs are incompatible"));
1934 1935 1936
        goto error;
    }

1937
    if (vendor && virCPUx86DataAddCPUID(base_model->data, &vendor->cpuid) < 0)
1938
        goto error;
J
Jiri Denemark 已提交
1939

1940
    if (x86Decode(cpu, base_model->data, models, nmodels, modelName, flags) < 0)
1941 1942
        goto error;

1943 1944 1945
    if (STREQ_NULLABLE(cpu->model, modelName))
        cpu->fallback = VIR_CPU_FALLBACK_FORBID;

1946 1947 1948
    if (!outputVendor)
        VIR_FREE(cpu->vendor);

1949 1950
    cpu->arch = VIR_ARCH_NONE;

1951
 cleanup:
1952 1953 1954 1955
    x86ModelFree(base_model);

    return cpu;

1956
 error:
J
Jiri Denemark 已提交
1957
    x86ModelFree(model);
1958 1959 1960 1961 1962 1963
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
}


1964
static int
1965
x86UpdateCustom(virCPUDefPtr guest,
1966
                const virCPUDef *host)
1967 1968
{
    int ret = -1;
1969
    size_t i;
1970
    const struct x86_map *map;
1971 1972
    struct x86_model *host_model = NULL;

1973
    if (!(map = virCPUx86GetMap()) ||
1974
        !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)))
1975 1976 1977 1978 1979 1980
        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))) {
1981 1982 1983
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unknown CPU feature %s"),
                               guest->features[i].name);
1984 1985 1986
                goto cleanup;
            }

J
Jiri Denemark 已提交
1987
            if (x86DataIsSubset(host_model->data, feature->data))
1988 1989 1990 1991 1992 1993 1994 1995
                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 已提交
1996 1997 1998
        if (x86ModelSubtractCPU(host_model, guest, map) ||
            x86DataToCPUFeatures(guest, VIR_CPU_FEATURE_REQUIRE,
                                 host_model->data, map))
1999 2000 2001 2002 2003
            goto cleanup;
    }

    ret = 0;

2004
 cleanup:
2005 2006 2007 2008
    x86ModelFree(host_model);
    return ret;
}

2009 2010 2011

static int
x86UpdateHostModel(virCPUDefPtr guest,
2012
                   const virCPUDef *host)
2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043
{
    virCPUDefPtr oldguest;
    size_t i;

    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)))
        return -1;

    virCPUDefFreeModel(guest);
    if (virCPUDefCopyModel(guest, host, true) < 0)
        return -1;

    for (i = 0; i < oldguest->nfeatures; i++) {
        if (virCPUDefUpdateFeature(guest,
                                   oldguest->features[i].name,
                                   oldguest->features[i].policy) < 0)
            return -1;
    }

    return 0;
}


2044 2045
static int
x86Update(virCPUDefPtr guest,
2046
          const virCPUDef *host)
2047
{
2048
    switch ((virCPUMode) guest->mode) {
2049 2050 2051 2052
    case VIR_CPU_MODE_CUSTOM:
        return x86UpdateCustom(guest, host);

    case VIR_CPU_MODE_HOST_MODEL:
2053 2054
        return x86UpdateHostModel(guest, host);

2055
    case VIR_CPU_MODE_HOST_PASSTHROUGH:
2056
        guest->match = VIR_CPU_MATCH_MINIMUM;
2057 2058 2059 2060 2061 2062 2063
        virCPUDefFreeModel(guest);
        return virCPUDefCopyModel(guest, host, true);

    case VIR_CPU_MODE_LAST:
        break;
    }

2064 2065
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Unexpected CPU mode: %d"), guest->mode);
2066 2067 2068
    return -1;
}

2069 2070 2071 2072

static int
x86HasFeature(const virCPUData *data,
              const char *name)
D
Daniel P. Berrange 已提交
2073
{
2074
    const struct x86_map *map;
D
Daniel P. Berrange 已提交
2075 2076 2077
    struct x86_feature *feature;
    int ret = -1;

2078
    if (!(map = virCPUx86GetMap()))
D
Daniel P. Berrange 已提交
2079 2080 2081 2082 2083
        return -1;

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

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

2086
 cleanup:
D
Daniel P. Berrange 已提交
2087 2088
    return ret;
}
2089

2090

J
Jiri Denemark 已提交
2091 2092 2093 2094 2095
struct cpuArchDriver cpuDriverX86 = {
    .name = "x86",
    .arch = archs,
    .narch = ARRAY_CARDINALITY(archs),
    .compare    = x86Compare,
2096
    .decode     = x86DecodeCPUData,
J
Jiri Denemark 已提交
2097
    .encode     = x86Encode,
2098
    .free       = x86FreeCPUData,
J
Jiri Denemark 已提交
2099 2100 2101 2102 2103
#if HAVE_CPUID
    .nodeData   = x86NodeData,
#else
    .nodeData   = NULL,
#endif
2104
    .guestData  = x86GuestData,
2105
    .baseline   = x86Baseline,
2106
    .update     = x86Update,
D
Daniel P. Berrange 已提交
2107
    .hasFeature = x86HasFeature,
2108 2109
    .dataFormat = x86CPUDataFormat,
    .dataParse  = x86CPUDataParse,
J
Jiri Denemark 已提交
2110
};