cpu_x86.c 57.2 KB
Newer Older
J
Jiri Denemark 已提交
1 2 3
/*
 * cpu_x86.c: CPU driver for CPUs with x86 compatible CPUID instruction
 *
4
 * Copyright (C) 2009-2014 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

47 48 49
typedef struct _virCPUx86Vendor virCPUx86Vendor;
typedef virCPUx86Vendor *virCPUx86VendorPtr;
struct _virCPUx86Vendor {
J
Jiri Denemark 已提交
50
    char *name;
51
    virCPUx86CPUID cpuid;
J
Jiri Denemark 已提交
52

53
    virCPUx86VendorPtr next;
J
Jiri Denemark 已提交
54 55
};

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

    struct x86_feature *next;
};

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 }},
80 81 82 83 84 85 86 87
    {VIR_CPU_x86_KVM_HV_RUNTIME,   { .function = 0x40000003, .eax = 0x00000001 }},
    {VIR_CPU_x86_KVM_HV_SYNIC,     { .function = 0x40000003, .eax = 0x00000004 }},
    {VIR_CPU_x86_KVM_HV_STIMER,    { .function = 0x40000003, .eax = 0x00000008 }},
    {VIR_CPU_x86_KVM_HV_RELAXED,   { .function = 0x40000003, .eax = 0x00000020 }},
    {VIR_CPU_x86_KVM_HV_SPINLOCK,  { .function = 0x40000003, .eax = 0x00000022 }},
    {VIR_CPU_x86_KVM_HV_VAPIC,     { .function = 0x40000003, .eax = 0x00000030 }},
    {VIR_CPU_x86_KVM_HV_VPINDEX,   { .function = 0x40000003, .eax = 0x00000040 }},
    {VIR_CPU_x86_KVM_HV_RESET,     { .function = 0x40000003, .eax = 0x00000080 }},
88 89
};

J
Jiri Denemark 已提交
90 91
struct x86_model {
    char *name;
92
    virCPUx86VendorPtr vendor;
93
    virCPUx86Data *data;
J
Jiri Denemark 已提交
94 95 96 97 98

    struct x86_model *next;
};

struct x86_map {
99
    virCPUx86VendorPtr vendors;
J
Jiri Denemark 已提交
100 101
    struct x86_feature *features;
    struct x86_model *models;
102
    struct x86_feature *migrate_blockers;
J
Jiri Denemark 已提交
103 104
};

105
static struct x86_map* virCPUx86Map;
106 107 108
int virCPUx86MapOnceInit(void);
VIR_ONCE_GLOBAL_INIT(virCPUx86Map);

J
Jiri Denemark 已提交
109 110 111 112 113 114 115 116 117

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


118
struct virCPUx86DataIterator {
119
    const virCPUx86Data *data;
J
Jiri Denemark 已提交
120 121
    int pos;
};
J
Jiri Denemark 已提交
122 123


124
#define virCPUx86DataIteratorInit(data) \
125
    { data, -1 }
J
Jiri Denemark 已提交
126 127


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


139
static bool
140 141
x86cpuidMatchMasked(const virCPUx86CPUID *cpuid,
                    const virCPUx86CPUID *mask)
J
Jiri Denemark 已提交
142 143 144 145 146 147 148 149
{
    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 已提交
150
static void
151 152
x86cpuidSetBits(virCPUx86CPUID *cpuid,
                const virCPUx86CPUID *mask)
J
Jiri Denemark 已提交
153
{
154 155 156
    if (!mask)
        return;

J
Jiri Denemark 已提交
157 158 159 160 161 162 163
    cpuid->eax |= mask->eax;
    cpuid->ebx |= mask->ebx;
    cpuid->ecx |= mask->ecx;
    cpuid->edx |= mask->edx;
}


J
Jiri Denemark 已提交
164
static void
165 166
x86cpuidClearBits(virCPUx86CPUID *cpuid,
                  const virCPUx86CPUID *mask)
J
Jiri Denemark 已提交
167
{
168 169 170
    if (!mask)
        return;

J
Jiri Denemark 已提交
171 172 173 174 175 176 177
    cpuid->eax &= ~mask->eax;
    cpuid->ebx &= ~mask->ebx;
    cpuid->ecx &= ~mask->ecx;
    cpuid->edx &= ~mask->edx;
}


J
Jiri Denemark 已提交
178
static void
179 180
x86cpuidAndBits(virCPUx86CPUID *cpuid,
                const virCPUx86CPUID *mask)
181
{
182 183 184
    if (!mask)
        return;

185 186 187 188 189 190
    cpuid->eax &= mask->eax;
    cpuid->ebx &= mask->ebx;
    cpuid->ecx &= mask->ecx;
    cpuid->edx &= mask->edx;
}

191 192 193 194 195 196 197 198 199 200 201 202 203 204
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;
}

205

J
Jiri Denemark 已提交
206
/* skips all zero CPUID leafs */
207
static virCPUx86CPUID *
208
x86DataCpuidNext(struct virCPUx86DataIterator *iterator)
J
Jiri Denemark 已提交
209
{
210
    const virCPUx86Data *data = iterator->data;
J
Jiri Denemark 已提交
211

212
    if (!data)
J
Jiri Denemark 已提交
213 214
        return NULL;

215 216 217 218
    while (++iterator->pos < data->len) {
        if (!x86cpuidMatch(data->data + iterator->pos, &cpuidNull))
            return data->data + iterator->pos;
    }
J
Jiri Denemark 已提交
219

220
    return NULL;
J
Jiri Denemark 已提交
221 222 223
}


224
static virCPUx86CPUID *
225
x86DataCpuid(const virCPUx86Data *data,
J
Jiri Denemark 已提交
226 227
             uint32_t function)
{
228
    size_t i;
J
Jiri Denemark 已提交
229

230 231 232
    for (i = 0; i < data->len; i++) {
        if (data->data[i].function == function)
            return data->data + i;
J
Jiri Denemark 已提交
233 234
    }

235
    return NULL;
J
Jiri Denemark 已提交
236 237
}

J
Jiri Denemark 已提交
238
void
239
virCPUx86DataFree(virCPUx86Data *data)
J
Jiri Denemark 已提交
240 241 242 243
{
    if (data == NULL)
        return;

244
    VIR_FREE(data->data);
J
Jiri Denemark 已提交
245 246 247 248
    VIR_FREE(data);
}


J
Jiri Denemark 已提交
249
virCPUDataPtr
250
virCPUx86MakeData(virArch arch, virCPUx86Data **data)
251
{
252
    virCPUDataPtr cpuData;
253 254 255 256

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

J
Jiri Denemark 已提交
257 258
    cpuData->arch = arch;
    cpuData->data.x86 = *data;
259 260 261 262 263 264
    *data = NULL;

    return cpuData;
}

static void
265
x86FreeCPUData(virCPUDataPtr data)
266 267 268 269
{
    if (!data)
        return;

270
    virCPUx86DataFree(data->data.x86);
271 272 273 274
    VIR_FREE(data);
}


275 276
static virCPUx86Data *
x86DataCopy(const virCPUx86Data *data)
J
Jiri Denemark 已提交
277
{
278
    virCPUx86Data *copy = NULL;
279
    size_t i;
J
Jiri Denemark 已提交
280

281 282
    if (VIR_ALLOC(copy) < 0 ||
        VIR_ALLOC_N(copy->data, data->len) < 0) {
283
        virCPUx86DataFree(copy);
J
Jiri Denemark 已提交
284 285 286
        return NULL;
    }

287 288 289
    copy->len = data->len;
    for (i = 0; i < data->len; i++)
        copy->data[i] = data->data[i];
J
Jiri Denemark 已提交
290 291 292 293 294

    return copy;
}


J
Jiri Denemark 已提交
295
int
296 297
virCPUx86DataAddCPUID(virCPUx86Data *data,
                      const virCPUx86CPUID *cpuid)
