cpu_x86.c 58.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 };
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
};

54 55 56
typedef struct _virCPUx86Feature virCPUx86Feature;
typedef virCPUx86Feature *virCPUx86FeaturePtr;
struct _virCPUx86Feature {
J
Jiri Denemark 已提交
57
    char *name;
58
    virCPUx86Data data;
J
Jiri Denemark 已提交
59
    bool migratable;
J
Jiri Denemark 已提交
60 61
};

62

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
#define KVM_FEATURE_DEF(Name, Eax_in, Eax)                          \
    static virCPUx86CPUID Name ## _cpuid[] = {                      \
        { .eax_in = Eax_in, .eax = Eax },                           \
    }

#define KVM_FEATURE(Name)                                           \
    {                                                               \
        .name = (char *) Name,                                      \
        .data = {                                                   \
            .len = ARRAY_CARDINALITY(Name ## _cpuid),               \
            .data = Name ## _cpuid                                  \
        }                                                           \
    }

KVM_FEATURE_DEF(VIR_CPU_x86_KVM_CLOCKSOURCE,
                0x40000001, 0x00000001);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_NOP_IO_DELAY,
                0x40000001, 0x00000002);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_MMU_OP,
                0x40000001, 0x00000004);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_CLOCKSOURCE2,
                0x40000001, 0x00000008);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_ASYNC_PF,
                0x40000001, 0x00000010);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_STEAL_TIME,
                0x40000001, 0x00000020);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_PV_EOI,
                0x40000001, 0x00000040);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_PV_UNHALT,
                0x40000001, 0x00000080);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_CLOCKSOURCE_STABLE_BIT,
                0x40000001, 0x01000000);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_RUNTIME,
                0x40000003, 0x00000001);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_SYNIC,
                0x40000003, 0x00000004);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_STIMER,
                0x40000003, 0x00000008);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_RELAXED,
                0x40000003, 0x00000020);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_SPINLOCK,
                0x40000003, 0x00000022);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_VAPIC,
                0x40000003, 0x00000030);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_VPINDEX,
                0x40000003, 0x00000040);
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_RESET,
                0x40000003, 0x00000080);

static virCPUx86Feature x86_kvm_features[] =
{
    KVM_FEATURE(VIR_CPU_x86_KVM_CLOCKSOURCE),
    KVM_FEATURE(VIR_CPU_x86_KVM_NOP_IO_DELAY),
    KVM_FEATURE(VIR_CPU_x86_KVM_MMU_OP),
    KVM_FEATURE(VIR_CPU_x86_KVM_CLOCKSOURCE2),
    KVM_FEATURE(VIR_CPU_x86_KVM_ASYNC_PF),
    KVM_FEATURE(VIR_CPU_x86_KVM_STEAL_TIME),
    KVM_FEATURE(VIR_CPU_x86_KVM_PV_EOI),
    KVM_FEATURE(VIR_CPU_x86_KVM_PV_UNHALT),
    KVM_FEATURE(VIR_CPU_x86_KVM_CLOCKSOURCE_STABLE_BIT),
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_RUNTIME),
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_SYNIC),
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_STIMER),
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_RELAXED),
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_SPINLOCK),
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_VAPIC),
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_VPINDEX),
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_RESET),
131 132
};

J
Jiri Denemark 已提交
133 134 135
typedef struct _virCPUx86Model virCPUx86Model;
typedef virCPUx86Model *virCPUx86ModelPtr;
struct _virCPUx86Model {
J
Jiri Denemark 已提交
136
    char *name;
137
    virCPUx86VendorPtr vendor;
138
    virCPUx86Data data;
J
Jiri Denemark 已提交
139 140
};

J
Jiri Denemark 已提交
141 142 143
typedef struct _virCPUx86Map virCPUx86Map;
typedef virCPUx86Map *virCPUx86MapPtr;
struct _virCPUx86Map {
144 145
    size_t nvendors;
    virCPUx86VendorPtr *vendors;
146 147
    size_t nfeatures;
    virCPUx86FeaturePtr *features;
148 149
    size_t nmodels;
    virCPUx86ModelPtr *models;
150 151
    size_t nblockers;
    virCPUx86FeaturePtr *migrate_blockers;
J
Jiri Denemark 已提交
152 153
};

J
Jiri Denemark 已提交
154
static virCPUx86MapPtr cpuMap;
155 156 157
int virCPUx86MapOnceInit(void);
VIR_ONCE_GLOBAL_INIT(virCPUx86Map);

J
Jiri Denemark 已提交
158

159
typedef enum {
J
Jiri Denemark 已提交
160 161 162 163
    SUBSET,
    EQUAL,
    SUPERSET,
    UNRELATED
164
} virCPUx86CompareResult;
J
Jiri Denemark 已提交
165 166


167 168 169
typedef struct _virCPUx86DataIterator virCPUx86DataIterator;
typedef virCPUx86DataIterator *virCPUx86DataIteratorPtr;
struct _virCPUx86DataIterator {
170
    const virCPUx86Data *data;
J
Jiri Denemark 已提交
171 172
    int pos;
};
J
Jiri Denemark 已提交
173 174


175
#define virCPUx86DataIteratorInit(data) \
176
    { data, -1 }
J
Jiri Denemark 已提交
177 178


179
static bool
180 181
x86cpuidMatch(const virCPUx86CPUID *cpuid1,
              const virCPUx86CPUID *cpuid2)
J
Jiri Denemark 已提交
182 183 184 185 186 187 188 189
{
    return (cpuid1->eax == cpuid2->eax &&
            cpuid1->ebx == cpuid2->ebx &&
            cpuid1->ecx == cpuid2->ecx &&
            cpuid1->edx == cpuid2->edx);
}


190
static bool
191 192
x86cpuidMatchMasked(const virCPUx86CPUID *cpuid,
                    const virCPUx86CPUID *mask)
J
Jiri Denemark 已提交
193 194 195 196 197 198 199 200
{
    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 已提交
201
static void
202 203
x86cpuidSetBits(virCPUx86CPUID *cpuid,
                const virCPUx86CPUID *mask)
J
Jiri Denemark 已提交
204
{
205 206 207
    if (!mask)
        return;

J
Jiri Denemark 已提交
208 209 210 211 212 213 214
    cpuid->eax |= mask->eax;
    cpuid->ebx |= mask->ebx;
    cpuid->ecx |= mask->ecx;
    cpuid->edx |= mask->edx;
}


J
Jiri Denemark 已提交
215
static void
216 217
x86cpuidClearBits(virCPUx86CPUID *cpuid,
                  const virCPUx86CPUID *mask)
J
Jiri Denemark 已提交
218
{
219 220 221
    if (!mask)
        return;

J
Jiri Denemark 已提交
222 223 224 225 226 227 228
    cpuid->eax &= ~mask->eax;
    cpuid->ebx &= ~mask->ebx;
    cpuid->ecx &= ~mask->ecx;
    cpuid->edx &= ~mask->edx;
}


J
Jiri Denemark 已提交
229
static void
230 231
x86cpuidAndBits(virCPUx86CPUID *cpuid,
                const virCPUx86CPUID *mask)
232
{
233 234 235
    if (!mask)
        return;

236 237 238 239 240 241
    cpuid->eax &= mask->eax;
    cpuid->ebx &= mask->ebx;
    cpuid->ecx &= mask->ecx;
    cpuid->edx &= mask->edx;
}

242 243 244 245 246 247
static int
virCPUx86CPUIDSorter(const void *a, const void *b)
{
    virCPUx86CPUID *da = (virCPUx86CPUID *) a;
    virCPUx86CPUID *db = (virCPUx86CPUID *) b;

248
    if (da->eax_in > db->eax_in)
249
        return 1;
250
    else if (da->eax_in < db->eax_in)
251 252
        return -1;

253 254 255 256 257
    if (da->ecx_in > db->ecx_in)
        return 1;
    else if (da->ecx_in < db->ecx_in)
        return -1;

258 259 260
    return 0;
}

261

J
Jiri Denemark 已提交
262
/* skips all zero CPUID leafs */
263
static virCPUx86CPUID *
264
x86DataCpuidNext(virCPUx86DataIteratorPtr iterator)
J
Jiri Denemark 已提交
265
{
266
    const virCPUx86Data *data = iterator->data;
J
Jiri Denemark 已提交
267

268
    if (!data)
J
Jiri Denemark 已提交
269 270
        return NULL;

271 272 273 274
    while (++iterator->pos < data->len) {
        if (!x86cpuidMatch(data->data + iterator->pos, &cpuidNull))
            return data->data + iterator->pos;
    }
J
Jiri Denemark 已提交
275

276
    return NULL;
J
Jiri Denemark 已提交
277 278 279
}


280
static virCPUx86CPUID *
281
x86DataCpuid(const virCPUx86Data *data,
282
             const virCPUx86CPUID *cpuid)
J
Jiri Denemark 已提交
283
{
284
    size_t i;
J
Jiri Denemark 已提交
285

286
    for (i = 0; i < data->len; i++) {
287 288
        if (data->data[i].eax_in == cpuid->eax_in &&
            data->data[i].ecx_in == cpuid->ecx_in)
289
            return data->data + i;
J
Jiri Denemark 已提交
290 291
    }

292
    return NULL;
J
Jiri Denemark 已提交
293 294
}

J
Jiri Denemark 已提交
295
void
296
virCPUx86DataClear(virCPUx86Data *data)
J
Jiri Denemark 已提交
297
{
298
    if (!data)
J
Jiri Denemark 已提交
299 300
        return;

301
    VIR_FREE(data->data);
J
Jiri Denemark 已提交
302 303 304
}


J
Jiri Denemark 已提交
305
virCPUDataPtr
306
virCPUx86MakeData(virArch arch, virCPUx86Data *data)
307
{
308
    virCPUDataPtr cpuData;
309 310 311 312

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

J
Jiri Denemark 已提交
313 314
    cpuData->arch = arch;
    cpuData->data.x86 = *data;
315 316
    data->len = 0;
    data->data = NULL;
317 318 319 320 321

    return cpuData;
}

static void
322
x86FreeCPUData(virCPUDataPtr data)
323 324 325 326
{
    if (!data)
        return;

327
    virCPUx86DataClear(&data->data.x86);
328 329 330 331
    VIR_FREE(data);
}


332 333
static int
x86DataCopy(virCPUx86Data *dst, const virCPUx86Data *src)
J
Jiri Denemark 已提交
334
{
335
    size_t i;
J
Jiri Denemark 已提交
336

337 338
    if (VIR_ALLOC_N(dst->data, src->len) < 0)
        return -1;
J
Jiri Denemark 已提交
339

340 341 342
    dst->len = src->len;
    for (i = 0; i < src->len; i++)
        dst->data[i] = src->data[i];
J
Jiri Denemark 已提交
343

344
    return 0;
J
Jiri Denemark 已提交
345 346 347
}


J
Jiri Denemark 已提交
348
int
349 350
virCPUx86DataAddCPUID(virCPUx86Data *data,
                      const virCPUx86CPUID *cpuid)
J
Jiri Denemark 已提交
351
{
352
    virCPUx86CPUID *existing;
J
Jiri Denemark 已提交
353

354
    if ((existing = x86DataCpuid(data, cpuid))) {
355 356 357 358 359
        x86cpuidSetBits(existing, cpuid);
    } else {
        if (VIR_APPEND_ELEMENT_COPY(data->data, data->len,
                                    *((virCPUx86CPUID *)cpuid)) < 0)
            return -1;
J
Jiri Denemark 已提交
360

361 362 363
        qsort(data->data, data->len,
              sizeof(virCPUx86CPUID), virCPUx86CPUIDSorter);
    }
J
Jiri Denemark 已提交
364

J
Jiri Denemark 已提交
365 366 367 368 369
    return 0;
}


static int
370 371
x86DataAdd(virCPUx86Data *data1,
           const virCPUx86Data *data2)
J
Jiri Denemark 已提交
372
{
373
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data2);
374 375
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
J
Jiri Denemark 已提交
376

377
    while ((cpuid2 = x86DataCpuidNext(&iter))) {
378
        cpuid1 = x86DataCpuid(data1, cpuid2);
J
Jiri Denemark 已提交
379

380 381 382 383 384 385
        if (cpuid1) {
            x86cpuidSetBits(cpuid1, cpuid2);
        } else {
            if (virCPUx86DataAddCPUID(data1, cpuid2) < 0)
                return -1;
        }
J
Jiri Denemark 已提交
386
    }
J
Jiri Denemark 已提交
387 388 389 390 391

    return 0;
}


392
static void
393 394
x86DataSubtract(virCPUx86Data *data1,
                const virCPUx86Data *data2)
395
{
396
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data1);
397 398
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
399

400
    while ((cpuid1 = x86DataCpuidNext(&iter))) {
401
        cpuid2 = x86DataCpuid(data2, cpuid1);
402
        x86cpuidClearBits(cpuid1, cpuid2);
403 404 405 406
    }
}


J
Jiri Denemark 已提交
407
static void
408 409
x86DataIntersect(virCPUx86Data *data1,
                 const virCPUx86Data *data2)
410
{
411
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data1);
412 413
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
414

J
Jiri Denemark 已提交
415
    while ((cpuid1 = x86DataCpuidNext(&iter))) {
416
        cpuid2 = x86DataCpuid(data2, cpuid1);
J
Jiri Denemark 已提交
417 418 419 420
        if (cpuid2)
            x86cpuidAndBits(cpuid1, cpuid2);
        else
            x86cpuidClearBits(cpuid1, cpuid1);
421 422 423 424
    }
}


J
Jiri Denemark 已提交
425
static bool
426
x86DataIsEmpty(virCPUx86Data *data)
J
Jiri Denemark 已提交
427
{
428
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data);
J
Jiri Denemark 已提交
429

430
    return !x86DataCpuidNext(&iter);
J
Jiri Denemark 已提交
431
}
J
Jiri Denemark 已提交
432 433


J
Jiri Denemark 已提交
434
static bool
435 436
x86DataIsSubset(const virCPUx86Data *data,
                const virCPUx86Data *subset)
J
Jiri Denemark 已提交
437 438
{

439
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit((virCPUx86Data *)subset);
440 441
    const virCPUx86CPUID *cpuid;
    const virCPUx86CPUID *cpuidSubset;
J
Jiri Denemark 已提交
442

J
Jiri Denemark 已提交
443
    while ((cpuidSubset = x86DataCpuidNext(&iter))) {
444
        if (!(cpuid = x86DataCpuid(data, cpuidSubset)) ||
J
Jiri Denemark 已提交
445 446
            !x86cpuidMatchMasked(cpuid, cpuidSubset))
            return false;
J
Jiri Denemark 已提交
447 448
    }

J
Jiri Denemark 已提交
449
    return true;
J
Jiri Denemark 已提交
450 451 452
}


453 454 455 456
/* also removes all detected features from data */
static int
x86DataToCPUFeatures(virCPUDefPtr cpu,
                     int policy,
457
                     virCPUx86Data *data,
J
Jiri Denemark 已提交
458
                     virCPUx86MapPtr map)
459
{
460
    size_t i;
461

462 463
    for (i = 0; i < map->nfeatures; i++) {
        virCPUx86FeaturePtr feature = map->features[i];
464 465
        if (x86DataIsSubset(data, &feature->data)) {
            x86DataSubtract(data, &feature->data);
J
Jiri Denemark 已提交
466 467
            if (virCPUDefAddFeature(cpu, feature->name, policy) < 0)
                return -1;
468 469 470 471 472 473 474
        }
    }

    return 0;
}


J
Jiri Denemark 已提交
475
/* also removes bits corresponding to vendor string from data */
476
static virCPUx86VendorPtr
J
Jiri Denemark 已提交
477
x86DataToVendor(const virCPUx86Data *data,
J
Jiri Denemark 已提交
478
                virCPUx86MapPtr map)
J
Jiri Denemark 已提交
479
{
480
    virCPUx86CPUID *cpuid;
481
    size_t i;
J
Jiri Denemark 已提交
482

483 484
    for (i = 0; i < map->nvendors; i++) {
        virCPUx86VendorPtr vendor = map->vendors[i];
485
        if ((cpuid = x86DataCpuid(data, &vendor->cpuid)) &&
J
Jiri Denemark 已提交
486 487 488 489 490 491 492 493 494 495
            x86cpuidMatchMasked(cpuid, &vendor->cpuid)) {
            x86cpuidClearBits(cpuid, &vendor->cpuid);
            return vendor;
        }
    }

    return NULL;
}


496
static virCPUDefPtr
497
x86DataToCPU(const virCPUx86Data *data,
J
Jiri Denemark 已提交
498
             virCPUx86ModelPtr model,
J
Jiri Denemark 已提交
499
             virCPUx86MapPtr map)
500 501
{
    virCPUDefPtr cpu;
502 503
    virCPUx86Data copy = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data modelData = VIR_CPU_X86_DATA_INIT;
504
    virCPUx86VendorPtr vendor;
505 506

    if (VIR_ALLOC(cpu) < 0 ||
507
        VIR_STRDUP(cpu->model, model->name) < 0 ||
508 509
        x86DataCopy(&copy, data) < 0 ||
        x86DataCopy(&modelData, &model->data) < 0)
510
        goto error;
511

512
    if ((vendor = x86DataToVendor(&copy, map)) &&
513
        VIR_STRDUP(cpu->vendor, vendor->name) < 0)
514
        goto error;
J
Jiri Denemark 已提交
515

516 517
    x86DataSubtract(&copy, &modelData);
    x86DataSubtract(&modelData, data);
518 519 520

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

522 523
    if (x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_REQUIRE, &copy, map) ||
        x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_DISABLE, &modelData, map))
524
        goto error;
525

526
 cleanup:
527 528
    virCPUx86DataClear(&modelData);
    virCPUx86DataClear(&copy);
529 530
    return cpu;

531
 error:
532 533 534 535 536 537
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
}


J
Jiri Denemark 已提交
538
static void
539
x86VendorFree(virCPUx86VendorPtr vendor)
J
Jiri Denemark 已提交
540 541 542 543 544 545
{
    if (!vendor)
        return;

    VIR_FREE(vendor->name);
    VIR_FREE(vendor);
J
Jiri Denemark 已提交
546
}
J
Jiri Denemark 已提交
547 548


549
static virCPUx86VendorPtr
J
Jiri Denemark 已提交
550
x86VendorFind(virCPUx86MapPtr map,
J
Jiri Denemark 已提交
551 552
              const char *name)
{
553
    size_t i;
J
Jiri Denemark 已提交
554

555 556 557
    for (i = 0; i < map->nvendors; i++) {
        if (STREQ(map->vendors[i]->name, name))
            return map->vendors[i];
J
Jiri Denemark 已提交
558 559 560 561 562 563
    }

    return NULL;
}


J
Jiri Denemark 已提交
564 565 566
static virCPUx86VendorPtr
x86VendorParse(xmlXPathContextPtr ctxt,
               virCPUx86MapPtr map)
J
Jiri Denemark 已提交
567
{
568
    virCPUx86VendorPtr vendor = NULL;
J
Jiri Denemark 已提交
569 570 571
    char *string = NULL;

    if (VIR_ALLOC(vendor) < 0)
J
Jiri Denemark 已提交
572
        goto error;
J
Jiri Denemark 已提交
573 574 575

    vendor->name = virXPathString("string(@name)", ctxt);
    if (!vendor->name) {
576 577
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Missing CPU vendor name"));
J
Jiri Denemark 已提交
578
        goto error;
J
Jiri Denemark 已提交
579 580 581
    }

    if (x86VendorFind(map, vendor->name)) {
582 583
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU vendor %s already defined"), vendor->name);
J
Jiri Denemark 已提交
584
        goto error;
J
Jiri Denemark 已提交
585 586 587 588
    }

    string = virXPathString("string(@string)", ctxt);
    if (!string) {
589
        virReportError(VIR_ERR_INTERNAL_ERROR,
590 591
                       _("Missing vendor string for CPU vendor %s"),
                       vendor->name);
J
Jiri Denemark 已提交
592
        goto error;
J
Jiri Denemark 已提交
593 594
    }
    if (strlen(string) != VENDOR_STRING_LENGTH) {
595 596
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid CPU vendor string '%s'"), string);
J
Jiri Denemark 已提交
597
        goto error;
J
Jiri Denemark 已提交
598 599
    }

600
    vendor->cpuid.eax_in = 0;
601
    vendor->cpuid.ecx_in = 0;
E
Eric Blake 已提交
602 603 604 605
    vendor->cpuid.ebx = virReadBufInt32LE(string);
    vendor->cpuid.edx = virReadBufInt32LE(string + 4);
    vendor->cpuid.ecx = virReadBufInt32LE(string + 8);

J
Jiri Denemark 已提交
606
 cleanup:
J
Jiri Denemark 已提交
607
    VIR_FREE(string);
J
Jiri Denemark 已提交
608 609 610
    return vendor;

 error:
J
Jiri Denemark 已提交
611
    x86VendorFree(vendor);
J
Jiri Denemark 已提交
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
    vendor = NULL;
    goto cleanup;
}