J
Jiri Denemark 已提交
298
{
299
    virCPUx86CPUID *existing;
J
Jiri Denemark 已提交
300

301 302 303 304 305 306
    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 已提交
307

308 309 310
        qsort(data->data, data->len,
              sizeof(virCPUx86CPUID), virCPUx86CPUIDSorter);
    }
J
Jiri Denemark 已提交
311

J
Jiri Denemark 已提交
312 313 314 315 316
    return 0;
}


static int
317 318
x86DataAdd(virCPUx86Data *data1,
           const virCPUx86Data *data2)
J
Jiri Denemark 已提交
319
{
320 321 322
    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data2);
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
J
Jiri Denemark 已提交
323

324 325
    while ((cpuid2 = x86DataCpuidNext(&iter))) {
        cpuid1 = x86DataCpuid(data1, cpuid2->function);
J
Jiri Denemark 已提交
326

327 328 329 330 331 332
        if (cpuid1) {
            x86cpuidSetBits(cpuid1, cpuid2);
        } else {
            if (virCPUx86DataAddCPUID(data1, cpuid2) < 0)
                return -1;
        }
J
Jiri Denemark 已提交
333
    }
J
Jiri Denemark 已提交
334 335 336 337 338

    return 0;
}


339
static void
340 341
x86DataSubtract(virCPUx86Data *data1,
                const virCPUx86Data *data2)
342
{
343 344 345
    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data1);
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
346

347 348 349
    while ((cpuid1 = x86DataCpuidNext(&iter))) {
        cpuid2 = x86DataCpuid(data2, cpuid1->function);
        x86cpuidClearBits(cpuid1, cpuid2);
350 351 352 353
    }
}


J
Jiri Denemark 已提交
354
static void
355 356
x86DataIntersect(virCPUx86Data *data1,
                 const virCPUx86Data *data2)
357
{
358
    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data1);
359 360
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
361

J
Jiri Denemark 已提交
362 363 364 365 366 367
    while ((cpuid1 = x86DataCpuidNext(&iter))) {
        cpuid2 = x86DataCpuid(data2, cpuid1->function);
        if (cpuid2)
            x86cpuidAndBits(cpuid1, cpuid2);
        else
            x86cpuidClearBits(cpuid1, cpuid1);
368 369 370 371
    }
}


J
Jiri Denemark 已提交
372
static bool
373
x86DataIsEmpty(virCPUx86Data *data)
J
Jiri Denemark 已提交
374
{
375
    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data);
J
Jiri Denemark 已提交
376

377
    return x86DataCpuidNext(&iter) == NULL;
J
Jiri Denemark 已提交
378
}
J
Jiri Denemark 已提交
379 380


J
Jiri Denemark 已提交
381
static bool
382 383
x86DataIsSubset(const virCPUx86Data *data,
                const virCPUx86Data *subset)
J
Jiri Denemark 已提交
384 385
{

386
    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit((virCPUx86Data *)subset);
387 388
    const virCPUx86CPUID *cpuid;
    const virCPUx86CPUID *cpuidSubset;
J
Jiri Denemark 已提交
389

J
Jiri Denemark 已提交
390 391 392 393
    while ((cpuidSubset = x86DataCpuidNext(&iter))) {
        if (!(cpuid = x86DataCpuid(data, cpuidSubset->function)) ||
            !x86cpuidMatchMasked(cpuid, cpuidSubset))
            return false;
J
Jiri Denemark 已提交
394 395
    }

J
Jiri Denemark 已提交
396
    return true;
J
Jiri Denemark 已提交
397 398 399
}


400 401 402 403
/* also removes all detected features from data */
static int
x86DataToCPUFeatures(virCPUDefPtr cpu,
                     int policy,
404
                     virCPUx86Data *data,
405 406 407 408 409
                     const struct x86_map *map)
{
    const struct x86_feature *feature = map->features;

    while (feature != NULL) {
J
Jiri Denemark 已提交
410 411 412 413
        if (x86DataIsSubset(data, feature->data)) {
            x86DataSubtract(data, feature->data);
            if (virCPUDefAddFeature(cpu, feature->name, policy) < 0)
                return -1;
414 415 416 417 418 419 420 421
        }
        feature = feature->next;
    }

    return 0;
}


J
Jiri Denemark 已提交
422
/* also removes bits corresponding to vendor string from data */
423
static virCPUx86VendorPtr
424
x86DataToVendor(virCPUx86Data *data,
J
Jiri Denemark 已提交
425 426
                const struct x86_map *map)
{
427
    virCPUx86VendorPtr vendor = map->vendors;
428
    virCPUx86CPUID *cpuid;
J
Jiri Denemark 已提交
429 430 431 432 433 434 435 436 437 438 439 440 441 442

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

    return NULL;
}


443
static virCPUDefPtr
444
x86DataToCPU(const virCPUx86Data *data,
445 446 447 448
             const struct x86_model *model,
             const struct x86_map *map)
{
    virCPUDefPtr cpu;
449 450
    virCPUx86Data *copy = NULL;
    virCPUx86Data *modelData = NULL;
451
    virCPUx86VendorPtr vendor;
452 453

    if (VIR_ALLOC(cpu) < 0 ||
454
        VIR_STRDUP(cpu->model, model->name) < 0 ||
455
        !(copy = x86DataCopy(data)) ||
J
Jiri Denemark 已提交
456
        !(modelData = x86DataCopy(model->data)))
457
        goto error;
458

J
Jiri Denemark 已提交
459
    if ((vendor = x86DataToVendor(copy, map)) &&
460
        VIR_STRDUP(cpu->vendor, vendor->name) < 0)
461
        goto error;
J
Jiri Denemark 已提交
462

463 464 465 466 467
    x86DataSubtract(copy, modelData);
    x86DataSubtract(modelData, data);

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

469 470
    if (x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_REQUIRE, copy, map) ||
        x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_DISABLE, modelData, map))
471
        goto error;
472

473
 cleanup:
474 475
    virCPUx86DataFree(modelData);
    virCPUx86DataFree(copy);
476 477
    return cpu;

478
 error:
479 480 481 482 483 484
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
}


J
Jiri Denemark 已提交
485
static void
486
x86VendorFree(virCPUx86VendorPtr vendor)
J
Jiri Denemark 已提交
487 488 489 490 491 492
{
    if (!vendor)
        return;

    VIR_FREE(vendor->name);
    VIR_FREE(vendor);
J
Jiri Denemark 已提交
493
}
J
Jiri Denemark 已提交
494 495


496
static virCPUx86VendorPtr
J
Jiri Denemark 已提交
497 498 499
x86VendorFind(const struct x86_map *map,
              const char *name)
{
500
    virCPUx86VendorPtr vendor;
J
Jiri Denemark 已提交
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517

    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)
{
518
    virCPUx86VendorPtr vendor = NULL;
J
Jiri Denemark 已提交
519 520 521 522
    char *string = NULL;
    int ret = 0;

    if (VIR_ALLOC(vendor) < 0)
523
        goto error;
J
Jiri Denemark 已提交
524 525 526

    vendor->name = virXPathString("string(@name)", ctxt);
    if (!vendor->name) {
527 528
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing CPU vendor name"));
J
Jiri Denemark 已提交
529 530 531 532
        goto ignore;
    }

    if (x86VendorFind(map, vendor->name)) {
533 534
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU vendor %s already defined"), vendor->name);
J
Jiri Denemark 已提交
535 536 537 538 539
        goto ignore;
    }

    string = virXPathString("string(@string)", ctxt);
    if (!string) {
540
        virReportError(VIR_ERR_INTERNAL_ERROR,
541 542
                       _("Missing vendor string for CPU vendor %s"),
                       vendor->name);
J
Jiri Denemark 已提交
543 544 545
        goto ignore;
    }
    if (strlen(string) != VENDOR_STRING_LENGTH) {
546 547
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid CPU vendor string '%s'"), string);
J
Jiri Denemark 已提交
548 549 550 551
        goto ignore;
    }

    vendor->cpuid.function = 0;
E
Eric Blake 已提交
552 553 554 555 556
    vendor->cpuid.ebx = virReadBufInt32LE(string);
    vendor->cpuid.edx = virReadBufInt32LE(string + 4);
    vendor->cpuid.ecx = virReadBufInt32LE(string + 8);

    if (!map->vendors) {
J
Jiri Denemark 已提交
557
        map->vendors = vendor;
E
Eric Blake 已提交
558
    } else {
J
Jiri Denemark 已提交
559 560 561 562
        vendor->next = map->vendors;
        map->vendors = vendor;
    }

563
 out:
J
Jiri Denemark 已提交
564 565 566 567
    VIR_FREE(string);

    return ret;

568
 error:
J
Jiri Denemark 已提交
569
    ret = -1;
570
 ignore:
J
Jiri Denemark 已提交
571 572 573 574 575
    x86VendorFree(vendor);
    goto out;
}