static int
x86VendorsLoad(virCPUx86MapPtr map,
               xmlXPathContextPtr ctxt,
               xmlNodePtr *nodes,
               int n)
{
    virCPUx86VendorPtr vendor;
    size_t i;

    if (VIR_ALLOC_N(map->vendors, n) < 0)
        return -1;

    for (i = 0; i < n; i++) {
        ctxt->node = nodes[i];
        if (!(vendor = x86VendorParse(ctxt, map)))
            return -1;
        map->vendors[map->nvendors++] = vendor;
    }

    return 0;
J
Jiri Denemark 已提交
637 638 639
}


640
static virCPUx86FeaturePtr
J
Jiri Denemark 已提交
641 642
x86FeatureNew(void)
{
643
    virCPUx86FeaturePtr feature;
J
Jiri Denemark 已提交
644 645 646 647 648 649 650 651

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

    return feature;
}


J
Jiri Denemark 已提交
652
static void
653
x86FeatureFree(virCPUx86FeaturePtr feature)
J
Jiri Denemark 已提交
654
{
655
    if (!feature)
J
Jiri Denemark 已提交
656 657 658
        return;

    VIR_FREE(feature->name);
659
    virCPUx86DataClear(&feature->data);
J
Jiri Denemark 已提交
660 661 662 663
    VIR_FREE(feature);
}


664
static virCPUx86FeaturePtr
J
Jiri Denemark 已提交
665
x86FeatureFind(virCPUx86MapPtr map,
J
Jiri Denemark 已提交
666 667
               const char *name)
{
668
    size_t i;
J
Jiri Denemark 已提交
669

670 671 672
    for (i = 0; i < map->nfeatures; i++) {
        if (STREQ(map->features[i]->name, name))
            return map->features[i];
J
Jiri Denemark 已提交
673 674 675 676 677 678
    }

    return NULL;
}


679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
static virCPUx86FeaturePtr
x86FeatureFindInternal(const char *name)
{
    size_t i;
    size_t count = ARRAY_CARDINALITY(x86_kvm_features);

    for (i = 0; i < count; i++) {
        if (STREQ(x86_kvm_features[i].name, name))
            return x86_kvm_features + i;
    }

    return NULL;
}


694
static char *
J
Jiri Denemark 已提交
695
x86FeatureNames(virCPUx86MapPtr map,
696
                const char *separator,
697
                virCPUx86Data *data)
698 699 700
{
    virBuffer ret = VIR_BUFFER_INITIALIZER;
    bool first = true;
701
    size_t i;
702 703 704

    virBufferAdd(&ret, "", 0);

705 706
    for (i = 0; i < map->nfeatures; i++) {
        virCPUx86FeaturePtr feature = map->features[i];
707
        if (x86DataIsSubset(data, &feature->data)) {
708 709 710 711 712
            if (!first)
                virBufferAdd(&ret, separator, -1);
            else
                first = false;

713
            virBufferAdd(&ret, feature->name, -1);
714 715 716 717 718 719 720
        }
    }

    return virBufferContentAndReset(&ret);
}


721 722
static int
x86ParseCPUID(xmlXPathContextPtr ctxt,
723
              virCPUx86CPUID *cpuid)
724
{
725
    unsigned long eax_in, ecx_in;
726
    unsigned long eax, ebx, ecx, edx;
727
    int ret_eax_in, ret_ecx_in, ret_eax, ret_ebx, ret_ecx, ret_edx;
728 729 730

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

731
    eax_in = ecx_in = 0;
732 733
    eax = ebx = ecx = edx = 0;
    ret_eax_in = virXPathULongHex("string(@eax_in)", ctxt, &eax_in);
734
    ret_ecx_in = virXPathULongHex("string(@ecx_in)", ctxt, &ecx_in);
735 736 737 738 739
    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);

740
    if (ret_eax_in < 0 || ret_ecx_in == -2 ||
741
        ret_eax == -2 || ret_ebx == -2 || ret_ecx == -2 || ret_edx == -2)
742 743
        return -1;

744
    cpuid->eax_in = eax_in;
745
    cpuid->ecx_in = ecx_in;
746 747 748 749 750 751 752 753
    cpuid->eax = eax;
    cpuid->ebx = ebx;
    cpuid->ecx = ecx;
    cpuid->edx = edx;
    return 0;
}


J
Jiri Denemark 已提交
754 755 756
static virCPUx86FeaturePtr
x86FeatureParse(xmlXPathContextPtr ctxt,
                virCPUx86MapPtr map)
J
Jiri Denemark 已提交
757 758
{
    xmlNodePtr *nodes = NULL;
759
    virCPUx86FeaturePtr feature;
760
    virCPUx86CPUID cpuid;
761
    size_t i;
J
Jiri Denemark 已提交
762
    int n;
763
    char *str = NULL;
J
Jiri Denemark 已提交
764

J
Jiri Denemark 已提交
765
    if (!(feature = x86FeatureNew()))
J
Jiri Denemark 已提交
766
        goto error;
J
Jiri Denemark 已提交
767

J
Jiri Denemark 已提交
768
    feature->migratable = true;
769
    feature->name = virXPathString("string(@name)", ctxt);
770
    if (!feature->name) {
771 772
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing CPU feature name"));
J
Jiri Denemark 已提交
773
        goto error;
J
Jiri Denemark 已提交
774 775 776
    }

    if (x86FeatureFind(map, feature->name)) {
777 778
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU feature %s already defined"), feature->name);
J
Jiri Denemark 已提交
779
        goto error;
J
Jiri Denemark 已提交
780 781
    }

782 783
    str = virXPathString("string(@migratable)", ctxt);
    if (STREQ_NULLABLE(str, "no"))
J
Jiri Denemark 已提交
784
        feature->migratable = false;
785

786
    n = virXPathNodeSet("./cpuid", ctxt, &nodes);
J
Jiri Denemark 已提交
787
    if (n < 0)
J
Jiri Denemark 已提交
788
        goto error;
J
Jiri Denemark 已提交
789 790 791

    for (i = 0; i < n; i++) {
        ctxt->node = nodes[i];
792
        if (x86ParseCPUID(ctxt, &cpuid) < 0) {
793
            virReportError(VIR_ERR_INTERNAL_ERROR,
794 795
                           _("Invalid cpuid[%zu] in %s feature"),
                           i, feature->name);
J
Jiri Denemark 已提交
796
            goto error;
J
Jiri Denemark 已提交
797
        }
798
        if (virCPUx86DataAddCPUID(&feature->data, &cpuid))
J
Jiri Denemark 已提交
799
            goto error;
J
Jiri Denemark 已提交
800 801
    }

J
Jiri Denemark 已提交
802
 cleanup:
803
    VIR_FREE(nodes);
804
    VIR_FREE(str);
J
Jiri Denemark 已提交
805
    return feature;
806

J
Jiri Denemark 已提交
807 808 809 810
 error:
    x86FeatureFree(feature);
    feature = NULL;
    goto cleanup;
J
Jiri Denemark 已提交
811 812 813
}


J
Jiri Denemark 已提交
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
static int
x86FeaturesLoad(virCPUx86MapPtr map,
                xmlXPathContextPtr ctxt,
                xmlNodePtr *nodes,
                int n)
{
    virCPUx86FeaturePtr feature;
    size_t i;

    if (VIR_ALLOC_N(map->features, n) < 0)
        return -1;

    for (i = 0; i < n; i++) {
        ctxt->node = nodes[i];
        if (!(feature = x86FeatureParse(ctxt, map)))
            return -1;
        map->features[map->nfeatures++] = feature;
        if (!feature->migratable &&
            VIR_APPEND_ELEMENT(map->migrate_blockers,
                               map->nblockers,
                               feature) < 0)
            return -1;
    }

    return 0;
}

841 842 843
static int
x86DataFromCPUFeatures(virCPUx86Data *data,
                       virCPUDefPtr cpu,
J
Jiri Denemark 已提交
844
                       virCPUx86MapPtr map)
845 846 847 848
{
    size_t i;

    for (i = 0; i < cpu->nfeatures; i++) {
849
        virCPUx86FeaturePtr feature;
850 851 852
        if (!(feature = x86FeatureFind(map, cpu->features[i].name))) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU feature %s"), cpu->features[i].name);
853
            return -1;
854 855
        }

856 857
        if (x86DataAdd(data, &feature->data) < 0)
            return -1;
858 859
    }

860
    return 0;
861 862 863
}


J
Jiri Denemark 已提交
864
static virCPUx86ModelPtr
J
Jiri Denemark 已提交
865 866
x86ModelNew(void)
{
J
Jiri Denemark 已提交
867
    virCPUx86ModelPtr model;
J
Jiri Denemark 已提交
868 869 870 871 872 873 874 875

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

    return model;
}


J
Jiri Denemark 已提交
876
static void
J
Jiri Denemark 已提交
877
x86ModelFree(virCPUx86ModelPtr model)
J
Jiri Denemark 已提交
878
{
879
    if (!model)
J
Jiri Denemark 已提交
880 881 882
        return;

    VIR_FREE(model->name);
883
    virCPUx86DataClear(&model->data);
J
Jiri Denemark 已提交
884 885 886 887
    VIR_FREE(model);
}