J
Jiri Denemark 已提交
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
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 已提交
593 594 595 596 597 598 599
static void
x86FeatureFree(struct x86_feature *feature)
{
    if (feature == NULL)
        return;

    VIR_FREE(feature->name);
600
    virCPUx86DataFree(feature->data);
J
Jiri Denemark 已提交
601 602 603 604
    VIR_FREE(feature);
}


605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
static struct x86_feature *
x86FeatureCopy(const struct x86_feature *src)
{
    struct x86_feature *feature;

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

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

    if ((feature->data = x86DataCopy(src->data)) == NULL)
        goto error;

    return feature;

 error:
    x86FeatureFree(feature);
    return NULL;
}


J
Jiri Denemark 已提交
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
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;
}


645 646 647
static char *
x86FeatureNames(const struct x86_map *map,
                const char *separator,
648
                virCPUx86Data *data)
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
{
    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);
}


673 674
static int
x86ParseCPUID(xmlXPathContextPtr ctxt,
675
              virCPUx86CPUID *cpuid)
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
{
    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 已提交
702 703
static int
x86FeatureLoad(xmlXPathContextPtr ctxt,
J
Jiri Denemark 已提交
704
               struct x86_map *map)
J
Jiri Denemark 已提交
705 706
{
    xmlNodePtr *nodes = NULL;
707
    xmlNodePtr ctxt_node = ctxt->node;
J
Jiri Denemark 已提交
708
    struct x86_feature *feature;
709
    virCPUx86CPUID cpuid;
J
Jiri Denemark 已提交
710
    int ret = 0;
711
    size_t i;
J
Jiri Denemark 已提交
712
    int n;
713 714 715
    char *str = NULL;
    bool migratable = true;
    struct x86_feature *migrate_blocker = NULL;
J
Jiri Denemark 已提交
716

J
Jiri Denemark 已提交
717
    if (!(feature = x86FeatureNew()))
718
        goto error;
J
Jiri Denemark 已提交
719

720
    feature->name = virXPathString("string(@name)", ctxt);
J
Jiri Denemark 已提交
721
    if (feature->name == NULL) {
722 723
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing CPU feature name"));
J
Jiri Denemark 已提交
724 725 726 727
        goto ignore;
    }

    if (x86FeatureFind(map, feature->name)) {
728 729
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU feature %s already defined"), feature->name);
J
Jiri Denemark 已提交
730 731 732
        goto ignore;
    }

733 734 735 736
    str = virXPathString("string(@migratable)", ctxt);
    if (STREQ_NULLABLE(str, "no"))
        migratable = false;

737
    n = virXPathNodeSet("./cpuid", ctxt, &nodes);
J
Jiri Denemark 已提交
738 739 740 741 742
    if (n < 0)
        goto ignore;

    for (i = 0; i < n; i++) {
        ctxt->node = nodes[i];
743
        if (x86ParseCPUID(ctxt, &cpuid) < 0) {
744
            virReportError(VIR_ERR_INTERNAL_ERROR,
745 746
                           _("Invalid cpuid[%zu] in %s feature"),
                           i, feature->name);
J
Jiri Denemark 已提交
747 748
            goto ignore;
        }
749
        if (virCPUx86DataAddCPUID(feature->data, &cpuid))
750
            goto error;
J
Jiri Denemark 已提交
751 752
    }

753 754 755 756 757 758 759 760
    if (!migratable) {
        if ((migrate_blocker = x86FeatureCopy(feature)) == NULL)
            goto error;

        migrate_blocker->next = map->migrate_blockers;
        map->migrate_blockers = migrate_blocker;
    }

761
    if (map->features == NULL) {
J
Jiri Denemark 已提交
762
        map->features = feature;
763
    } else {
J
Jiri Denemark 已提交
764 765 766 767
        feature->next = map->features;
        map->features = feature;
    }

768
 out:
769 770
    ctxt->node = ctxt_node;
    VIR_FREE(nodes);
771
    VIR_FREE(str);
772

J
Jiri Denemark 已提交
773 774
    return ret;

775
 error:
J
Jiri Denemark 已提交
776 777
    ret = -1;

778
 ignore:
J
Jiri Denemark 已提交
779
    x86FeatureFree(feature);
780
    x86FeatureFree(migrate_blocker);
J
Jiri Denemark 已提交
781 782 783 784
    goto out;
}


785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
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;

809
 error:
810 811 812 813 814
    virCPUx86DataFree(data);
    return NULL;
}


J
Jiri Denemark 已提交
815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
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 已提交
832 833 834 835 836 837 838
static void
x86ModelFree(struct x86_model *model)
{
    if (model == NULL)
        return;

    VIR_FREE(model->name);
839
    virCPUx86DataFree(model->data);
J
Jiri Denemark 已提交
840 841 842 843 844 845 846 847 848
    VIR_FREE(model);
}


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

849 850 851
    if (VIR_ALLOC(copy) < 0 ||
        VIR_STRDUP(copy->name, model->name) < 0 ||
        !(copy->data = x86DataCopy(model->data))) {
J
Jiri Denemark 已提交
852 853 854 855
        x86ModelFree(copy);
        return NULL;
    }

J
Jiri Denemark 已提交
856
    copy->vendor = model->vendor;
J
Jiri Denemark 已提交
857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880

    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 *
881
x86ModelFromCPU(const virCPUDef *cpu,
J
Jiri Denemark 已提交
882 883 884 885
                const struct x86_map *map,
                int policy)
{
    struct x86_model *model = NULL;
886
    size_t i;
J
Jiri Denemark 已提交
887

888
    if (policy == VIR_CPU_FEATURE_REQUIRE) {
J
Jiri Denemark 已提交
889
        if ((model = x86ModelFind(map, cpu->model)) == NULL) {
890 891
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU model %s"), cpu->model);
J
Jiri Denemark 已提交
892 893 894 895
            goto error;
        }

        if ((model = x86ModelCopy(model)) == NULL)
896
            goto error;
J
Jiri Denemark 已提交
897
    } else if (!(model = x86ModelNew())) {
898
        goto error;
J
Jiri Denemark 已提交
899
    } else if (cpu->type == VIR_CPU_TYPE_HOST) {
900
        return model;
J
Jiri Denemark 已提交
901
    }
J
Jiri Denemark 已提交
902 903 904 905 906 907 908 909 910

    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) {
911 912
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU feature %s"), cpu->features[i].name);
J
Jiri Denemark 已提交
913 914 915
            goto error;
        }

J
Jiri Denemark 已提交
916
        if (x86DataAdd(model->data, feature->data))
917
            goto error;
J
Jiri Denemark 已提交
918 919 920 921
    }

    return model;

922
 error:
J
Jiri Denemark 已提交
923 924 925 926 927
    x86ModelFree(model);
    return NULL;
}


928 929
static int
x86ModelSubtractCPU(struct x86_model *model,
930
                    const virCPUDef *cpu,
931 932 933
                    const struct x86_map *map)
{
    const struct x86_model *cpu_model;
934
    size_t i;
935 936

    if (!(cpu_model = x86ModelFind(map, cpu->model))) {
937 938 939
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown CPU model %s"),
                       cpu->model);
940 941 942
        return -1;
    }