J
Jiri Denemark 已提交
888 889
static virCPUx86ModelPtr
x86ModelCopy(virCPUx86ModelPtr model)
J
Jiri Denemark 已提交
890
{
J
Jiri Denemark 已提交
891
    virCPUx86ModelPtr copy;
J
Jiri Denemark 已提交
892

893 894
    if (VIR_ALLOC(copy) < 0 ||
        VIR_STRDUP(copy->name, model->name) < 0 ||
895
        x86DataCopy(&copy->data, &model->data) < 0) {
J
Jiri Denemark 已提交
896 897 898 899
        x86ModelFree(copy);
        return NULL;
    }

J
Jiri Denemark 已提交
900
    copy->vendor = model->vendor;
J
Jiri Denemark 已提交
901 902 903 904 905

    return copy;
}


J
Jiri Denemark 已提交
906
static virCPUx86ModelPtr
J
Jiri Denemark 已提交
907
x86ModelFind(virCPUx86MapPtr map,
J
Jiri Denemark 已提交
908 909
             const char *name)
{
910
    size_t i;
J
Jiri Denemark 已提交
911

912 913 914
    for (i = 0; i < map->nmodels; i++) {
        if (STREQ(map->models[i]->name, name))
            return map->models[i];
J
Jiri Denemark 已提交
915 916 917 918 919 920
    }

    return NULL;
}


J
Jiri Denemark 已提交
921
static virCPUx86ModelPtr
922
x86ModelFromCPU(const virCPUDef *cpu,
J
Jiri Denemark 已提交
923
                virCPUx86MapPtr map,
J
Jiri Denemark 已提交
924 925
                int policy)
{
J
Jiri Denemark 已提交
926
    virCPUx86ModelPtr model = NULL;
927
    size_t i;
J
Jiri Denemark 已提交
928

929
    if (policy == VIR_CPU_FEATURE_REQUIRE) {
930
        if (!(model = x86ModelFind(map, cpu->model))) {
931 932
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU model %s"), cpu->model);
J
Jiri Denemark 已提交
933 934 935
            goto error;
        }

936
        if (!(model = x86ModelCopy(model)))
937
            goto error;
J
Jiri Denemark 已提交
938
    } else if (!(model = x86ModelNew())) {
939
        goto error;
J
Jiri Denemark 已提交
940
    } else if (cpu->type == VIR_CPU_TYPE_HOST) {
941
        return model;
J
Jiri Denemark 已提交
942
    }
J
Jiri Denemark 已提交
943 944

    for (i = 0; i < cpu->nfeatures; i++) {
945
        virCPUx86FeaturePtr feature;
J
Jiri Denemark 已提交
946 947 948 949 950

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

951
        if (!(feature = x86FeatureFind(map, cpu->features[i].name))) {
952 953
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU feature %s"), cpu->features[i].name);
J
Jiri Denemark 已提交
954 955 956
            goto error;
        }

957
        if (x86DataAdd(&model->data, &feature->data))
958
            goto error;
J
Jiri Denemark 已提交
959 960 961 962
    }

    return model;

963
 error:
J
Jiri Denemark 已提交
964 965 966 967 968
    x86ModelFree(model);
    return NULL;
}


969
static int
J
Jiri Denemark 已提交
970
x86ModelSubtractCPU(virCPUx86ModelPtr model,
971
                    const virCPUDef *cpu,
J
Jiri Denemark 已提交
972
                    virCPUx86MapPtr map)
973
{
J
Jiri Denemark 已提交
974
    virCPUx86ModelPtr cpu_model;
975
    size_t i;
976 977

    if (!(cpu_model = x86ModelFind(map, cpu->model))) {
978 979 980
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown CPU model %s"),
                       cpu->model);
981 982 983
        return -1;
    }

984
    x86DataSubtract(&model->data, &cpu_model->data);
985 986

    for (i = 0; i < cpu->nfeatures; i++) {
987
        virCPUx86FeaturePtr feature;
988 989

        if (!(feature = x86FeatureFind(map, cpu->features[i].name))) {
990 991 992
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU feature %s"),
                           cpu->features[i].name);
993 994 995
            return -1;
        }

996
        x86DataSubtract(&model->data, &feature->data);
997 998 999 1000 1001 1002
    }

    return 0;
}


1003
static virCPUx86CompareResult
J
Jiri Denemark 已提交
1004 1005
x86ModelCompare(virCPUx86ModelPtr model1,
                virCPUx86ModelPtr model2)
J
Jiri Denemark 已提交
1006
{
1007
    virCPUx86CompareResult result = EQUAL;
1008 1009
    virCPUx86DataIterator iter1 = virCPUx86DataIteratorInit(&model1->data);
    virCPUx86DataIterator iter2 = virCPUx86DataIteratorInit(&model2->data);
1010 1011
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
J
Jiri Denemark 已提交
1012

J
Jiri Denemark 已提交
1013
    while ((cpuid1 = x86DataCpuidNext(&iter1))) {
1014
        virCPUx86CompareResult match = SUPERSET;
J
Jiri Denemark 已提交
1015

1016
        if ((cpuid2 = x86DataCpuid(&model2->data, cpuid1))) {
J
Jiri Denemark 已提交
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
            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 已提交
1029
    while ((cpuid2 = x86DataCpuidNext(&iter2))) {
1030
        virCPUx86CompareResult match = SUBSET;
J
Jiri Denemark 已提交
1031

1032
        if ((cpuid1 = x86DataCpuid(&model1->data, cpuid2))) {
J
Jiri Denemark 已提交
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
            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;
}


J
Jiri Denemark 已提交
1049 1050 1051
static virCPUx86ModelPtr
x86ModelParse(xmlXPathContextPtr ctxt,
              virCPUx86MapPtr map)
J
Jiri Denemark 已提交
1052 1053
{
    xmlNodePtr *nodes = NULL;
J
Jiri Denemark 已提交
1054
    virCPUx86ModelPtr model;
J
Jiri Denemark 已提交
1055
    char *vendor = NULL;
1056
    size_t i;
J
Jiri Denemark 已提交
1057 1058
    int n;

J
Jiri Denemark 已提交
1059
    if (!(model = x86ModelNew()))
J
Jiri Denemark 已提交
1060
        goto error;
J
Jiri Denemark 已提交
1061

1062
    model->name = virXPathString("string(@name)", ctxt);
1063
    if (!model->name) {
1064 1065
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing CPU model name"));
J
Jiri Denemark 已提交
1066
        goto error;
J
Jiri Denemark 已提交
1067 1068
    }

1069
    if (virXPathNode("./model", ctxt)) {
J
Jiri Denemark 已提交
1070
        virCPUx86ModelPtr ancestor;
J
Jiri Denemark 已提交
1071 1072
        char *name;

1073
        name = virXPathString("string(./model/@name)", ctxt);
1074
        if (!name) {
1075 1076 1077
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing ancestor's name in CPU model %s"),
                           model->name);
J
Jiri Denemark 已提交
1078
            goto error;
J
Jiri Denemark 已提交
1079 1080
        }

1081
        if (!(ancestor = x86ModelFind(map, name))) {
1082 1083 1084
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Ancestor model %s not found for CPU model %s"),
                           name, model->name);
J
Jiri Denemark 已提交
1085
            VIR_FREE(name);
J
Jiri Denemark 已提交
1086
            goto error;
J
Jiri Denemark 已提交
1087 1088 1089 1090
        }

        VIR_FREE(name);

J
Jiri Denemark 已提交
1091
        model->vendor = ancestor->vendor;
1092
        if (x86DataCopy(&model->data, &ancestor->data) < 0)
J
Jiri Denemark 已提交
1093
            goto error;
J
Jiri Denemark 已提交
1094 1095
    }

1096 1097 1098
    if (virXPathBoolean("boolean(./vendor)", ctxt)) {
        vendor = virXPathString("string(./vendor/@name)", ctxt);
        if (!vendor) {
1099 1100 1101
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid vendor element in CPU model %s"),
                           model->name);
J
Jiri Denemark 已提交
1102
            goto error;
1103 1104
        }

J
Jiri Denemark 已提交
1105
        if (!(model->vendor = x86VendorFind(map, vendor))) {
1106 1107 1108
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown vendor %s referenced by CPU model %s"),
                           vendor, model->name);
J
Jiri Denemark 已提交
1109
            goto error;
J
Jiri Denemark 已提交
1110 1111 1112
        }
    }

1113
    n = virXPathNodeSet("./feature", ctxt, &nodes);
J
Jiri Denemark 已提交
1114
    if (n < 0)
J
Jiri Denemark 已提交
1115
        goto error;
J
Jiri Denemark 已提交
1116 1117

    for (i = 0; i < n; i++) {
1118
        virCPUx86FeaturePtr feature;
J
Jiri Denemark 已提交
1119 1120
        char *name;

1121
        if (!(name = virXMLPropString(nodes[i], "name"))) {
1122 1123
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing feature name for CPU model %s"), model->name);
J
Jiri Denemark 已提交
1124
            goto error;
J
Jiri Denemark 已提交
1125 1126
        }

1127
        if (!(feature = x86FeatureFind(map, name))) {
1128 1129 1130
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Feature %s required by CPU model %s not found"),
                           name, model->name);
J
Jiri Denemark 已提交
1131
            VIR_FREE(name);
J
Jiri Denemark 已提交
1132
            goto error;
J
Jiri Denemark 已提交
1133 1134 1135
        }
        VIR_FREE(name);

1136
        if (x86DataAdd(&model->data, &feature->data))
J
Jiri Denemark 已提交
1137
            goto error;
J
Jiri Denemark 已提交
1138 1139
    }

J
Jiri Denemark 已提交
1140
 cleanup:
J
Jiri Denemark 已提交
1141
    VIR_FREE(vendor);
1142
    VIR_FREE(nodes);
J
Jiri Denemark 已提交
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
    return model;

 error:
    x86ModelFree(model);
    model = NULL;
    goto cleanup;
}