J
Jiri Denemark 已提交
943
    x86DataSubtract(model->data, cpu_model->data);
944 945 946 947 948

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

        if (!(feature = x86FeatureFind(map, cpu->features[i].name))) {
949 950 951
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU feature %s"),
                           cpu->features[i].name);
952 953 954
            return -1;
        }

J
Jiri Denemark 已提交
955
        x86DataSubtract(model->data, feature->data);
956 957 958 959 960 961
    }

    return 0;
}


J
Jiri Denemark 已提交
962 963 964 965 966
static enum compare_result
x86ModelCompare(const struct x86_model *model1,
                const struct x86_model *model2)
{
    enum compare_result result = EQUAL;
967 968
    struct virCPUx86DataIterator iter1 = virCPUx86DataIteratorInit(model1->data);
    struct virCPUx86DataIterator iter2 = virCPUx86DataIteratorInit(model2->data);
969 970
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
J
Jiri Denemark 已提交
971

J
Jiri Denemark 已提交
972
    while ((cpuid1 = x86DataCpuidNext(&iter1))) {
J
Jiri Denemark 已提交
973 974
        enum compare_result match = SUPERSET;

J
Jiri Denemark 已提交
975
        if ((cpuid2 = x86DataCpuid(model2->data, cpuid1->function))) {
J
Jiri Denemark 已提交
976 977 978 979 980 981 982 983 984 985 986 987
            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 已提交
988
    while ((cpuid2 = x86DataCpuidNext(&iter2))) {
J
Jiri Denemark 已提交
989 990
        enum compare_result match = SUBSET;

J
Jiri Denemark 已提交
991
        if ((cpuid1 = x86DataCpuid(model1->data, cpuid2->function))) {
J
Jiri Denemark 已提交
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
            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 已提交
1010
             struct x86_map *map)
J
Jiri Denemark 已提交
1011 1012
{
    xmlNodePtr *nodes = NULL;
J
Jiri Denemark 已提交
1013
    struct x86_model *model;
J
Jiri Denemark 已提交
1014
    char *vendor = NULL;
J
Jiri Denemark 已提交
1015
    int ret = 0;
1016
    size_t i;
J
Jiri Denemark 已提交
1017 1018
    int n;

J
Jiri Denemark 已提交
1019
    if (!(model = x86ModelNew()))
1020
        goto error;
J
Jiri Denemark 已提交
1021

1022
    model->name = virXPathString("string(@name)", ctxt);
J
Jiri Denemark 已提交
1023
    if (model->name == NULL) {
1024 1025
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing CPU model name"));
J
Jiri Denemark 已提交
1026 1027 1028
        goto ignore;
    }

1029
    if (virXPathNode("./model", ctxt) != NULL) {
J
Jiri Denemark 已提交
1030 1031 1032
        const struct x86_model *ancestor;
        char *name;

1033
        name = virXPathString("string(./model/@name)", ctxt);
J
Jiri Denemark 已提交
1034
        if (name == NULL) {
1035 1036 1037
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing ancestor's name in CPU model %s"),
                           model->name);
J
Jiri Denemark 已提交
1038 1039 1040 1041
            goto ignore;
        }

        if ((ancestor = x86ModelFind(map, name)) == NULL) {
1042 1043 1044
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Ancestor model %s not found for CPU model %s"),
                           name, model->name);
J
Jiri Denemark 已提交
1045 1046 1047 1048 1049 1050
            VIR_FREE(name);
            goto ignore;
        }

        VIR_FREE(name);

J
Jiri Denemark 已提交
1051
        model->vendor = ancestor->vendor;
1052
        virCPUx86DataFree(model->data);
J
Jiri Denemark 已提交
1053
        if (!(model->data = x86DataCopy(ancestor->data)))
1054
            goto error;
J
Jiri Denemark 已提交
1055 1056
    }

1057 1058 1059
    if (virXPathBoolean("boolean(./vendor)", ctxt)) {
        vendor = virXPathString("string(./vendor/@name)", ctxt);
        if (!vendor) {
1060 1061 1062
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid vendor element in CPU model %s"),
                           model->name);
1063 1064 1065
            goto ignore;
        }

J
Jiri Denemark 已提交
1066
        if (!(model->vendor = x86VendorFind(map, vendor))) {
1067 1068 1069
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown vendor %s referenced by CPU model %s"),
                           vendor, model->name);
J
Jiri Denemark 已提交
1070 1071 1072 1073
            goto ignore;
        }
    }

1074
    n = virXPathNodeSet("./feature", ctxt, &nodes);
J
Jiri Denemark 已提交
1075 1076 1077 1078 1079 1080 1081 1082
    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) {
1083 1084
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing feature name for CPU model %s"), model->name);
J
Jiri Denemark 已提交
1085 1086 1087 1088
            goto ignore;
        }

        if ((feature = x86FeatureFind(map, name)) == NULL) {
1089 1090 1091
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Feature %s required by CPU model %s not found"),
                           name, model->name);
J
Jiri Denemark 已提交
1092 1093 1094 1095 1096
            VIR_FREE(name);
            goto ignore;
        }
        VIR_FREE(name);

J
Jiri Denemark 已提交
1097
        if (x86DataAdd(model->data, feature->data))
1098
            goto error;
J
Jiri Denemark 已提交
1099 1100
    }

1101
    if (map->models == NULL) {
J
Jiri Denemark 已提交
1102
        map->models = model;
1103
    } else {
J
Jiri Denemark 已提交
1104 1105 1106 1107
        model->next = map->models;
        map->models = model;
    }

1108
 out:
J
Jiri Denemark 已提交
1109
    VIR_FREE(vendor);
1110
    VIR_FREE(nodes);
J
Jiri Denemark 已提交
1111 1112
    return ret;

1113
 error:
J
Jiri Denemark 已提交
1114 1115
    ret = -1;

1116
 ignore:
J
Jiri Denemark 已提交
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
    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);
    }

1140
    while (map->vendors != NULL) {
1141
        virCPUx86VendorPtr vendor = map->vendors;
1142 1143 1144 1145
        map->vendors = vendor->next;
        x86VendorFree(vendor);
    }

1146 1147 1148 1149 1150 1151
    while (map->migrate_blockers != NULL) {
        struct x86_feature *migrate_blocker = map->migrate_blockers;
        map->migrate_blockers = migrate_blocker->next;
        x86FeatureFree(migrate_blocker);
    }

J
Jiri Denemark 已提交
1152 1153 1154 1155
    VIR_FREE(map);
}


J
Jiri Denemark 已提交
1156
static int
1157
x86MapLoadCallback(cpuMapElement element,
J
Jiri Denemark 已提交
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
                   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;
}


1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
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;

1214
 error:
1215 1216 1217 1218 1219
    x86FeatureFree(feature);
    return -1;
}


J
Jiri Denemark 已提交
1220
static struct x86_map *
1221
virCPUx86LoadMap(void)
J
Jiri Denemark 已提交
1222 1223 1224
{
    struct x86_map *map;

1225
    if (VIR_ALLOC(map) < 0)
J
Jiri Denemark 已提交
1226 1227
        return NULL;

J
Jiri Denemark 已提交
1228
    if (cpuMapLoad("x86", x86MapLoadCallback, map) < 0)
J
Jiri Denemark 已提交
1229 1230
        goto error;

1231 1232 1233
    if (x86MapLoadInternalFeatures(map) < 0)
        goto error;

J
Jiri Denemark 已提交
1234 1235
    return map;

1236
 error:
J
Jiri Denemark 已提交
1237 1238 1239 1240 1241
    x86MapFree(map);
    return NULL;
}


1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
int
virCPUx86MapOnceInit(void)
{
    if (!(virCPUx86Map = virCPUx86LoadMap()))
        return -1;

    return 0;
}


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

    return virCPUx86Map;
}


1262 1263 1264
static char *
x86CPUDataFormat(const virCPUData *data)
{
1265
    struct virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data->data.x86);
1266
    virCPUx86CPUID *cpuid;
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279
    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");

1280
    if (virBufferCheckError(&buf) < 0)
1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
        return NULL;

    return virBufferContentAndReset(&buf);
}


static virCPUDataPtr
x86CPUDataParse(const char *xmlStr)
{
    xmlDocPtr xml = NULL;
    xmlXPathContextPtr ctxt = NULL;
    xmlNodePtr *nodes = NULL;
    virCPUDataPtr cpuData = NULL;
1294
    virCPUx86Data *data = NULL;
1295
    virCPUx86CPUID cpuid;
1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322
    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;
        }
1323
        if (virCPUx86DataAddCPUID(data, &cpuid) < 0)
1324 1325 1326
            goto cleanup;
    }

1327
    cpuData = virCPUx86MakeData(VIR_ARCH_X86_64, &data);
1328

1329
 cleanup:
1330 1331 1332
    VIR_FREE(nodes);
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(xml);
1333
    virCPUx86DataFree(data);
1334 1335 1336 1337
    return cpuData;
}


1338 1339 1340
/* A helper macro to exit the cpu computation function without writing
 * redundant code:
 * MSG: error message
1341
 * CPU_DEF: a virCPUx86Data pointer with flags that are conflicting
1342 1343 1344 1345 1346 1347 1348
 * RET: return code to set
 *
 * This macro generates the error string outputs it into logs.
 */
#define virX86CpuIncompatible(MSG, CPU_DEF)                             \
        do {                                                            \
            char *flagsStr = NULL;                                      \
1349 1350 1351 1352
            if (!(flagsStr = x86FeatureNames(map, ", ", (CPU_DEF)))) {  \
                virReportOOMError();                                    \
                goto error;                                             \
            }                                                           \
1353 1354 1355
            if (message &&                                              \
                virAsprintf(message, "%s: %s", _(MSG), flagsStr) < 0) { \
                VIR_FREE(flagsStr);                                     \
1356
                goto error;                                             \
1357 1358 1359 1360 1361 1362
            }                                                           \
            VIR_DEBUG("%s: %s", MSG, flagsStr);                         \
            VIR_FREE(flagsStr);                                         \
            ret = VIR_CPU_COMPARE_INCOMPATIBLE;                         \
        } while (0)

1363

J
Jiri Denemark 已提交
1364 1365 1366
static virCPUCompareResult
x86Compute(virCPUDefPtr host,
           virCPUDefPtr cpu,
1367
           virCPUDataPtr *guest,
1368
           char **message)
J
Jiri Denemark 已提交
1369
{
1370
    const struct x86_map *map = NULL;
J
Jiri Denemark 已提交
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
    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 已提交
1381
    virArch arch;
1382
    size_t i;
J
Jiri Denemark 已提交
1383

1384 1385 1386 1387 1388 1389
    if (!cpu->model) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("no guest CPU model specified"));
        return VIR_CPU_COMPARE_ERROR;
    }

1390
    if (cpu->arch != VIR_ARCH_NONE) {
J
Jiri Denemark 已提交
1391 1392 1393
        bool found = false;

        for (i = 0; i < ARRAY_CARDINALITY(archs); i++) {
1394
            if (archs[i] == cpu->arch) {
J
Jiri Denemark 已提交
1395 1396 1397 1398 1399
                found = true;
                break;
            }
        }

1400
        if (!found) {
1401 1402
            VIR_DEBUG("CPU arch %s does not match host arch",
                      virArchToString(cpu->arch));
1403 1404 1405
            if (message &&
                virAsprintf(message,
                            _("CPU arch %s does not match host arch"),
1406
                            virArchToString(cpu->arch)) < 0)
1407
                goto error;
J
Jiri Denemark 已提交
1408
            return VIR_CPU_COMPARE_INCOMPATIBLE;
1409
        }
J
Jiri Denemark 已提交
1410 1411 1412
        arch = cpu->arch;
    } else {
        arch = host->arch;
J
Jiri Denemark 已提交
1413 1414
    }

J
Jiri Denemark 已提交
1415 1416 1417 1418
    if (cpu->vendor &&
        (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) {
        VIR_DEBUG("host CPU vendor does not match required CPU vendor %s",
                  cpu->vendor);
1419 1420 1421 1422 1423
        if (message &&
            virAsprintf(message,
                        _("host CPU vendor does not match required "
                          "CPU vendor %s"),
                        cpu->vendor) < 0)
1424
            goto error;
1425

J
Jiri Denemark 已提交
1426 1427 1428
        return VIR_CPU_COMPARE_INCOMPATIBLE;
    }

1429
    if (!(map = virCPUx86GetMap()) ||
1430
        !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)) ||