static int
x86ModelsLoad(virCPUx86MapPtr map,
              xmlXPathContextPtr ctxt,
              xmlNodePtr *nodes,
              int n)
{
    virCPUx86ModelPtr model;
    size_t i;

    if (VIR_ALLOC_N(map->models, n) < 0)
        return -1;

    for (i = 0; i < n; i++) {
        ctxt->node = nodes[i];
        if (!(model = x86ModelParse(ctxt, map)))
            return -1;
        map->models[map->nmodels++] = model;
    }

    return 0;
J
Jiri Denemark 已提交
1172 1173 1174 1175
}


static void
J
Jiri Denemark 已提交
1176
x86MapFree(virCPUx86MapPtr map)
J
Jiri Denemark 已提交
1177
{
1178 1179
    size_t i;

1180
    if (!map)
J
Jiri Denemark 已提交
1181 1182
        return;

1183 1184 1185
    for (i = 0; i < map->nfeatures; i++)
        x86FeatureFree(map->features[i]);
    VIR_FREE(map->features);
J
Jiri Denemark 已提交
1186

1187 1188 1189
    for (i = 0; i < map->nmodels; i++)
        x86ModelFree(map->models[i]);
    VIR_FREE(map->models);
J
Jiri Denemark 已提交
1190

1191 1192 1193
    for (i = 0; i < map->nvendors; i++)
        x86VendorFree(map->vendors[i]);
    VIR_FREE(map->vendors);
1194

1195 1196 1197 1198
    /* migrate_blockers only points to the features from map->features list,
     * which were already freed above
     */
    VIR_FREE(map->migrate_blockers);
1199

J
Jiri Denemark 已提交
1200 1201 1202 1203
    VIR_FREE(map);
}


J
Jiri Denemark 已提交
1204
static int
1205
x86MapLoadCallback(cpuMapElement element,
J
Jiri Denemark 已提交
1206
                   xmlXPathContextPtr ctxt,
J
Jiri Denemark 已提交
1207 1208
                   xmlNodePtr *nodes,
                   int n,
J
Jiri Denemark 已提交
1209 1210
                   void *data)
{
J
Jiri Denemark 已提交
1211
    virCPUx86MapPtr map = data;
J
Jiri Denemark 已提交
1212 1213 1214

    switch (element) {
    case CPU_MAP_ELEMENT_VENDOR:
J
Jiri Denemark 已提交
1215
        return x86VendorsLoad(map, ctxt, nodes, n);
J
Jiri Denemark 已提交
1216
    case CPU_MAP_ELEMENT_FEATURE:
J
Jiri Denemark 已提交
1217
        return x86FeaturesLoad(map, ctxt, nodes, n);
J
Jiri Denemark 已提交
1218
    case CPU_MAP_ELEMENT_MODEL:
J
Jiri Denemark 已提交
1219
        return x86ModelsLoad(map, ctxt, nodes, n);
J
Jiri Denemark 已提交
1220 1221 1222 1223 1224 1225 1226 1227
    case CPU_MAP_ELEMENT_LAST:
        break;
    }

    return 0;
}


J
Jiri Denemark 已提交
1228
static virCPUx86MapPtr
1229
virCPUx86LoadMap(void)
J
Jiri Denemark 已提交
1230
{
J
Jiri Denemark 已提交
1231
    virCPUx86MapPtr map;
J
Jiri Denemark 已提交
1232

1233
    if (VIR_ALLOC(map) < 0)
J
Jiri Denemark 已提交
1234 1235
        return NULL;

J
Jiri Denemark 已提交
1236
    if (cpuMapLoad("x86", x86MapLoadCallback, map) < 0)
J
Jiri Denemark 已提交
1237 1238 1239 1240
        goto error;

    return map;

1241
 error:
J
Jiri Denemark 已提交
1242 1243 1244 1245 1246
    x86MapFree(map);
    return NULL;
}


1247 1248 1249
int
virCPUx86MapOnceInit(void)
{
J
Jiri Denemark 已提交
1250
    if (!(cpuMap = virCPUx86LoadMap()))
1251 1252 1253 1254 1255 1256
        return -1;

    return 0;
}


J
Jiri Denemark 已提交
1257
static virCPUx86MapPtr
1258 1259 1260 1261 1262
virCPUx86GetMap(void)
{
    if (virCPUx86MapInitialize() < 0)
        return NULL;

J
Jiri Denemark 已提交
1263
    return cpuMap;
1264 1265 1266
}


1267 1268 1269
static char *
x86CPUDataFormat(const virCPUData *data)
{
1270
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(&data->data.x86);
1271
    virCPUx86CPUID *cpuid;
1272 1273 1274 1275 1276
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virBufferAddLit(&buf, "<cpudata arch='x86'>\n");
    while ((cpuid = x86DataCpuidNext(&iter))) {
        virBufferAsprintf(&buf,
1277
                          "  <cpuid eax_in='0x%08x' ecx_in='0x%08x'"
1278 1279
                          " eax='0x%08x' ebx='0x%08x'"
                          " ecx='0x%08x' edx='0x%08x'/>\n",
1280
                          cpuid->eax_in, cpuid->ecx_in,
1281 1282 1283 1284
                          cpuid->eax, cpuid->ebx, cpuid->ecx, cpuid->edx);
    }
    virBufferAddLit(&buf, "</cpudata>\n");

1285
    if (virBufferCheckError(&buf) < 0)
1286 1287 1288 1289 1290 1291 1292
        return NULL;

    return virBufferContentAndReset(&buf);
}


static virCPUDataPtr
1293
x86CPUDataParse(xmlXPathContextPtr ctxt)
1294 1295 1296
{
    xmlNodePtr *nodes = NULL;
    virCPUDataPtr cpuData = NULL;
1297
    virCPUx86Data data = VIR_CPU_X86_DATA_INIT;
1298
    virCPUx86CPUID cpuid;
1299 1300 1301
    size_t i;
    int n;

1302
    n = virXPathNodeSet("/cpudata/cpuid", ctxt, &nodes);
J
Jiri Denemark 已提交
1303
    if (n <= 0) {
1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315
        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;
        }
1316
        if (virCPUx86DataAddCPUID(&data, &cpuid) < 0)
1317 1318 1319
            goto cleanup;
    }

1320
    cpuData = virCPUx86MakeData(VIR_ARCH_X86_64, &data);
1321

1322
 cleanup:
1323
    VIR_FREE(nodes);
1324
    virCPUx86DataClear(&data);
1325 1326 1327 1328
    return cpuData;
}


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

1354

J
Jiri Denemark 已提交
1355 1356 1357
static virCPUCompareResult
x86Compute(virCPUDefPtr host,
           virCPUDefPtr cpu,
1358
           virCPUDataPtr *guest,
1359
           char **message)
J
Jiri Denemark 已提交
1360
{
J
Jiri Denemark 已提交
1361
    virCPUx86MapPtr map = NULL;
J
Jiri Denemark 已提交
1362 1363 1364 1365 1366 1367 1368 1369
    virCPUx86ModelPtr host_model = NULL;
    virCPUx86ModelPtr cpu_force = NULL;
    virCPUx86ModelPtr cpu_require = NULL;
    virCPUx86ModelPtr cpu_optional = NULL;
    virCPUx86ModelPtr cpu_disable = NULL;
    virCPUx86ModelPtr cpu_forbid = NULL;
    virCPUx86ModelPtr diff = NULL;
    virCPUx86ModelPtr guest_model = NULL;
1370
    virCPUx86Data guestData = VIR_CPU_X86_DATA_INIT;
J
Jiri Denemark 已提交
1371
    virCPUCompareResult ret;
1372
    virCPUx86CompareResult result;
J
Jiri Denemark 已提交
1373
    virArch arch;
1374
    size_t i;
J
Jiri Denemark 已提交
1375

1376 1377 1378 1379 1380 1381
    if (!cpu->model) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("no guest CPU model specified"));
        return VIR_CPU_COMPARE_ERROR;
    }

1382
    if (cpu->arch != VIR_ARCH_NONE) {
J
Jiri Denemark 已提交
1383 1384 1385
        bool found = false;

        for (i = 0; i < ARRAY_CARDINALITY(archs); i++) {
1386
            if (archs[i] == cpu->arch) {
J
Jiri Denemark 已提交
1387 1388 1389 1390 1391
                found = true;
                break;
            }
        }

1392
        if (!found) {
1393 1394
            VIR_DEBUG("CPU arch %s does not match host arch",
                      virArchToString(cpu->arch));
1395 1396 1397
            if (message &&
                virAsprintf(message,
                            _("CPU arch %s does not match host arch"),
1398
                            virArchToString(cpu->arch)) < 0)
1399
                goto error;
J
Jiri Denemark 已提交
1400
            return VIR_CPU_COMPARE_INCOMPATIBLE;
1401
        }
J
Jiri Denemark 已提交
1402 1403 1404
        arch = cpu->arch;
    } else {
        arch = host->arch;
J
Jiri Denemark 已提交
1405 1406
    }

J
Jiri Denemark 已提交
1407 1408 1409 1410
    if (cpu->vendor &&
        (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) {
        VIR_DEBUG("host CPU vendor does not match required CPU vendor %s",
                  cpu->vendor);
1411 1412 1413 1414 1415
        if (message &&
            virAsprintf(message,
                        _("host CPU vendor does not match required "
                          "CPU vendor %s"),
                        cpu->vendor) < 0)
1416
            goto error;
1417

J
Jiri Denemark 已提交
1418 1419 1420
        return VIR_CPU_COMPARE_INCOMPATIBLE;
    }

1421
    if (!(map = virCPUx86GetMap()) ||
1422
        !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)) ||
J
Jiri Denemark 已提交
1423 1424 1425 1426 1427
        !(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 已提交
1428 1429
        goto error;

1430 1431
    x86DataIntersect(&cpu_forbid->data, &host_model->data);
    if (!x86DataIsEmpty(&cpu_forbid->data)) {
1432
        virX86CpuIncompatible(N_("Host CPU provides forbidden features"),
1433
                              &cpu_forbid->data);
1434
        goto cleanup;
J
Jiri Denemark 已提交
1435 1436
    }

1437 1438 1439
    /* first remove features that were inherited from the CPU model and were
     * explicitly forced, disabled, or made optional
     */
1440 1441 1442
    x86DataSubtract(&cpu_require->data, &cpu_force->data);
    x86DataSubtract(&cpu_require->data, &cpu_optional->data);
    x86DataSubtract(&cpu_require->data, &cpu_disable->data);
J
Jiri Denemark 已提交
1443 1444
    result = x86ModelCompare(host_model, cpu_require);
    if (result == SUBSET || result == UNRELATED) {
1445
        x86DataSubtract(&cpu_require->data, &host_model->data);
1446 1447
        virX86CpuIncompatible(N_("Host CPU does not provide required "
                                 "features"),
1448
                              &cpu_require->data);
1449
        goto cleanup;
J
Jiri Denemark 已提交
1450 1451 1452 1453
    }

    ret = VIR_CPU_COMPARE_IDENTICAL;

1454
    if (!(diff = x86ModelCopy(host_model)))
1455
        goto error;
J
Jiri Denemark 已提交
1456

1457 1458 1459 1460
    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 已提交
1461

1462
    if (!x86DataIsEmpty(&diff->data))
J
Jiri Denemark 已提交
1463
        ret = VIR_CPU_COMPARE_SUPERSET;
J
Jiri Denemark 已提交
1464 1465 1466 1467

    if (ret == VIR_CPU_COMPARE_SUPERSET
        && cpu->type == VIR_CPU_TYPE_GUEST
        && cpu->match == VIR_CPU_MATCH_STRICT) {
1468 1469
        virX86CpuIncompatible(N_("Host CPU does not strictly match guest CPU: "
                                 "Extra features"),
1470
                              &diff->data);
1471
        goto cleanup;
J
Jiri Denemark 已提交
1472 1473
    }

1474 1475
    if (guest) {
        if (!(guest_model = x86ModelCopy(host_model)))
1476
            goto error;
J
Jiri Denemark 已提交
1477

1478
        if (cpu->vendor &&
1479
            virCPUx86DataAddCPUID(&guest_model->data,
1480 1481 1482
                                  &host_model->vendor->cpuid) < 0)
            goto error;

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

1487
        if (x86DataAdd(&guest_model->data, &cpu_force->data))
1488
            goto error;
J
Jiri Denemark 已提交
1489

1490
        x86DataSubtract(&guest_model->data, &cpu_disable->data);
J
Jiri Denemark 已提交
1491

1492 1493
        if (x86DataCopy(&guestData, &guest_model->data) < 0 ||
            !(*guest = virCPUx86MakeData(arch, &guestData)))
1494
            goto error;
J
Jiri Denemark 已提交
1495 1496
    }

1497
 cleanup:
J
Jiri Denemark 已提交
1498 1499 1500 1501 1502 1503 1504 1505
    x86ModelFree(host_model);
    x86ModelFree(diff);
    x86ModelFree(cpu_force);
    x86ModelFree(cpu_require);
    x86ModelFree(cpu_optional);
    x86ModelFree(cpu_disable);
    x86ModelFree(cpu_forbid);
    x86ModelFree(guest_model);
1506
    virCPUx86DataClear(&guestData);
J
Jiri Denemark 已提交
1507 1508 1509

    return ret;

1510
 error:
J
Jiri Denemark 已提交
1511
    ret = VIR_CPU_COMPARE_ERROR;
1512
    goto cleanup;
J
Jiri Denemark 已提交
1513
}
1514
#undef virX86CpuIncompatible
J
Jiri Denemark 已提交
1515 1516 1517 1518


static virCPUCompareResult
x86Compare(virCPUDefPtr host,
1519
           virCPUDefPtr cpu,
1520
           bool failIncompatible)
J
Jiri Denemark 已提交
1521
{
1522 1523 1524 1525 1526
    virCPUCompareResult ret;
    char *message = NULL;

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

1527
    if (failIncompatible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) {
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537
        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 已提交
1538 1539 1540 1541 1542 1543
}


static virCPUCompareResult
x86GuestData(virCPUDefPtr host,
             virCPUDefPtr guest,
1544
             virCPUDataPtr *data,
1545
             char **message)
J
Jiri Denemark 已提交
1546
{
1547
    return x86Compute(host, guest, data, message);
J
Jiri Denemark 已提交
1548 1549
}

1550

1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587
/*
 * Checks whether cpuCandidate is a better fit for the CPU data than the
 * currently selected one from cpuCurrent.
 *
 * Returns 0 if cpuCurrent is better,
 *         1 if cpuCandidate is better,
 *         2 if cpuCandidate is the best one (search should stop now).
 */
static int
x86DecodeUseCandidate(virCPUDefPtr cpuCurrent,
                      virCPUDefPtr cpuCandidate,
                      const char *preferred,
                      bool checkPolicy)
{
    if (checkPolicy) {
        size_t i;
        for (i = 0; i < cpuCandidate->nfeatures; i++) {
            if (cpuCandidate->features[i].policy == VIR_CPU_FEATURE_DISABLE)
                return 0;
            cpuCandidate->features[i].policy = -1;
        }
    }

    if (preferred &&
        STREQ(cpuCandidate->model, preferred))
        return 2;

    if (!cpuCurrent)
        return 1;

    if (cpuCurrent->nfeatures > cpuCandidate->nfeatures)
        return 1;

    return 0;
}


J
Jiri Denemark 已提交
1588 1589
static int
x86Decode(virCPUDefPtr cpu,
1590
          const virCPUx86Data *data,
1591
          const char **models,
1592
          unsigned int nmodels,
1593 1594
          const char *preferred,
          unsigned int flags)
J
Jiri Denemark 已提交
1595 1596
{
    int ret = -1;
J
Jiri Denemark 已提交
1597
    virCPUx86MapPtr map;
J
Jiri Denemark 已提交
1598
    virCPUx86ModelPtr candidate;
1599 1600
    virCPUDefPtr cpuCandidate;
    virCPUDefPtr cpuModel = NULL;
1601 1602
    virCPUx86Data copy = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data features = VIR_CPU_X86_DATA_INIT;
1603
    const virCPUx86Data *cpuData = NULL;
J
Jiri Denemark 已提交
1604
    virCPUx86VendorPtr vendor;
1605
    ssize_t i;
1606
    int rc;
J
Jiri Denemark 已提交
1607

1608 1609
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, -1);
1610

1611
    if (!data || !(map = virCPUx86GetMap()))
J
Jiri Denemark 已提交
1612 1613
        return -1;

J
Jiri Denemark 已提交
1614 1615
    vendor = x86DataToVendor(data, map);

1616 1617 1618 1619 1620
    /* Walk through the CPU models in reverse order to check newest
     * models first.
     */
    for (i = map->nmodels - 1; i >= 0; i--) {
        candidate = map->models[i];
1621
        if (!cpuModelIsAllowed(candidate->name, models, nmodels)) {
1622 1623
            if (preferred && STREQ(candidate->name, preferred)) {
                if (cpu->fallback != VIR_CPU_FALLBACK_ALLOW) {
1624 1625 1626
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("CPU model %s is not supported by hypervisor"),
                                   preferred);
J
Jiri Denemark 已提交
1627
                    goto cleanup;
1628 1629 1630 1631 1632 1633 1634 1635 1636
                } 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);
            }
1637
            continue;
J
Jiri Denemark 已提交
1638 1639
        }

J
Jiri Denemark 已提交
1640 1641 1642 1643
        /* Both vendor and candidate->vendor are pointers to a single list of
         * known vendors stored in the map.
         */
        if (vendor && candidate->vendor && vendor != candidate->vendor) {
J
Jiri Denemark 已提交
1644
            VIR_DEBUG("CPU vendor %s of model %s differs from %s; ignoring",
J
Jiri Denemark 已提交
1645
                      candidate->vendor->name, candidate->name, vendor->name);
1646
            continue;
J
Jiri Denemark 已提交
1647 1648
        }

J
Jiri Denemark 已提交
1649 1650 1651 1652
        if (!(cpuCandidate = x86DataToCPU(data, candidate, map)))
            goto cleanup;
        cpuCandidate->type = cpu->type;

1653 1654
        if ((rc = x86DecodeUseCandidate(cpuModel, cpuCandidate, preferred,
                                        cpu->type == VIR_CPU_TYPE_HOST))) {
1655 1656
            virCPUDefFree(cpuModel);
            cpuModel = cpuCandidate;
1657
            cpuData = &candidate->data;
1658 1659
            if (rc == 2)
                break;
1660
        } else {
1661
            virCPUDefFree(cpuCandidate);
1662
        }
J
Jiri Denemark 已提交
1663 1664
    }

1665
    if (!cpuModel) {
1666 1667
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Cannot find suitable CPU model for given data"));
J
Jiri Denemark 已提交
1668
        goto cleanup;
J
Jiri Denemark 已提交
1669 1670
    }