J
Jiri Denemark 已提交
1431 1432 1433 1434 1435
        !(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 已提交
1436 1437
        goto error;

1438 1439 1440 1441
    x86DataIntersect(cpu_forbid->data, host_model->data);
    if (!x86DataIsEmpty(cpu_forbid->data)) {
        virX86CpuIncompatible(N_("Host CPU provides forbidden features"),
                              cpu_forbid->data);
1442
        goto cleanup;
J
Jiri Denemark 已提交
1443 1444
    }

1445 1446 1447 1448 1449
    /* 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 已提交
1450
    x86DataSubtract(cpu_require->data, cpu_disable->data);
J
Jiri Denemark 已提交
1451 1452
    result = x86ModelCompare(host_model, cpu_require);
    if (result == SUBSET || result == UNRELATED) {
1453 1454 1455 1456
        x86DataSubtract(cpu_require->data, host_model->data);
        virX86CpuIncompatible(N_("Host CPU does not provide required "
                                 "features"),
                              cpu_require->data);
1457
        goto cleanup;
J
Jiri Denemark 已提交
1458 1459 1460 1461
    }

    ret = VIR_CPU_COMPARE_IDENTICAL;

J
Jiri Denemark 已提交
1462
    if ((diff = x86ModelCopy(host_model)) == NULL)
1463
        goto error;
J
Jiri Denemark 已提交
1464

J
Jiri Denemark 已提交
1465 1466 1467 1468
    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 已提交
1469

J
Jiri Denemark 已提交
1470 1471
    if (!x86DataIsEmpty(diff->data))
        ret = VIR_CPU_COMPARE_SUPERSET;
J
Jiri Denemark 已提交
1472 1473 1474 1475

    if (ret == VIR_CPU_COMPARE_SUPERSET
        && cpu->type == VIR_CPU_TYPE_GUEST
        && cpu->match == VIR_CPU_MATCH_STRICT) {
1476 1477 1478
        virX86CpuIncompatible(N_("Host CPU does not strictly match guest CPU: "
                                 "Extra features"),
                              diff->data);
1479
        goto cleanup;
J
Jiri Denemark 已提交
1480 1481 1482
    }

    if (guest != NULL) {
1483
        virCPUx86Data *guestData;
1484

J
Jiri Denemark 已提交
1485
        if ((guest_model = x86ModelCopy(host_model)) == NULL)
1486
            goto error;
J
Jiri Denemark 已提交
1487 1488 1489

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

J
Jiri Denemark 已提交
1492
        if (x86DataAdd(guest_model->data, cpu_force->data))
1493
            goto error;
J
Jiri Denemark 已提交
1494

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

1497
        if (!(guestData = x86DataCopy(guest_model->data)) ||
1498
            !(*guest = virCPUx86MakeData(arch, &guestData))) {
1499
            virCPUx86DataFree(guestData);
1500
            goto error;
1501
        }
J
Jiri Denemark 已提交
1502 1503
    }

1504
 cleanup:
J
Jiri Denemark 已提交
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515
    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;

1516
 error:
J
Jiri Denemark 已提交
1517
    ret = VIR_CPU_COMPARE_ERROR;
1518
    goto cleanup;
J
Jiri Denemark 已提交
1519
}
1520
#undef virX86CpuIncompatible
J
Jiri Denemark 已提交
1521 1522 1523 1524


static virCPUCompareResult
x86Compare(virCPUDefPtr host,
1525
           virCPUDefPtr cpu,
1526
           bool failIncompatible)
J
Jiri Denemark 已提交
1527
{
1528 1529 1530 1531 1532
    virCPUCompareResult ret;
    char *message = NULL;

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

1533
    if (failIncompatible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) {
1534 1535 1536 1537 1538 1539 1540 1541 1542 1543
        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 已提交
1544 1545 1546 1547 1548 1549
}


static virCPUCompareResult
x86GuestData(virCPUDefPtr host,
             virCPUDefPtr guest,
1550
             virCPUDataPtr *data,
1551
             char **message)
J
Jiri Denemark 已提交
1552
{
1553
    return x86Compute(host, guest, data, message);
J
Jiri Denemark 已提交
1554 1555
}

1556

J
Jiri Denemark 已提交
1557 1558
static int
x86Decode(virCPUDefPtr cpu,
1559
          const virCPUx86Data *data,
1560
          const char **models,
1561
          unsigned int nmodels,
1562 1563
          const char *preferred,
          unsigned int flags)
J
Jiri Denemark 已提交
1564 1565
{
    int ret = -1;
1566
    const struct x86_map *map;
J
Jiri Denemark 已提交
1567
    const struct x86_model *candidate;
1568 1569
    virCPUDefPtr cpuCandidate;
    virCPUDefPtr cpuModel = NULL;
1570 1571 1572
    virCPUx86Data *copy = NULL;
    virCPUx86Data *features = NULL;
    const virCPUx86Data *cpuData = NULL;
1573
    size_t i;
J
Jiri Denemark 已提交
1574

1575 1576
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, -1);
1577

1578
    if (!data || !(map = virCPUx86GetMap()))
J
Jiri Denemark 已提交
1579 1580 1581 1582
        return -1;

    candidate = map->models;
    while (candidate != NULL) {
1583
        if (!cpuModelIsAllowed(candidate->name, models, nmodels)) {
1584 1585
            if (preferred && STREQ(candidate->name, preferred)) {
                if (cpu->fallback != VIR_CPU_FALLBACK_ALLOW) {
1586 1587 1588
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("CPU model %s is not supported by hypervisor"),
                                   preferred);
1589 1590 1591 1592 1593 1594 1595 1596 1597 1598
                    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);
            }
1599
            goto next;
J
Jiri Denemark 已提交
1600 1601
        }

1602 1603 1604
        if (!(cpuCandidate = x86DataToCPU(data, candidate, map)))
            goto out;

J
Jiri Denemark 已提交
1605 1606 1607 1608 1609 1610 1611 1612 1613
        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;
        }

1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626
        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;
                }
            }
        }

1627 1628 1629
        if (preferred && STREQ(cpuCandidate->model, preferred)) {
            virCPUDefFree(cpuModel);
            cpuModel = cpuCandidate;
1630
            cpuData = candidate->data;
1631 1632 1633
            break;
        }

1634 1635 1636 1637
        if (cpuModel == NULL
            || cpuModel->nfeatures > cpuCandidate->nfeatures) {
            virCPUDefFree(cpuModel);
            cpuModel = cpuCandidate;
1638 1639
            cpuData = candidate->data;
        } else {
1640
            virCPUDefFree(cpuCandidate);
1641
        }
1642

J
Jiri Denemark 已提交
1643 1644 1645 1646
    next:
        candidate = candidate->next;
    }

1647
    if (cpuModel == NULL) {
1648 1649
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Cannot find suitable CPU model for given data"));
J
Jiri Denemark 已提交
1650 1651 1652
        goto out;
    }

1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
    /* Remove non-migratable features if requested
     * Note: this only works as long as no CPU model contains non-migratable
     * features directly */
    if (flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE) {
        for (i = 0; i < cpuModel->nfeatures; i++) {
            const struct x86_feature *feat;
            for (feat = map->migrate_blockers; feat; feat = feat->next) {
                if (STREQ(feat->name, cpuModel->features[i].name)) {
                    VIR_FREE(cpuModel->features[i].name);
                    VIR_DELETE_ELEMENT_INPLACE(cpuModel->features, i, cpuModel->nfeatures);
                }
            }
        }
    }

1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
    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;
    }

1679
    cpu->model = cpuModel->model;
J
Jiri Denemark 已提交
1680
    cpu->vendor = cpuModel->vendor;
1681 1682 1683
    cpu->nfeatures = cpuModel->nfeatures;
    cpu->features = cpuModel->features;
    VIR_FREE(cpuModel);
J
Jiri Denemark 已提交
1684 1685 1686

    ret = 0;

1687
 out:
1688
    virCPUDefFree(cpuModel);
1689 1690
    virCPUx86DataFree(copy);
    virCPUx86DataFree(features);
J
Jiri Denemark 已提交
1691 1692 1693
    return ret;
}

1694 1695
static int
x86DecodeCPUData(virCPUDefPtr cpu,
1696
                 const virCPUData *data,
1697 1698
                 const char **models,
                 unsigned int nmodels,
1699 1700
                 const char *preferred,
                 unsigned int flags)
1701
{
1702
    return x86Decode(cpu, data->data.x86, models, nmodels, preferred, flags);
1703
}
J
Jiri Denemark 已提交
1704

1705

1706
static virCPUx86Data *
1707
x86EncodePolicy(const virCPUDef *cpu,
J
Jiri Denemark 已提交
1708
                const struct x86_map *map,
1709
                virCPUFeaturePolicy policy)
J
Jiri Denemark 已提交
1710 1711
{
    struct x86_model *model;
1712
    virCPUx86Data *data = NULL;
J
Jiri Denemark 已提交
1713 1714 1715 1716

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

J
Jiri Denemark 已提交
1717 1718
    data = model->data;
    model->data = NULL;
J
Jiri Denemark 已提交
1719 1720 1721 1722 1723 1724 1725
    x86ModelFree(model);

    return data;
}


static int
J
Jiri Denemark 已提交
1726
x86Encode(virArch arch,
1727
          const virCPUDef *cpu,
1728 1729 1730 1731 1732 1733
          virCPUDataPtr *forced,
          virCPUDataPtr *required,
          virCPUDataPtr *optional,
          virCPUDataPtr *disabled,
          virCPUDataPtr *forbidden,
          virCPUDataPtr *vendor)
J
Jiri Denemark 已提交
1734
{
1735
    const struct x86_map *map = NULL;
1736 1737 1738 1739 1740 1741
    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 已提交
1742

1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755
    if (forced)
        *forced = NULL;
    if (required)
        *required = NULL;
    if (optional)
        *optional = NULL;
    if (disabled)
        *disabled = NULL;
    if (forbidden)
        *forbidden = NULL;
    if (vendor)
        *vendor = NULL;

1756
    if ((map = virCPUx86GetMap()) == NULL)
J
Jiri Denemark 已提交
1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788
        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 已提交
1789
    if (vendor) {
1790
        virCPUx86VendorPtr v = NULL;
J
Jiri Denemark 已提交
1791 1792

        if (cpu->vendor && !(v = x86VendorFind(map, cpu->vendor))) {
1793 1794
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("CPU vendor %s not found"), cpu->vendor);
J
Jiri Denemark 已提交
1795 1796 1797 1798 1799
            goto error;
        }

        if (v &&
            (VIR_ALLOC(data_vendor) < 0 ||
1800
             virCPUx86DataAddCPUID(data_vendor, &v->cpuid) < 0)) {
J
Jiri Denemark 已提交
1801 1802 1803 1804
            goto error;
        }
    }

1805
    if (forced &&
1806
        !(*forced = virCPUx86MakeData(arch, &data_forced)))