1671 1672 1673 1674 1675
    /* 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++) {
1676 1677 1678 1679
            size_t j;
            for (j = 0; j < map->nblockers; j++) {
                if (STREQ(map->migrate_blockers[j]->name,
                          cpuModel->features[i].name)) {
1680
                    VIR_FREE(cpuModel->features[i].name);
1681 1682
                    VIR_DELETE_ELEMENT_INPLACE(cpuModel->features, i,
                                               cpuModel->nfeatures);
1683 1684 1685 1686 1687
                }
            }
        }
    }

1688
    if (flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) {
1689 1690
        if (x86DataCopy(&copy, cpuData) < 0 ||
            x86DataFromCPUFeatures(&features, cpuModel, map) < 0)
J
Jiri Denemark 已提交
1691
            goto cleanup;
1692

1693
        x86DataSubtract(&copy, &features);
1694
        if (x86DataToCPUFeatures(cpuModel, VIR_CPU_FEATURE_REQUIRE,
1695
                                 &copy, map) < 0)
J
Jiri Denemark 已提交
1696
            goto cleanup;
1697 1698
    }

J
Jiri Denemark 已提交
1699 1700 1701
    if (vendor && VIR_STRDUP(cpu->vendor, vendor->name) < 0)
        goto cleanup;

1702 1703 1704 1705
    cpu->model = cpuModel->model;
    cpu->nfeatures = cpuModel->nfeatures;
    cpu->features = cpuModel->features;
    VIR_FREE(cpuModel);
J
Jiri Denemark 已提交
1706 1707 1708

    ret = 0;

J
Jiri Denemark 已提交
1709
 cleanup:
1710
    virCPUDefFree(cpuModel);
1711 1712
    virCPUx86DataClear(&copy);
    virCPUx86DataClear(&features);
J
Jiri Denemark 已提交
1713 1714 1715
    return ret;
}

1716 1717
static int
x86DecodeCPUData(virCPUDefPtr cpu,
1718
                 const virCPUData *data,
1719 1720
                 const char **models,
                 unsigned int nmodels,
1721 1722
                 const char *preferred,
                 unsigned int flags)
1723
{
1724
    return x86Decode(cpu, &data->data.x86, models, nmodels, preferred, flags);
1725
}
J
Jiri Denemark 已提交
1726

1727

1728 1729 1730
static int
x86EncodePolicy(virCPUx86Data *data,
                const virCPUDef *cpu,
J
Jiri Denemark 已提交
1731
                virCPUx86MapPtr map,
1732
                virCPUFeaturePolicy policy)
J
Jiri Denemark 已提交
1733
{
J
Jiri Denemark 已提交
1734
    virCPUx86ModelPtr model;
J
Jiri Denemark 已提交
1735 1736

    if (!(model = x86ModelFromCPU(cpu, map, policy)))
1737
        return -1;
J
Jiri Denemark 已提交
1738

1739 1740 1741
    *data = model->data;
    model->data.len = 0;
    model->data.data = NULL;
J
Jiri Denemark 已提交
1742 1743
    x86ModelFree(model);

1744
    return 0;
J
Jiri Denemark 已提交
1745 1746 1747 1748
}


static int
J
Jiri Denemark 已提交
1749
x86Encode(virArch arch,
1750
          const virCPUDef *cpu,
1751 1752 1753 1754 1755 1756
          virCPUDataPtr *forced,
          virCPUDataPtr *required,
          virCPUDataPtr *optional,
          virCPUDataPtr *disabled,
          virCPUDataPtr *forbidden,
          virCPUDataPtr *vendor)
J
Jiri Denemark 已提交
1757
{
J
Jiri Denemark 已提交
1758
    virCPUx86MapPtr map = NULL;
1759 1760 1761 1762 1763 1764
    virCPUx86Data data_forced = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data data_required = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data data_optional = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data data_disabled = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data data_forbidden = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data data_vendor = VIR_CPU_X86_DATA_INIT;
J
Jiri Denemark 已提交
1765

1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778
    if (forced)
        *forced = NULL;
    if (required)
        *required = NULL;
    if (optional)
        *optional = NULL;
    if (disabled)
        *disabled = NULL;
    if (forbidden)
        *forbidden = NULL;
    if (vendor)
        *vendor = NULL;

1779
    if (!(map = virCPUx86GetMap()))
J
Jiri Denemark 已提交
1780 1781
        goto error;

1782 1783 1784
    if (forced &&
        x86EncodePolicy(&data_forced, cpu, map, VIR_CPU_FEATURE_FORCE) < 0)
        goto error;
J
Jiri Denemark 已提交
1785

1786 1787 1788
    if (required &&
        x86EncodePolicy(&data_required, cpu, map, VIR_CPU_FEATURE_REQUIRE) < 0)
        goto error;
J
Jiri Denemark 已提交
1789

1790 1791 1792
    if (optional &&
        x86EncodePolicy(&data_optional, cpu, map, VIR_CPU_FEATURE_OPTIONAL) < 0)
        goto error;
J
Jiri Denemark 已提交
1793

1794 1795 1796
    if (disabled &&
        x86EncodePolicy(&data_disabled, cpu, map, VIR_CPU_FEATURE_DISABLE) < 0)
        goto error;
J
Jiri Denemark 已提交
1797

1798 1799 1800
    if (forbidden &&
        x86EncodePolicy(&data_forbidden, cpu, map, VIR_CPU_FEATURE_FORBID) < 0)
        goto error;
J
Jiri Denemark 已提交
1801

J
Jiri Denemark 已提交
1802
    if (vendor) {
1803
        virCPUx86VendorPtr v = NULL;
J
Jiri Denemark 已提交
1804 1805

        if (cpu->vendor && !(v = x86VendorFind(map, cpu->vendor))) {
1806 1807
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("CPU vendor %s not found"), cpu->vendor);
J
Jiri Denemark 已提交
1808 1809 1810
            goto error;
        }

1811
        if (v && virCPUx86DataAddCPUID(&data_vendor, &v->cpuid) < 0)
J
Jiri Denemark 已提交
1812 1813 1814
            goto error;
    }

1815
    if (forced &&
1816
        !(*forced = virCPUx86MakeData(arch, &data_forced)))
1817 1818
        goto error;
    if (required &&
1819
        !(*required = virCPUx86MakeData(arch, &data_required)))
1820 1821
        goto error;
    if (optional &&
1822
        !(*optional = virCPUx86MakeData(arch, &data_optional)))
1823 1824
        goto error;
    if (disabled &&
1825
        !(*disabled = virCPUx86MakeData(arch, &data_disabled)))
1826 1827
        goto error;
    if (forbidden &&
1828
        !(*forbidden = virCPUx86MakeData(arch, &data_forbidden)))
1829 1830
        goto error;
    if (vendor &&
1831
        !(*vendor = virCPUx86MakeData(arch, &data_vendor)))
1832
        goto error;
J
Jiri Denemark 已提交
1833

1834
    return 0;
J
Jiri Denemark 已提交
1835

1836
 error:
1837 1838 1839 1840 1841 1842
    virCPUx86DataClear(&data_forced);
    virCPUx86DataClear(&data_required);
    virCPUx86DataClear(&data_optional);
    virCPUx86DataClear(&data_disabled);
    virCPUx86DataClear(&data_forbidden);
    virCPUx86DataClear(&data_vendor);
1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854
    if (forced)
        x86FreeCPUData(*forced);
    if (required)
        x86FreeCPUData(*required);
    if (optional)
        x86FreeCPUData(*optional);
    if (disabled)
        x86FreeCPUData(*disabled);
    if (forbidden)
        x86FreeCPUData(*forbidden);
    if (vendor)
        x86FreeCPUData(*vendor);
1855
    return -1;
J
Jiri Denemark 已提交
1856 1857 1858 1859 1860
}


#if HAVE_CPUID
static inline void
1861
cpuidCall(virCPUx86CPUID *cpuid)
J
Jiri Denemark 已提交
1862
{
1863
# if __x86_64__
1864
    asm("xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */
1865
        "xor %%edx, %%edx;" /* functions may use them as additional arguments */
1866
        "cpuid;"
J
Jiri Denemark 已提交
1867 1868 1869 1870
        : "=a" (cpuid->eax),
          "=b" (cpuid->ebx),
          "=c" (cpuid->ecx),
          "=d" (cpuid->edx)
1871 1872
        : "a" (cpuid->eax_in),
          "c" (cpuid->ecx_in));
1873
# else
J
Jiri Denemark 已提交
1874 1875 1876 1877
    /* 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;"
1878
        "xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */
1879
        "xor %%edx, %%edx;" /* functions may use them as additional arguments */
J
Jiri Denemark 已提交
1880 1881 1882 1883 1884 1885 1886
        "cpuid;"
        "mov %%ebx, %1;"
        "pop %%ebx;"
        : "=a" (cpuid->eax),
          "=r" (cpuid->ebx),
          "=c" (cpuid->ecx),
          "=d" (cpuid->edx)
1887 1888
        : "a" (cpuid->eax_in),
          "c" (cpuid->ecx_in)
J
Jiri Denemark 已提交
1889
        : "cc");
1890
# endif
J
Jiri Denemark 已提交
1891 1892 1893 1894
}


static int
1895
cpuidSet(uint32_t base, virCPUx86Data *data)
J
Jiri Denemark 已提交
1896 1897 1898
{
    uint32_t max;
    uint32_t i;
1899
    virCPUx86CPUID cpuid = { .eax_in = base };
J
Jiri Denemark 已提交
1900 1901

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

1904
    for (i = base; i <= max; i++) {
1905
        cpuid.eax_in = i;
1906
        cpuid.ecx_in = 0;
J
Jiri Denemark 已提交
1907
        cpuidCall(&cpuid);
1908 1909
        if (virCPUx86DataAddCPUID(data, &cpuid) < 0)
            return -1;
J
Jiri Denemark 已提交
1910 1911
    }

1912
    return 0;
J
Jiri Denemark 已提交
1913 1914 1915
}


1916
static virCPUDataPtr
1917
x86NodeData(virArch arch)
J
Jiri Denemark 已提交
1918
{
1919
    virCPUDataPtr cpuData = NULL;
1920
    virCPUx86Data data = VIR_CPU_X86_DATA_INIT;
J
Jiri Denemark 已提交
1921

1922
    if (cpuidSet(CPUX86_BASIC, &data) < 0)
J
Jiri Denemark 已提交
1923 1924
        goto error;

1925
    if (cpuidSet(CPUX86_EXTENDED, &data) < 0)
J
Jiri Denemark 已提交
1926 1927
        goto error;

1928
    if (!(cpuData = virCPUx86MakeData(arch, &data)))
1929 1930 1931
        goto error;

    return cpuData;
J
Jiri Denemark 已提交
1932

1933
 error:
1934
    virCPUx86DataClear(&data);
J
Jiri Denemark 已提交
1935 1936 1937 1938 1939 1940

    return NULL;
}
#endif


1941 1942 1943 1944
static virCPUDefPtr
x86Baseline(virCPUDefPtr *cpus,
            unsigned int ncpus,
            const char **models,
1945 1946
            unsigned int nmodels,
            unsigned int flags)
1947
{
J
Jiri Denemark 已提交
1948
    virCPUx86MapPtr map = NULL;
J
Jiri Denemark 已提交
1949
    virCPUx86ModelPtr base_model = NULL;
1950
    virCPUDefPtr cpu = NULL;
1951
    size_t i;
1952
    virCPUx86VendorPtr vendor = NULL;
J
Jiri Denemark 已提交
1953
    virCPUx86ModelPtr model = NULL;
1954
    bool outputVendor = true;
1955 1956
    const char *modelName;
    bool matchingNames = true;
1957

1958 1959 1960
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL);

1961
    if (!(map = virCPUx86GetMap()))
1962 1963
        goto error;

1964
    if (!(base_model = x86ModelFromCPU(cpus[0], map, VIR_CPU_FEATURE_REQUIRE)))
1965 1966
        goto error;

1967
    if (VIR_ALLOC(cpu) < 0)
1968
        goto error;
1969 1970

    cpu->arch = cpus[0]->arch;
1971 1972
    cpu->type = VIR_CPU_TYPE_GUEST;
    cpu->match = VIR_CPU_MATCH_EXACT;
1973

1974
    if (!cpus[0]->vendor) {
1975
        outputVendor = false;
1976
    } else if (!(vendor = x86VendorFind(map, cpus[0]->vendor))) {
1977 1978
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Unknown CPU vendor %s"), cpus[0]->vendor);
J
Jiri Denemark 已提交
1979 1980 1981
        goto error;
    }

1982
    modelName = cpus[0]->model;
1983
    for (i = 1; i < ncpus; i++) {
J
Jiri Denemark 已提交
1984 1985
        const char *vn = NULL;

1986 1987 1988 1989 1990 1991 1992 1993 1994
        if (matchingNames && cpus[i]->model) {
            if (!modelName) {
                modelName = cpus[i]->model;
            } else if (STRNEQ(modelName, cpus[i]->model)) {
                modelName = NULL;
                matchingNames = false;
            }
        }

1995
        if (!(model = x86ModelFromCPU(cpus[i], map, VIR_CPU_FEATURE_REQUIRE)))
1996 1997
            goto error;

J
Jiri Denemark 已提交
1998 1999
        if (cpus[i]->vendor && model->vendor &&
            STRNEQ(cpus[i]->vendor, model->vendor->name)) {
2000 2001 2002
            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 已提交
2003 2004 2005
            goto error;
        }

2006
        if (cpus[i]->vendor) {
J
Jiri Denemark 已提交
2007
            vn = cpus[i]->vendor;
2008
        } else {
2009 2010 2011 2012
            outputVendor = false;
            if (model->vendor)
                vn = model->vendor->name;
        }
J
Jiri Denemark 已提交
2013 2014 2015 2016

        if (vn) {
            if (!vendor) {
                if (!(vendor = x86VendorFind(map, vn))) {
2017 2018
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("Unknown CPU vendor %s"), vn);
J
Jiri Denemark 已提交
2019 2020 2021
                    goto error;
                }
            } else if (STRNEQ(vendor->name, vn)) {
2022 2023
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("CPU vendors do not match"));
J
Jiri Denemark 已提交
2024 2025 2026 2027
                goto error;
            }
        }

2028
        x86DataIntersect(&base_model->data, &model->data);
2029
        x86ModelFree(model);
J
Jiri Denemark 已提交
2030
        model = NULL;
2031 2032
    }

2033
    if (x86DataIsEmpty(&base_model->data)) {
2034 2035
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("CPUs are incompatible"));
2036 2037 2038
        goto error;
    }

2039
    if (vendor && virCPUx86DataAddCPUID(&base_model->data, &vendor->cpuid) < 0)
2040
        goto error;
J
Jiri Denemark 已提交
2041

2042
    if (x86Decode(cpu, &base_model->data, models, nmodels, modelName, flags) < 0)
2043 2044
        goto error;

2045 2046 2047
    if (STREQ_NULLABLE(cpu->model, modelName))
        cpu->fallback = VIR_CPU_FALLBACK_FORBID;

2048 2049 2050
    if (!outputVendor)
        VIR_FREE(cpu->vendor);

2051 2052
    cpu->arch = VIR_ARCH_NONE;

2053
 cleanup:
2054 2055 2056 2057
    x86ModelFree(base_model);

    return cpu;

2058
 error:
J
Jiri Denemark 已提交
2059
    x86ModelFree(model);
2060 2061 2062 2063 2064 2065
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
}


2066
static int
2067
x86UpdateCustom(virCPUDefPtr guest,
2068
                const virCPUDef *host)
2069 2070
{
    int ret = -1;
2071
    size_t i;
J
Jiri Denemark 已提交
2072
    virCPUx86MapPtr map;
J
Jiri Denemark 已提交
2073
    virCPUx86ModelPtr host_model = NULL;
2074

2075
    if (!(map = virCPUx86GetMap()) ||
2076
        !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)))
2077 2078 2079 2080
        goto cleanup;

    for (i = 0; i < guest->nfeatures; i++) {
        if (guest->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) {
2081
            virCPUx86FeaturePtr feature;
2082
            if (!(feature = x86FeatureFind(map, guest->features[i].name))) {
2083 2084 2085
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unknown CPU feature %s"),
                               guest->features[i].name);
2086 2087 2088
                goto cleanup;
            }

2089
            if (x86DataIsSubset(&host_model->data, &feature->data))
2090 2091 2092 2093 2094 2095 2096 2097
                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 已提交
2098 2099
        if (x86ModelSubtractCPU(host_model, guest, map) ||
            x86DataToCPUFeatures(guest, VIR_CPU_FEATURE_REQUIRE,
2100
                                 &host_model->data, map))
2101 2102 2103 2104 2105
            goto cleanup;
    }

    ret = 0;

2106
 cleanup:
2107 2108 2109 2110
    x86ModelFree(host_model);
    return ret;
}

2111 2112 2113

static int
x86UpdateHostModel(virCPUDefPtr guest,
2114 2115
                   const virCPUDef *host,
                   bool passthrough)
2116
{
2117
    virCPUDefPtr oldguest = NULL;
J
Jiri Denemark 已提交
2118
    virCPUx86MapPtr map;
2119
    size_t i;
2120
    int ret = -1;
2121

2122 2123
    if (!(map = virCPUx86GetMap()))
        goto cleanup;
2124 2125 2126

    /* update the host model according to the desired configuration */
    if (!(oldguest = virCPUDefCopy(guest)))
2127
        goto cleanup;
2128 2129 2130

    virCPUDefFreeModel(guest);
    if (virCPUDefCopyModel(guest, host, true) < 0)
2131
        goto cleanup;
2132

2133 2134 2135 2136 2137 2138
    if (oldguest->vendor_id) {
        VIR_FREE(guest->vendor_id);
        if (VIR_STRDUP(guest->vendor_id, oldguest->vendor_id) < 0)
            goto cleanup;
    }

2139 2140 2141 2142
    /* 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++) {
2143 2144 2145
        size_t j;
        for (j = 0; j < map->nblockers; j++) {
            if (STREQ(map->migrate_blockers[j]->name, guest->features[i].name)) {
J
Ján Tomko 已提交
2146
                VIR_FREE(guest->features[i].name);
2147
                VIR_DELETE_ELEMENT_INPLACE(guest->features, i, guest->nfeatures);
J
Ján Tomko 已提交
2148
            }
2149 2150
        }
    }
2151
    for (i = 0; !passthrough && i < oldguest->nfeatures; i++) {
2152 2153 2154
        if (virCPUDefUpdateFeature(guest,
                                   oldguest->features[i].name,
                                   oldguest->features[i].policy) < 0)
2155
            goto cleanup;
2156 2157
    }

2158 2159 2160 2161 2162
    ret = 0;

 cleanup:
    virCPUDefFree(oldguest);
    return ret;
2163 2164 2165
}


2166 2167
static int
x86Update(virCPUDefPtr guest,
2168
          const virCPUDef *host)
2169
{
2170
    switch ((virCPUMode) guest->mode) {
2171 2172 2173 2174
    case VIR_CPU_MODE_CUSTOM:
        return x86UpdateCustom(guest, host);

    case VIR_CPU_MODE_HOST_MODEL:
2175 2176
        guest->match = VIR_CPU_MATCH_EXACT;
        return x86UpdateHostModel(guest, host, false);
2177

2178
    case VIR_CPU_MODE_HOST_PASSTHROUGH:
2179
        guest->match = VIR_CPU_MATCH_MINIMUM;
2180
        return x86UpdateHostModel(guest, host, true);
2181 2182 2183 2184 2185

    case VIR_CPU_MODE_LAST:
        break;
    }

2186 2187
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Unexpected CPU mode: %d"), guest->mode);
2188 2189 2190
    return -1;
}

2191 2192 2193 2194

static int
x86HasFeature(const virCPUData *data,
              const char *name)
D
Daniel P. Berrange 已提交
2195
{
J
Jiri Denemark 已提交
2196
    virCPUx86MapPtr map;
2197
    virCPUx86FeaturePtr feature;
D
Daniel P. Berrange 已提交
2198 2199
    int ret = -1;

2200
    if (!(map = virCPUx86GetMap()))
D
Daniel P. Berrange 已提交
2201 2202
        return -1;

2203 2204
    if (!(feature = x86FeatureFind(map, name)) &&
        !(feature = x86FeatureFindInternal(name)))
D
Daniel P. Berrange 已提交
2205 2206
        goto cleanup;

2207
    ret = x86DataIsSubset(&data->data.x86, &feature->data) ? 1 : 0;
D
Daniel P. Berrange 已提交
2208

2209
 cleanup:
D
Daniel P. Berrange 已提交
2210 2211
    return ret;
}
2212

2213 2214 2215
static int
x86GetModels(char ***models)
{
J
Jiri Denemark 已提交
2216
    virCPUx86MapPtr map;
2217
    size_t i;
2218 2219 2220 2221

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

2222 2223 2224
    if (models) {
        if (VIR_ALLOC_N(*models, map->nmodels + 1) < 0)
            goto error;
2225

2226 2227
        for (i = 0; i < map->nmodels; i++) {
            if (VIR_STRDUP((*models)[i], map->models[i]->name) < 0)
2228 2229
                goto error;
        }
2230 2231
    }

2232
    return map->nmodels;
2233 2234

 error:
2235 2236 2237 2238
    if (models) {
        virStringFreeList(*models);
        *models = NULL;
    }
2239 2240 2241
    return -1;
}

2242

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