1807 1808
        goto error;
    if (required &&
1809
        !(*required = virCPUx86MakeData(arch, &data_required)))
1810 1811
        goto error;
    if (optional &&
1812
        !(*optional = virCPUx86MakeData(arch, &data_optional)))
1813 1814
        goto error;
    if (disabled &&
1815
        !(*disabled = virCPUx86MakeData(arch, &data_disabled)))
1816 1817
        goto error;
    if (forbidden &&
1818
        !(*forbidden = virCPUx86MakeData(arch, &data_forbidden)))
1819 1820
        goto error;
    if (vendor &&
1821
        !(*vendor = virCPUx86MakeData(arch, &data_vendor)))
1822
        goto error;
J
Jiri Denemark 已提交
1823

1824
    return 0;
J
Jiri Denemark 已提交
1825

1826
 error:
1827 1828 1829 1830 1831 1832
    virCPUx86DataFree(data_forced);
    virCPUx86DataFree(data_required);
    virCPUx86DataFree(data_optional);
    virCPUx86DataFree(data_disabled);
    virCPUx86DataFree(data_forbidden);
    virCPUx86DataFree(data_vendor);
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844
    if (forced)
        x86FreeCPUData(*forced);
    if (required)
        x86FreeCPUData(*required);
    if (optional)
        x86FreeCPUData(*optional);
    if (disabled)
        x86FreeCPUData(*disabled);
    if (forbidden)
        x86FreeCPUData(*forbidden);
    if (vendor)
        x86FreeCPUData(*vendor);
1845
    return -1;
J
Jiri Denemark 已提交
1846 1847 1848 1849 1850
}


#if HAVE_CPUID
static inline void
1851
cpuidCall(virCPUx86CPUID *cpuid)
J
Jiri Denemark 已提交
1852
{
1853
# if __x86_64__
1854 1855 1856 1857
    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 已提交
1858 1859 1860 1861 1862
        : "=a" (cpuid->eax),
          "=b" (cpuid->ebx),
          "=c" (cpuid->ecx),
          "=d" (cpuid->edx)
        : "a" (cpuid->function));
1863
# else
J
Jiri Denemark 已提交
1864 1865 1866 1867
    /* 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;"
1868 1869 1870
        "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 已提交
1871 1872 1873 1874 1875 1876 1877 1878 1879
        "cpuid;"
        "mov %%ebx, %1;"
        "pop %%ebx;"
        : "=a" (cpuid->eax),
          "=r" (cpuid->ebx),
          "=c" (cpuid->ecx),
          "=d" (cpuid->edx)
        : "a" (cpuid->function)
        : "cc");
1880
# endif
J
Jiri Denemark 已提交
1881 1882 1883 1884
}


static int
1885
cpuidSet(uint32_t base, virCPUx86Data *data)
J
Jiri Denemark 已提交
1886 1887 1888
{
    uint32_t max;
    uint32_t i;
1889
    virCPUx86CPUID cpuid = { base, 0, 0, 0, 0 };
J
Jiri Denemark 已提交
1890 1891

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

1894 1895
    for (i = base; i <= max; i++) {
        cpuid.function = i;
J
Jiri Denemark 已提交
1896
        cpuidCall(&cpuid);
1897 1898
        if (virCPUx86DataAddCPUID(data, &cpuid) < 0)
            return -1;
J
Jiri Denemark 已提交
1899 1900
    }

1901
    return 0;
J
Jiri Denemark 已提交
1902 1903 1904
}


1905
static virCPUDataPtr
1906
x86NodeData(virArch arch)
J
Jiri Denemark 已提交
1907
{
1908
    virCPUDataPtr cpuData = NULL;
1909
    virCPUx86Data *data;
J
Jiri Denemark 已提交
1910

1911
    if (VIR_ALLOC(data) < 0)
J
Jiri Denemark 已提交
1912 1913
        return NULL;

1914
    if (cpuidSet(CPUX86_BASIC, data) < 0)
J
Jiri Denemark 已提交
1915 1916
        goto error;

1917
    if (cpuidSet(CPUX86_EXTENDED, data) < 0)
J
Jiri Denemark 已提交
1918 1919
        goto error;

1920
    if (!(cpuData = virCPUx86MakeData(arch, &data)))
1921 1922 1923
        goto error;

    return cpuData;
J
Jiri Denemark 已提交
1924

1925
 error:
1926
    virCPUx86DataFree(data);
J
Jiri Denemark 已提交
1927 1928 1929 1930 1931 1932

    return NULL;
}
#endif


1933 1934 1935 1936
static virCPUDefPtr
x86Baseline(virCPUDefPtr *cpus,
            unsigned int ncpus,
            const char **models,
1937 1938
            unsigned int nmodels,
            unsigned int flags)
1939
{
1940
    const struct x86_map *map = NULL;
1941 1942
    struct x86_model *base_model = NULL;
    virCPUDefPtr cpu = NULL;
1943
    size_t i;
1944
    virCPUx86VendorPtr vendor = NULL;
J
Jiri Denemark 已提交
1945
    struct x86_model *model = NULL;
1946
    bool outputVendor = true;
1947 1948
    const char *modelName;
    bool matchingNames = true;
1949

1950 1951 1952
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL);

1953
    if (!(map = virCPUx86GetMap()))
1954 1955
        goto error;

1956
    if (!(base_model = x86ModelFromCPU(cpus[0], map, VIR_CPU_FEATURE_REQUIRE)))
1957 1958
        goto error;

1959
    if (VIR_ALLOC(cpu) < 0)
1960
        goto error;
1961 1962

    cpu->arch = cpus[0]->arch;
1963 1964
    cpu->type = VIR_CPU_TYPE_GUEST;
    cpu->match = VIR_CPU_MATCH_EXACT;
1965

1966
    if (!cpus[0]->vendor) {
1967
        outputVendor = false;
1968
    } else if (!(vendor = x86VendorFind(map, cpus[0]->vendor))) {
1969 1970
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Unknown CPU vendor %s"), cpus[0]->vendor);
J
Jiri Denemark 已提交
1971 1972 1973
        goto error;
    }

1974
    modelName = cpus[0]->model;
1975
    for (i = 1; i < ncpus; i++) {
J
Jiri Denemark 已提交
1976 1977
        const char *vn = NULL;

1978 1979 1980 1981 1982 1983 1984 1985 1986
        if (matchingNames && cpus[i]->model) {
            if (!modelName) {
                modelName = cpus[i]->model;
            } else if (STRNEQ(modelName, cpus[i]->model)) {
                modelName = NULL;
                matchingNames = false;
            }
        }

1987
        if (!(model = x86ModelFromCPU(cpus[i], map, VIR_CPU_FEATURE_REQUIRE)))
1988 1989
            goto error;

J
Jiri Denemark 已提交
1990 1991
        if (cpus[i]->vendor && model->vendor &&
            STRNEQ(cpus[i]->vendor, model->vendor->name)) {
1992 1993 1994
            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 已提交
1995 1996 1997
            goto error;
        }

1998
        if (cpus[i]->vendor) {
J
Jiri Denemark 已提交
1999
            vn = cpus[i]->vendor;
2000
        } else {
2001 2002 2003 2004
            outputVendor = false;
            if (model->vendor)
                vn = model->vendor->name;
        }
J
Jiri Denemark 已提交
2005 2006 2007 2008

        if (vn) {
            if (!vendor) {
                if (!(vendor = x86VendorFind(map, vn))) {
2009 2010
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("Unknown CPU vendor %s"), vn);
J
Jiri Denemark 已提交
2011 2012 2013
                    goto error;
                }
            } else if (STRNEQ(vendor->name, vn)) {
2014 2015
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("CPU vendors do not match"));
J
Jiri Denemark 已提交
2016 2017 2018 2019
                goto error;
            }
        }

J
Jiri Denemark 已提交
2020
        x86DataIntersect(base_model->data, model->data);
2021
        x86ModelFree(model);
J
Jiri Denemark 已提交
2022
        model = NULL;
2023 2024
    }

J
Jiri Denemark 已提交
2025
    if (x86DataIsEmpty(base_model->data)) {
2026 2027
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("CPUs are incompatible"));
2028 2029 2030
        goto error;
    }

2031
    if (vendor && virCPUx86DataAddCPUID(base_model->data, &vendor->cpuid) < 0)
2032
        goto error;
J
Jiri Denemark 已提交
2033

2034
    if (x86Decode(cpu, base_model->data, models, nmodels, modelName, flags) < 0)
2035 2036
        goto error;

2037 2038 2039
    if (STREQ_NULLABLE(cpu->model, modelName))
        cpu->fallback = VIR_CPU_FALLBACK_FORBID;

2040 2041 2042
    if (!outputVendor)
        VIR_FREE(cpu->vendor);

2043 2044
    cpu->arch = VIR_ARCH_NONE;

2045
 cleanup:
2046 2047 2048 2049
    x86ModelFree(base_model);

    return cpu;

2050
 error:
J
Jiri Denemark 已提交
2051
    x86ModelFree(model);
2052 2053 2054 2055 2056 2057
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
}


2058
static int
2059
x86UpdateCustom(virCPUDefPtr guest,
2060
                const virCPUDef *host)
2061 2062
{
    int ret = -1;
2063
    size_t i;
2064
    const struct x86_map *map;
2065 2066
    struct x86_model *host_model = NULL;

2067
    if (!(map = virCPUx86GetMap()) ||
2068
        !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)))
2069 2070 2071 2072 2073 2074
        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))) {
2075 2076 2077
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unknown CPU feature %s"),
                               guest->features[i].name);
2078 2079 2080
                goto cleanup;
            }

J
Jiri Denemark 已提交
2081
            if (x86DataIsSubset(host_model->data, feature->data))
2082 2083 2084 2085 2086 2087 2088 2089
                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 已提交
2090 2091 2092
        if (x86ModelSubtractCPU(host_model, guest, map) ||
            x86DataToCPUFeatures(guest, VIR_CPU_FEATURE_REQUIRE,
                                 host_model->data, map))
2093 2094 2095 2096 2097
            goto cleanup;
    }

    ret = 0;

2098
 cleanup:
2099 2100 2101 2102
    x86ModelFree(host_model);
    return ret;
}

2103 2104 2105

static int
x86UpdateHostModel(virCPUDefPtr guest,
2106 2107
                   const virCPUDef *host,
                   bool passthrough)
2108
{
2109
    virCPUDefPtr oldguest = NULL;
2110 2111
    const struct x86_map *map;
    const struct x86_feature *feat;
2112
    size_t i;
2113
    int ret = -1;
2114

2115 2116
    if (!(map = virCPUx86GetMap()))
        goto cleanup;
2117 2118 2119

    /* update the host model according to the desired configuration */
    if (!(oldguest = virCPUDefCopy(guest)))
2120
        goto cleanup;
2121 2122 2123

    virCPUDefFreeModel(guest);
    if (virCPUDefCopyModel(guest, host, true) < 0)
2124
        goto cleanup;
2125

2126 2127 2128 2129 2130 2131
    if (oldguest->vendor_id) {
        VIR_FREE(guest->vendor_id);
        if (VIR_STRDUP(guest->vendor_id, oldguest->vendor_id) < 0)
            goto cleanup;
    }

2132 2133 2134 2135 2136
    /* Remove non-migratable features by default
     * Note: this only works as long as no CPU model contains non-migratable
     * features directly */
    for (i = 0; i < guest->nfeatures; i++) {
        for (feat = map->migrate_blockers; feat; feat = feat->next) {
J
Ján Tomko 已提交
2137 2138
            if (STREQ(feat->name, guest->features[i].name)) {
                VIR_FREE(guest->features[i].name);
2139
                VIR_DELETE_ELEMENT_INPLACE(guest->features, i, guest->nfeatures);
J
Ján Tomko 已提交
2140
            }
2141 2142
        }
    }
2143
    for (i = 0; !passthrough && i < oldguest->nfeatures; i++) {
2144 2145 2146
        if (virCPUDefUpdateFeature(guest,
                                   oldguest->features[i].name,
                                   oldguest->features[i].policy) < 0)
2147
            goto cleanup;
2148 2149
    }

2150 2151 2152 2153 2154
    ret = 0;

 cleanup:
    virCPUDefFree(oldguest);
    return ret;
2155 2156 2157
}


2158 2159
static int
x86Update(virCPUDefPtr guest,
2160
          const virCPUDef *host)
2161
{
2162
    switch ((virCPUMode) guest->mode) {
2163 2164 2165 2166
    case VIR_CPU_MODE_CUSTOM:
        return x86UpdateCustom(guest, host);

    case VIR_CPU_MODE_HOST_MODEL:
2167 2168
        guest->match = VIR_CPU_MATCH_EXACT;
        return x86UpdateHostModel(guest, host, false);
2169

2170
    case VIR_CPU_MODE_HOST_PASSTHROUGH:
2171
        guest->match = VIR_CPU_MATCH_MINIMUM;
2172
        return x86UpdateHostModel(guest, host, true);
2173 2174 2175 2176 2177

    case VIR_CPU_MODE_LAST:
        break;
    }

2178 2179
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Unexpected CPU mode: %d"), guest->mode);
2180 2181 2182
    return -1;
}

2183 2184 2185 2186

static int
x86HasFeature(const virCPUData *data,
              const char *name)
D
Daniel P. Berrange 已提交
2187
{
2188
    const struct x86_map *map;
D
Daniel P. Berrange 已提交
2189 2190 2191
    struct x86_feature *feature;
    int ret = -1;

2192
    if (!(map = virCPUx86GetMap()))
D
Daniel P. Berrange 已提交
2193 2194 2195 2196 2197
        return -1;

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

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

2200
 cleanup:
D
Daniel P. Berrange 已提交
2201 2202
    return ret;
}
2203

2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219
static int
x86GetModels(char ***models)
{
    const struct x86_map *map;
    struct x86_model *model;
    char *name;
    size_t nmodels = 0;

    if (!(map = virCPUx86GetMap()))
        return -1;

    if (models && VIR_ALLOC_N(*models, 0) < 0)
        goto error;

    model = map->models;
    while (model != NULL) {
2220 2221 2222
        if (models) {
            if (VIR_STRDUP(name, model->name) < 0)
                goto error;
2223

2224 2225
            if (VIR_APPEND_ELEMENT(*models, nmodels, name) < 0) {
                VIR_FREE(name);
2226
                goto error;
2227
            }
2228 2229 2230
        } else {
            nmodels++;
        }
2231 2232 2233 2234 2235 2236 2237

        model = model->next;
    }

    return nmodels;

 error:
2238 2239 2240 2241
    if (models) {
        virStringFreeList(*models);
        *models = NULL;
    }
2242 2243 2244
    return -1;
}

2245

J
Jiri Denemark 已提交
2246 2247 2248 2249 2250
struct cpuArchDriver cpuDriverX86 = {
    .name = "x86",
    .arch = archs,
    .narch = ARRAY_CARDINALITY(archs),
    .compare    = x86Compare,
2251
    .decode     = x86DecodeCPUData,
J
Jiri Denemark 已提交
2252
    .encode     = x86Encode,
2253
    .free       = x86FreeCPUData,
J
Jiri Denemark 已提交
2254 2255 2256 2257 2258
#if HAVE_CPUID
    .nodeData   = x86NodeData,
#else
    .nodeData   = NULL,
#endif
2259
    .guestData  = x86GuestData,
2260
    .baseline   = x86Baseline,
2261
    .update     = x86Update,
D
Daniel P. Berrange 已提交
2262
    .hasFeature = x86HasFeature,
2263 2264
    .dataFormat = x86CPUDataFormat,
    .dataParse  = x86CPUDataParse,
2265
    .getModels  = x86GetModels,
J
Jiri Denemark 已提交
2266
};