cpu_x86.c 83.9 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
 */

#include <config.h>


24
#include "virlog.h"
25
#include "viralloc.h"
J
Jiri Denemark 已提交
26 27 28
#include "cpu.h"
#include "cpu_map.h"
#include "cpu_x86.h"
29
#include "virbuffer.h"
E
Eric Blake 已提交
30
#include "virendian.h"
31
#include "virstring.h"
32
#include "virhostcpu.h"
J
Jiri Denemark 已提交
33 34 35

#define VIR_FROM_THIS VIR_FROM_CPU

36 37
VIR_LOG_INIT("cpu.cpu_x86");

J
Jiri Denemark 已提交
38 39
#define VENDOR_STRING_LENGTH    12

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

42 43 44
typedef struct _virCPUx86Vendor virCPUx86Vendor;
typedef virCPUx86Vendor *virCPUx86VendorPtr;
struct _virCPUx86Vendor {
J
Jiri Denemark 已提交
45
    char *name;
46
    virCPUx86DataItem data;
J
Jiri Denemark 已提交
47 48
};

49 50 51
typedef struct _virCPUx86Feature virCPUx86Feature;
typedef virCPUx86Feature *virCPUx86FeaturePtr;
struct _virCPUx86Feature {
J
Jiri Denemark 已提交
52
    char *name;
53
    virCPUx86Data data;
J
Jiri Denemark 已提交
54
    bool migratable;
J
Jiri Denemark 已提交
55 56
};

57

58 59 60
#define CPUID(...) \
    { .type = VIR_CPU_X86_DATA_CPUID, \
      .data = { .cpuid = {__VA_ARGS__} } }
61

62
#define KVM_FEATURE_DEF(Name, Eax_in, Eax) \
63 64
    static virCPUx86DataItem Name ## _data[] = { \
        CPUID(.eax_in = Eax_in, .eax = Eax), \
65 66
    }

67 68 69 70
#define KVM_FEATURE(Name) \
    { \
        .name = (char *) Name, \
        .data = { \
71 72
            .len = ARRAY_CARDINALITY(Name ## _data), \
            .items = Name ## _data, \
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
    }

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);
102
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_SPINLOCKS,
103 104 105 106 107 108 109
                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);
110 111
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_FREQUENCIES,
                0x40000003, 0x00000800);
112 113
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_REENLIGHTENMENT,
                0x40000003, 0x00002000);
114 115
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_TLBFLUSH,
                0x40000004, 0x00000004);
116 117
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_IPI,
                0x40000004, 0x00000400);
118 119
KVM_FEATURE_DEF(VIR_CPU_x86_KVM_HV_EVMCS,
                0x40000004, 0x00004000);
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135

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),
136
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_SPINLOCKS),
137 138 139
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_VAPIC),
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_VPINDEX),
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_RESET),
140
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_FREQUENCIES),
141
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_REENLIGHTENMENT),
142
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_TLBFLUSH),
143
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_IPI),
144
    KVM_FEATURE(VIR_CPU_x86_KVM_HV_EVMCS),
145 146
};

J
Jiri Denemark 已提交
147 148 149
typedef struct _virCPUx86Model virCPUx86Model;
typedef virCPUx86Model *virCPUx86ModelPtr;
struct _virCPUx86Model {
J
Jiri Denemark 已提交
150
    char *name;
151
    virCPUx86VendorPtr vendor;
152 153
    size_t nsignatures;
    uint32_t *signatures;
154
    virCPUx86Data data;
J
Jiri Denemark 已提交
155 156
};

J
Jiri Denemark 已提交
157 158 159
typedef struct _virCPUx86Map virCPUx86Map;
typedef virCPUx86Map *virCPUx86MapPtr;
struct _virCPUx86Map {
160 161
    size_t nvendors;
    virCPUx86VendorPtr *vendors;
162 163
    size_t nfeatures;
    virCPUx86FeaturePtr *features;
164 165
    size_t nmodels;
    virCPUx86ModelPtr *models;
166 167
    size_t nblockers;
    virCPUx86FeaturePtr *migrate_blockers;
J
Jiri Denemark 已提交
168 169
};

J
Jiri Denemark 已提交
170
static virCPUx86MapPtr cpuMap;
171

172 173
int virCPUx86DriverOnceInit(void);
VIR_ONCE_GLOBAL_INIT(virCPUx86Driver);
174

J
Jiri Denemark 已提交
175

176
typedef enum {
J
Jiri Denemark 已提交
177 178 179 180
    SUBSET,
    EQUAL,
    SUPERSET,
    UNRELATED
181
} virCPUx86CompareResult;
J
Jiri Denemark 已提交
182 183


184 185 186
typedef struct _virCPUx86DataIterator virCPUx86DataIterator;
typedef virCPUx86DataIterator *virCPUx86DataIteratorPtr;
struct _virCPUx86DataIterator {
187
    const virCPUx86Data *data;
J
Jiri Denemark 已提交
188 189
    int pos;
};
J
Jiri Denemark 已提交
190 191


192
#define virCPUx86DataIteratorInit(data) \
193
    { data, -1 }
J
Jiri Denemark 已提交
194 195


196
static bool
197 198
virCPUx86DataItemMatch(const virCPUx86DataItem *item1,
                       const virCPUx86DataItem *item2)
J
Jiri Denemark 已提交
199
{
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
    const virCPUx86CPUID *cpuid1;
    const virCPUx86CPUID *cpuid2;

    switch (item1->type) {
    case VIR_CPU_X86_DATA_CPUID:
        cpuid1 = &item1->data.cpuid;
        cpuid2 = &item2->data.cpuid;
        return (cpuid1->eax == cpuid2->eax &&
                cpuid1->ebx == cpuid2->ebx &&
                cpuid1->ecx == cpuid2->ecx &&
                cpuid1->edx == cpuid2->edx);

    case VIR_CPU_X86_DATA_NONE:
    default:
        return false;
    }
J
Jiri Denemark 已提交
216 217 218
}


219
static bool
220 221
virCPUx86DataItemMatchMasked(const virCPUx86DataItem *item,
                             const virCPUx86DataItem *mask)
J
Jiri Denemark 已提交
222
{
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
    const virCPUx86CPUID *cpuid;
    const virCPUx86CPUID *cpuidMask;

    switch (item->type) {
    case VIR_CPU_X86_DATA_CPUID:
        cpuid = &item->data.cpuid;
        cpuidMask = &mask->data.cpuid;
        return ((cpuid->eax & cpuidMask->eax) == cpuidMask->eax &&
                (cpuid->ebx & cpuidMask->ebx) == cpuidMask->ebx &&
                (cpuid->ecx & cpuidMask->ecx) == cpuidMask->ecx &&
                (cpuid->edx & cpuidMask->edx) == cpuidMask->edx);

    case VIR_CPU_X86_DATA_NONE:
    default:
        return false;
    }
J
Jiri Denemark 已提交
239 240 241
}


J
Jiri Denemark 已提交
242
static void
243 244
virCPUx86DataItemSetBits(virCPUx86DataItemPtr item,
                         const virCPUx86DataItem *mask)
J
Jiri Denemark 已提交
245
{
246 247 248
    virCPUx86CPUIDPtr cpuid;
    const virCPUx86CPUID *cpuidMask;

249 250 251
    if (!mask)
        return;

252 253 254 255 256 257 258 259 260 261 262 263 264 265
    switch (item->type) {
    case VIR_CPU_X86_DATA_CPUID:
        cpuid = &item->data.cpuid;
        cpuidMask = &mask->data.cpuid;
        cpuid->eax |= cpuidMask->eax;
        cpuid->ebx |= cpuidMask->ebx;
        cpuid->ecx |= cpuidMask->ecx;
        cpuid->edx |= cpuidMask->edx;
        break;

    case VIR_CPU_X86_DATA_NONE:
    default:
        break;
    }
J
Jiri Denemark 已提交
266 267 268
}


J
Jiri Denemark 已提交
269
static void
270 271
virCPUx86DataItemClearBits(virCPUx86DataItemPtr item,
                           const virCPUx86DataItem *mask)
J
Jiri Denemark 已提交
272
{
273 274 275
    virCPUx86CPUIDPtr cpuid;
    const virCPUx86CPUID *cpuidMask;

276 277 278
    if (!mask)
        return;

279 280 281 282 283 284 285 286 287 288 289 290 291 292
    switch (item->type) {
    case VIR_CPU_X86_DATA_CPUID:
        cpuid = &item->data.cpuid;
        cpuidMask = &mask->data.cpuid;
        cpuid->eax &= ~cpuidMask->eax;
        cpuid->ebx &= ~cpuidMask->ebx;
        cpuid->ecx &= ~cpuidMask->ecx;
        cpuid->edx &= ~cpuidMask->edx;
        break;

    case VIR_CPU_X86_DATA_NONE:
    default:
        break;
    }
J
Jiri Denemark 已提交
293 294 295
}


J
Jiri Denemark 已提交
296
static void
297 298
virCPUx86DataItemAndBits(virCPUx86DataItemPtr item,
                         const virCPUx86DataItem *mask)
299
{
300 301 302
    virCPUx86CPUIDPtr cpuid;
    const virCPUx86CPUID *cpuidMask;

303 304 305
    if (!mask)
        return;

306 307 308 309 310 311 312 313 314 315 316 317 318 319
    switch (item->type) {
    case VIR_CPU_X86_DATA_CPUID:
        cpuid = &item->data.cpuid;
        cpuidMask = &mask->data.cpuid;
        cpuid->eax &= cpuidMask->eax;
        cpuid->ebx &= cpuidMask->ebx;
        cpuid->ecx &= cpuidMask->ecx;
        cpuid->edx &= cpuidMask->edx;
        break;

    case VIR_CPU_X86_DATA_NONE:
    default:
        break;
    }
320 321
}

322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352

static virCPUx86FeaturePtr
x86FeatureFind(virCPUx86MapPtr map,
               const char *name)
{
    size_t i;

    for (i = 0; i < map->nfeatures; i++) {
        if (STREQ(map->features[i]->name, name))
            return map->features[i];
    }

    return NULL;
}


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;
}


353
static int
354
virCPUx86DataSorter(const void *a, const void *b)
355
{
356 357
    virCPUx86DataItemPtr da = (virCPUx86DataItemPtr) a;
    virCPUx86DataItemPtr db = (virCPUx86DataItemPtr) b;
358

359
    if (da->type > db->type)
360
        return 1;
361
    else if (da->type < db->type)
362 363
        return -1;

364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
    switch (da->type) {
    case VIR_CPU_X86_DATA_CPUID:
        if (da->data.cpuid.eax_in > db->data.cpuid.eax_in)
            return 1;
        else if (da->data.cpuid.eax_in < db->data.cpuid.eax_in)
            return -1;

        if (da->data.cpuid.ecx_in > db->data.cpuid.ecx_in)
            return 1;
        else if (da->data.cpuid.ecx_in < db->data.cpuid.ecx_in)
            return -1;

        break;

    case VIR_CPU_X86_DATA_NONE:
    default:
        break;
    }
382

383 384 385
    return 0;
}

386 387 388 389 390 391 392
static int
virCPUx86DataItemCmp(const virCPUx86DataItem *item1,
                     const virCPUx86DataItem *item2)
{
    return virCPUx86DataSorter(item1, item2);
}

393

394
/* skips all zero CPUID leaves */
395
static virCPUx86DataItemPtr
396
virCPUx86DataNext(virCPUx86DataIteratorPtr iterator)
J
Jiri Denemark 已提交
397
{
398
    const virCPUx86Data *data = iterator->data;
399
    virCPUx86DataItem zero = { 0 };
J
Jiri Denemark 已提交
400

401
    if (!data)
J
Jiri Denemark 已提交
402 403
        return NULL;

404
    while (++iterator->pos < data->len) {
405 406
        virCPUx86DataItemPtr item = data->items + iterator->pos;

407
        if (!virCPUx86DataItemMatch(item, &zero))
408
            return item;
409
    }
J
Jiri Denemark 已提交
410

411
    return NULL;
J
Jiri Denemark 已提交
412 413 414
}


415
static virCPUx86DataItemPtr
J
Jiri Denemark 已提交
416 417
virCPUx86DataGet(const virCPUx86Data *data,
                 const virCPUx86DataItem *item)
J
Jiri Denemark 已提交
418
{
419
    size_t i;
J
Jiri Denemark 已提交
420

421
    for (i = 0; i < data->len; i++) {
422 423 424
        virCPUx86DataItemPtr di = data->items + i;
        if (virCPUx86DataItemCmp(di, item) == 0)
            return di;
J
Jiri Denemark 已提交
425 426
    }

427
    return NULL;
J
Jiri Denemark 已提交
428 429
}

430
static void
431
virCPUx86DataClear(virCPUx86Data *data)
J
Jiri Denemark 已提交
432
{
433
    if (!data)
J
Jiri Denemark 已提交
434 435
        return;

436
    VIR_FREE(data->items);
J
Jiri Denemark 已提交
437 438 439
}


440
static void
J
Jiri Denemark 已提交
441
virCPUx86DataFree(virCPUDataPtr data)
442 443 444 445
{
    if (!data)
        return;

446
    virCPUx86DataClear(&data->data.x86);
447 448 449 450
    VIR_FREE(data);
}


451 452
static int
x86DataCopy(virCPUx86Data *dst, const virCPUx86Data *src)
J
Jiri Denemark 已提交
453
{
454
    size_t i;
J
Jiri Denemark 已提交
455

456
    if (VIR_ALLOC_N(dst->items, src->len) < 0)
457
        return -1;
J
Jiri Denemark 已提交
458

459 460
    dst->len = src->len;
    for (i = 0; i < src->len; i++)
461
        dst->items[i] = src->items[i];
J
Jiri Denemark 已提交
462

463
    return 0;
J
Jiri Denemark 已提交
464 465 466
}


467
static int
468 469
virCPUx86DataAddItem(virCPUx86Data *data,
                     const virCPUx86DataItem *item)
J
Jiri Denemark 已提交
470
{
471
    virCPUx86DataItemPtr existing;
J
Jiri Denemark 已提交
472

J
Jiri Denemark 已提交
473
    if ((existing = virCPUx86DataGet(data, item))) {
474
        virCPUx86DataItemSetBits(existing, item);
475
    } else {
476
        if (VIR_APPEND_ELEMENT_COPY(data->items, data->len,
477
                                    *((virCPUx86DataItemPtr)item)) < 0)
478
            return -1;
J
Jiri Denemark 已提交
479

480
        qsort(data->items, data->len,
481
              sizeof(virCPUx86DataItem), virCPUx86DataSorter);
482
    }
J
Jiri Denemark 已提交
483

J
Jiri Denemark 已提交
484 485 486 487 488
    return 0;
}


static int
489 490
x86DataAdd(virCPUx86Data *data1,
           const virCPUx86Data *data2)
J
Jiri Denemark 已提交
491
{
492
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data2);
J
Jiri Denemark 已提交
493 494 495 496 497
    virCPUx86DataItemPtr item;

    while ((item = virCPUx86DataNext(&iter))) {
        if (virCPUx86DataAddItem(data1, item) < 0)
            return -1;
J
Jiri Denemark 已提交
498
    }
J
Jiri Denemark 已提交
499 500 501 502 503

    return 0;
}


504
static void
505 506
x86DataSubtract(virCPUx86Data *data1,
                const virCPUx86Data *data2)
507
{
508
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data1);
509 510
    virCPUx86DataItemPtr item1;
    virCPUx86DataItemPtr item2;
511

512
    while ((item1 = virCPUx86DataNext(&iter))) {
513 514
        item2 = virCPUx86DataGet(data2, item1);
        virCPUx86DataItemClearBits(item1, item2);
515 516 517 518
    }
}


J
Jiri Denemark 已提交
519
static void
520 521
x86DataIntersect(virCPUx86Data *data1,
                 const virCPUx86Data *data2)
522
{
523
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data1);
524 525
    virCPUx86DataItemPtr item1;
    virCPUx86DataItemPtr item2;
526

527
    while ((item1 = virCPUx86DataNext(&iter))) {
J
Jiri Denemark 已提交
528
        item2 = virCPUx86DataGet(data2, item1);
529
        if (item2)
530
            virCPUx86DataItemAndBits(item1, item2);
J
Jiri Denemark 已提交
531
        else
532
            virCPUx86DataItemClearBits(item1, item1);
533 534 535 536
    }
}


J
Jiri Denemark 已提交
537
static bool
538
x86DataIsEmpty(virCPUx86Data *data)
J
Jiri Denemark 已提交
539
{
540
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data);
J
Jiri Denemark 已提交
541

542
    return !virCPUx86DataNext(&iter);
J
Jiri Denemark 已提交
543
}
J
Jiri Denemark 已提交
544 545


J
Jiri Denemark 已提交
546
static bool
547 548
x86DataIsSubset(const virCPUx86Data *data,
                const virCPUx86Data *subset)
J
Jiri Denemark 已提交
549
{
550
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit((virCPUx86Data *)subset);
551 552
    const virCPUx86DataItem *item;
    const virCPUx86DataItem *itemSubset;
J
Jiri Denemark 已提交
553

554
    while ((itemSubset = virCPUx86DataNext(&iter))) {
J
Jiri Denemark 已提交
555
        if (!(item = virCPUx86DataGet(data, itemSubset)) ||
556
            !virCPUx86DataItemMatchMasked(item, itemSubset))
J
Jiri Denemark 已提交
557
            return false;
J
Jiri Denemark 已提交
558 559
    }

J
Jiri Denemark 已提交
560
    return true;
J
Jiri Denemark 已提交
561 562 563
}


564 565 566 567
/* also removes all detected features from data */
static int
x86DataToCPUFeatures(virCPUDefPtr cpu,
                     int policy,
568
                     virCPUx86Data *data,
J
Jiri Denemark 已提交
569
                     virCPUx86MapPtr map)
570
{
571
    size_t i;
572

573 574
    for (i = 0; i < map->nfeatures; i++) {
        virCPUx86FeaturePtr feature = map->features[i];
575 576
        if (x86DataIsSubset(data, &feature->data)) {
            x86DataSubtract(data, &feature->data);
J
Jiri Denemark 已提交
577 578
            if (virCPUDefAddFeature(cpu, feature->name, policy) < 0)
                return -1;
579 580 581 582 583 584 585
        }
    }

    return 0;
}


J
Jiri Denemark 已提交
586
/* also removes bits corresponding to vendor string from data */
587
static virCPUx86VendorPtr
J
Jiri Denemark 已提交
588
x86DataToVendor(const virCPUx86Data *data,
J
Jiri Denemark 已提交
589
                virCPUx86MapPtr map)
J
Jiri Denemark 已提交
590
{
591
    virCPUx86DataItemPtr item;
592
    size_t i;
J
Jiri Denemark 已提交
593

594 595
    for (i = 0; i < map->nvendors; i++) {
        virCPUx86VendorPtr vendor = map->vendors[i];
J
Jiri Denemark 已提交
596
        if ((item = virCPUx86DataGet(data, &vendor->data)) &&
597
            virCPUx86DataItemMatchMasked(item, &vendor->data)) {
598
            virCPUx86DataItemClearBits(item, &vendor->data);
J
Jiri Denemark 已提交
599 600 601 602 603 604 605 606
            return vendor;
        }
    }

    return NULL;
}


607
static int
608
virCPUx86VendorToData(const char *vendor,
609
                      virCPUx86DataItemPtr item)
610
{
611
    virCPUx86CPUIDPtr cpuid;
612

613 614 615 616 617 618
    if (strlen(vendor) != VENDOR_STRING_LENGTH) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid CPU vendor string '%s'"), vendor);
        return -1;
    }

619 620
    item->type = VIR_CPU_X86_DATA_CPUID;
    cpuid = &item->data.cpuid;
621 622 623 624 625 626 627 628 629 630
    cpuid->eax_in = 0;
    cpuid->ecx_in = 0;
    cpuid->ebx = virReadBufInt32LE(vendor);
    cpuid->edx = virReadBufInt32LE(vendor + 4);
    cpuid->ecx = virReadBufInt32LE(vendor + 8);

    return 0;
}


631 632
static uint32_t
x86MakeSignature(unsigned int family,
633 634
                 unsigned int model,
                 unsigned int stepping)
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
{
    uint32_t sig = 0;

    /*
     * CPU signature (eax from 0x1 CPUID leaf):
     *
     * |31 .. 28|27 .. 20|19 .. 16|15 .. 14|13 .. 12|11 .. 8|7 .. 4|3 .. 0|
     * |   R    | extFam | extMod |   R    | PType  |  Fam  | Mod  | Step |
     *
     * R        reserved
     * extFam   extended family (valid only if Fam == 0xf)
     * extMod   extended model
     * PType    processor type
     * Fam      family
     * Mod      model
     * Step     stepping
     *
     * family = eax[27:20] + eax[11:8]
     * model = eax[19:16] << 4 + eax[7:4]
654
     * stepping = eax[3:0]
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
     */

    /* extFam */
    if (family > 0xf) {
        sig |= (family - 0xf) << 20;
        family = 0xf;
    }

    /* extMod */
    sig |= (model >> 4) << 16;

    /* PType is always 0 */

    /* Fam */
    sig |= family << 8;

    /* Mod */
    sig |= (model & 0xf) << 4;

674 675
    /* Step */
    sig |= stepping & 0xf;
676 677 678 679 680

    return sig;
}


681 682 683 684 685 686
static void
x86DataToSignatureFull(const virCPUx86Data *data,
                       unsigned int *family,
                       unsigned int *model,
                       unsigned int *stepping)
{
687 688 689
    virCPUx86DataItem leaf1 = CPUID(.eax_in = 0x1);
    virCPUx86DataItemPtr item;
    virCPUx86CPUIDPtr cpuid;
690 691 692

    *family = *model = *stepping = 0;

J
Jiri Denemark 已提交
693
    if (!(item = virCPUx86DataGet(data, &leaf1)))
694 695
        return;

696
    cpuid = &item->data.cpuid;
697 698 699 700 701 702
    *family = ((cpuid->eax >> 20) & 0xff) + ((cpuid->eax >> 8) & 0xf);
    *model = ((cpuid->eax >> 12) & 0xf0) + ((cpuid->eax >> 4) & 0xf);
    *stepping = cpuid->eax & 0xf;
}


703 704 705 706 707 708
/* Mask out irrelevant bits (R and Step) from processor signature. */
#define SIGNATURE_MASK  0x0fff3ff0

static uint32_t
x86DataToSignature(const virCPUx86Data *data)
{
709
    virCPUx86DataItem leaf1 = CPUID(.eax_in = 0x1);
710
    virCPUx86DataItemPtr item;
711

J
Jiri Denemark 已提交
712
    if (!(item = virCPUx86DataGet(data, &leaf1)))
713 714
        return 0;

715
    return item->data.cpuid.eax & SIGNATURE_MASK;
716 717 718 719 720 721 722
}


static int
x86DataAddSignature(virCPUx86Data *data,
                    uint32_t signature)
{
723
    virCPUx86DataItem leaf1 = CPUID(.eax_in = 0x1, .eax = signature);
724

725
    return virCPUx86DataAddItem(data, &leaf1);
726 727 728
}


729
static virCPUDefPtr
730
x86DataToCPU(const virCPUx86Data *data,
J
Jiri Denemark 已提交
731
             virCPUx86ModelPtr model,
732 733
             virCPUx86MapPtr map,
             virDomainCapsCPUModelPtr hvModel)
734 735
{
    virCPUDefPtr cpu;
736 737
    virCPUx86Data copy = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data modelData = VIR_CPU_X86_DATA_INIT;
738
    virCPUx86VendorPtr vendor;
739 740

    if (VIR_ALLOC(cpu) < 0 ||
741
        VIR_STRDUP(cpu->model, model->name) < 0 ||
742 743
        x86DataCopy(&copy, data) < 0 ||
        x86DataCopy(&modelData, &model->data) < 0)
744
        goto error;
745

746
    if ((vendor = x86DataToVendor(&copy, map)) &&
747
        VIR_STRDUP(cpu->vendor, vendor->name) < 0)
748
        goto error;
J
Jiri Denemark 已提交
749

750 751
    x86DataSubtract(&copy, &modelData);
    x86DataSubtract(&modelData, data);
752

753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
    /* The hypervisor's version of the CPU model (hvModel) may contain
     * additional features which may be currently unavailable. Such features
     * block usage of the CPU model and we need to explicitly disable them.
     */
    if (hvModel && hvModel->blockers) {
        char **blocker;
        virCPUx86FeaturePtr feature;

        for (blocker = hvModel->blockers; *blocker; blocker++) {
            if ((feature = x86FeatureFind(map, *blocker)) &&
                !x86DataIsSubset(&copy, &feature->data))
                x86DataAdd(&modelData, &feature->data);
        }
    }

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

771 772
    if (x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_REQUIRE, &copy, map) ||
        x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_DISABLE, &modelData, map))
773
        goto error;
774

775
 cleanup:
776 777
    virCPUx86DataClear(&modelData);
    virCPUx86DataClear(&copy);
778 779
    return cpu;

780
 error:
781 782 783 784 785 786
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
}


J
Jiri Denemark 已提交
787
static void
788
x86VendorFree(virCPUx86VendorPtr vendor)
J
Jiri Denemark 已提交
789 790 791 792 793 794
{
    if (!vendor)
        return;

    VIR_FREE(vendor->name);
    VIR_FREE(vendor);
J
Jiri Denemark 已提交
795
}
J
Jiri Denemark 已提交
796 797


798
static virCPUx86VendorPtr
J
Jiri Denemark 已提交
799
x86VendorFind(virCPUx86MapPtr map,
J
Jiri Denemark 已提交
800 801
              const char *name)
{
802
    size_t i;
J
Jiri Denemark 已提交
803

804 805 806
    for (i = 0; i < map->nvendors; i++) {
        if (STREQ(map->vendors[i]->name, name))
            return map->vendors[i];
J
Jiri Denemark 已提交
807 808 809 810 811 812
    }

    return NULL;
}


813
static int
J
Jiri Denemark 已提交
814
x86VendorParse(xmlXPathContextPtr ctxt,
815 816
               const char *name,
               void *data)
J
Jiri Denemark 已提交
817
{
818
    virCPUx86MapPtr map = data;
819
    virCPUx86VendorPtr vendor = NULL;
J
Jiri Denemark 已提交
820
    char *string = NULL;
821
    int ret = -1;
J
Jiri Denemark 已提交
822 823

    if (VIR_ALLOC(vendor) < 0)
824
        goto cleanup;
J
Jiri Denemark 已提交
825

826
    if (VIR_STRDUP(vendor->name, name) < 0)
827
        goto cleanup;
J
Jiri Denemark 已提交
828 829

    if (x86VendorFind(map, vendor->name)) {
830 831
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU vendor %s already defined"), vendor->name);
832
        goto cleanup;
J
Jiri Denemark 已提交
833 834 835 836
    }

    string = virXPathString("string(@string)", ctxt);
    if (!string) {
837
        virReportError(VIR_ERR_INTERNAL_ERROR,
838 839
                       _("Missing vendor string for CPU vendor %s"),
                       vendor->name);
840
        goto cleanup;
J
Jiri Denemark 已提交
841 842
    }

843
    if (virCPUx86VendorToData(string, &vendor->data) < 0)
844
        goto cleanup;
E
Eric Blake 已提交
845

846
    if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0)
847
        goto cleanup;
848 849 850

    ret = 0;

J
Jiri Denemark 已提交
851
 cleanup:
852
    x86VendorFree(vendor);
J
Jiri Denemark 已提交
853
    VIR_FREE(string);
854
    return ret;
J
Jiri Denemark 已提交
855 856 857
}


858
static virCPUx86FeaturePtr
J
Jiri Denemark 已提交
859 860
x86FeatureNew(void)
{
861
    virCPUx86FeaturePtr feature;
J
Jiri Denemark 已提交
862 863 864 865 866 867 868 869

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

    return feature;
}


J
Jiri Denemark 已提交
870
static void
871
x86FeatureFree(virCPUx86FeaturePtr feature)
J
Jiri Denemark 已提交
872
{
873
    if (!feature)
J
Jiri Denemark 已提交
874 875 876
        return;

    VIR_FREE(feature->name);
877
    virCPUx86DataClear(&feature->data);
J
Jiri Denemark 已提交
878 879 880 881
    VIR_FREE(feature);
}


J
Jiri Denemark 已提交
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
static int
x86FeatureInData(const char *name,
                 const virCPUx86Data *data,
                 virCPUx86MapPtr map)
{
    virCPUx86FeaturePtr feature;

    if (!(feature = x86FeatureFind(map, name)) &&
        !(feature = x86FeatureFindInternal(name))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown CPU feature %s"), name);
        return -1;
    }

    if (x86DataIsSubset(data, &feature->data))
        return 1;
    else
        return 0;
}


903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918
static bool
x86FeatureIsMigratable(const char *name,
                       void *cpu_map)
{
    virCPUx86MapPtr map = cpu_map;
    size_t i;

    for (i = 0; i < map->nblockers; i++) {
        if (STREQ(name, map->migrate_blockers[i]->name))
            return false;
    }

    return true;
}


919
static char *
J
Jiri Denemark 已提交
920
x86FeatureNames(virCPUx86MapPtr map,
921
                const char *separator,
922
                virCPUx86Data *data)
923 924 925
{
    virBuffer ret = VIR_BUFFER_INITIALIZER;
    bool first = true;
926
    size_t i;
927 928 929

    virBufferAdd(&ret, "", 0);

930 931
    for (i = 0; i < map->nfeatures; i++) {
        virCPUx86FeaturePtr feature = map->features[i];
932
        if (x86DataIsSubset(data, &feature->data)) {
933 934 935 936 937
            if (!first)
                virBufferAdd(&ret, separator, -1);
            else
                first = false;

938
            virBufferAdd(&ret, feature->name, -1);
939 940 941 942 943 944 945
        }
    }

    return virBufferContentAndReset(&ret);
}


946 947
static int
x86ParseCPUID(xmlXPathContextPtr ctxt,
948
              virCPUx86DataItemPtr item)
949
{
950
    virCPUx86CPUIDPtr cpuid;
951
    unsigned long eax_in, ecx_in;
952
    unsigned long eax, ebx, ecx, edx;
953
    int ret_eax_in, ret_ecx_in, ret_eax, ret_ebx, ret_ecx, ret_edx;
954

955
    memset(item, 0, sizeof(*item));
956

957
    eax_in = ecx_in = 0;
958 959
    eax = ebx = ecx = edx = 0;
    ret_eax_in = virXPathULongHex("string(@eax_in)", ctxt, &eax_in);
960
    ret_ecx_in = virXPathULongHex("string(@ecx_in)", ctxt, &ecx_in);
961 962 963 964 965
    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);

966
    if (ret_eax_in < 0 || ret_ecx_in == -2 ||
967
        ret_eax == -2 || ret_ebx == -2 || ret_ecx == -2 || ret_edx == -2)
968 969
        return -1;

970 971
    item->type = VIR_CPU_X86_DATA_CPUID;
    cpuid = &item->data.cpuid;
972
    cpuid->eax_in = eax_in;
973
    cpuid->ecx_in = ecx_in;
974 975 976 977 978 979 980 981
    cpuid->eax = eax;
    cpuid->ebx = ebx;
    cpuid->ecx = ecx;
    cpuid->edx = edx;
    return 0;
}


982
static int
J
Jiri Denemark 已提交
983
x86FeatureParse(xmlXPathContextPtr ctxt,
984 985
                const char *name,
                void *data)
J
Jiri Denemark 已提交
986
{
987
    virCPUx86MapPtr map = data;
J
Jiri Denemark 已提交
988
    xmlNodePtr *nodes = NULL;
989
    virCPUx86FeaturePtr feature;
990
    virCPUx86DataItem item;
991
    size_t i;
J
Jiri Denemark 已提交
992
    int n;
993
    char *str = NULL;
994
    int ret = -1;
J
Jiri Denemark 已提交
995

J
Jiri Denemark 已提交
996
    if (!(feature = x86FeatureNew()))
997
        goto cleanup;
J
Jiri Denemark 已提交
998

J
Jiri Denemark 已提交
999
    feature->migratable = true;
1000 1001

    if (VIR_STRDUP(feature->name, name) < 0)
1002
        goto cleanup;
J
Jiri Denemark 已提交
1003 1004

    if (x86FeatureFind(map, feature->name)) {
1005 1006
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU feature %s already defined"), feature->name);
1007
        goto cleanup;
J
Jiri Denemark 已提交
1008 1009
    }

1010 1011
    str = virXPathString("string(@migratable)", ctxt);
    if (STREQ_NULLABLE(str, "no"))
J
Jiri Denemark 已提交
1012
        feature->migratable = false;
1013

1014
    n = virXPathNodeSet("./cpuid", ctxt, &nodes);
J
Jiri Denemark 已提交
1015
    if (n < 0)
1016
        goto cleanup;
J
Jiri Denemark 已提交
1017

1018 1019 1020 1021 1022 1023 1024
    if (n == 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Missing cpuid for feature %s"),
                       feature->name);
        goto cleanup;
    }

J
Jiri Denemark 已提交
1025 1026
    for (i = 0; i < n; i++) {
        ctxt->node = nodes[i];
1027
        if (x86ParseCPUID(ctxt, &item) < 0) {
1028
            virReportError(VIR_ERR_INTERNAL_ERROR,
1029 1030
                           _("Invalid cpuid[%zu] in %s feature"),
                           i, feature->name);
1031
            goto cleanup;
J
Jiri Denemark 已提交
1032
        }
1033
        if (virCPUx86DataAddItem(&feature->data, &item))
1034
            goto cleanup;
J
Jiri Denemark 已提交
1035 1036
    }

1037 1038 1039 1040
    if (!feature->migratable &&
        VIR_APPEND_ELEMENT_COPY(map->migrate_blockers,
                                map->nblockers,
                                feature) < 0)
1041
        goto cleanup;
1042 1043

    if (VIR_APPEND_ELEMENT(map->features, map->nfeatures, feature) < 0)
1044
        goto cleanup;
1045 1046 1047

    ret = 0;

J
Jiri Denemark 已提交
1048
 cleanup:
1049
    x86FeatureFree(feature);
1050
    VIR_FREE(nodes);
1051
    VIR_FREE(str);
1052
    return ret;
J
Jiri Denemark 已提交
1053 1054 1055
}


J
Jiri Denemark 已提交
1056
static virCPUx86ModelPtr
J
Jiri Denemark 已提交
1057 1058
x86ModelNew(void)
{
J
Jiri Denemark 已提交
1059
    virCPUx86ModelPtr model;
J
Jiri Denemark 已提交
1060 1061 1062 1063 1064 1065 1066 1067

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

    return model;
}


J
Jiri Denemark 已提交
1068
static void
J
Jiri Denemark 已提交
1069
x86ModelFree(virCPUx86ModelPtr model)
J
Jiri Denemark 已提交
1070
{
1071
    if (!model)
J
Jiri Denemark 已提交
1072 1073 1074
        return;

    VIR_FREE(model->name);
1075
    VIR_FREE(model->signatures);
1076
    virCPUx86DataClear(&model->data);
J
Jiri Denemark 已提交
1077 1078 1079 1080
    VIR_FREE(model);
}


1081 1082 1083 1084
static int
x86ModelCopySignatures(virCPUx86ModelPtr dst,
                       virCPUx86ModelPtr src)
{
1085 1086
    size_t i;

1087 1088 1089
    if (src->nsignatures == 0)
        return 0;

1090 1091 1092 1093 1094 1095
    if (VIR_ALLOC_N(dst->signatures, src->nsignatures) < 0)
        return -1;

    dst->nsignatures = src->nsignatures;
    for (i = 0; i < src->nsignatures; i++)
        dst->signatures[i] = src->signatures[i];
1096 1097 1098 1099 1100

    return 0;
}


J
Jiri Denemark 已提交
1101 1102
static virCPUx86ModelPtr
x86ModelCopy(virCPUx86ModelPtr model)
J
Jiri Denemark 已提交
1103
{
J
Jiri Denemark 已提交
1104
    virCPUx86ModelPtr copy;
J
Jiri Denemark 已提交
1105

1106 1107
    if (VIR_ALLOC(copy) < 0 ||
        VIR_STRDUP(copy->name, model->name) < 0 ||
1108
        x86ModelCopySignatures(copy, model) < 0 ||
1109
        x86DataCopy(&copy->data, &model->data) < 0) {
J
Jiri Denemark 已提交
1110 1111 1112 1113
        x86ModelFree(copy);
        return NULL;
    }

J
Jiri Denemark 已提交
1114
    copy->vendor = model->vendor;
J
Jiri Denemark 已提交
1115 1116 1117 1118 1119

    return copy;
}


J
Jiri Denemark 已提交
1120
static virCPUx86ModelPtr
J
Jiri Denemark 已提交
1121
x86ModelFind(virCPUx86MapPtr map,
J
Jiri Denemark 已提交
1122 1123
             const char *name)
{
1124
    size_t i;
J
Jiri Denemark 已提交
1125

1126 1127 1128
    for (i = 0; i < map->nmodels; i++) {
        if (STREQ(map->models[i]->name, name))
            return map->models[i];
J
Jiri Denemark 已提交
1129 1130 1131 1132 1133 1134
    }

    return NULL;
}


1135 1136 1137 1138 1139 1140 1141 1142 1143
/*
 * Computes CPU model data from a CPU definition associated with features
 * matching @policy. If @policy equals -1, the computed model will describe
 * all CPU features, i.e., it will contain:
 *
 *      features from model
 *      + required and forced features
 *      - disabled and forbidden features
 */
J
Jiri Denemark 已提交
1144
static virCPUx86ModelPtr
1145
x86ModelFromCPU(const virCPUDef *cpu,
J
Jiri Denemark 已提交
1146
                virCPUx86MapPtr map,
J
Jiri Denemark 已提交
1147 1148
                int policy)
{
J
Jiri Denemark 已提交
1149
    virCPUx86ModelPtr model = NULL;
1150
    size_t i;
J
Jiri Denemark 已提交
1151

1152 1153 1154 1155
    /* host CPU only contains required features; requesting other features
     * just returns an empty model
     */
    if (cpu->type == VIR_CPU_TYPE_HOST &&
1156 1157
        policy != VIR_CPU_FEATURE_REQUIRE &&
        policy != -1)
1158 1159
        return x86ModelNew();

J
Jiri Denemark 已提交
1160 1161
    if (cpu->model &&
        (policy == VIR_CPU_FEATURE_REQUIRE || policy == -1)) {
1162
        if (!(model = x86ModelFind(map, cpu->model))) {
1163 1164
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU model %s"), cpu->model);
1165
            return NULL;
J
Jiri Denemark 已提交
1166 1167
        }

1168 1169 1170
        model = x86ModelCopy(model);
    } else {
        model = x86ModelNew();
J
Jiri Denemark 已提交
1171
    }
J
Jiri Denemark 已提交
1172

1173 1174 1175
    if (!model)
        return NULL;

J
Jiri Denemark 已提交
1176
    for (i = 0; i < cpu->nfeatures; i++) {
1177
        virCPUx86FeaturePtr feature;
1178
        virCPUFeaturePolicy fpol;
J
Jiri Denemark 已提交
1179

1180 1181 1182 1183 1184 1185 1186
        if (cpu->features[i].policy == -1)
            fpol = VIR_CPU_FEATURE_REQUIRE;
        else
            fpol = cpu->features[i].policy;

        if ((policy == -1 && fpol == VIR_CPU_FEATURE_OPTIONAL) ||
            (policy != -1 && fpol != policy))
J
Jiri Denemark 已提交
1187 1188
            continue;

1189
        if (!(feature = x86FeatureFind(map, cpu->features[i].name))) {
1190 1191
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU feature %s"), cpu->features[i].name);
J
Jiri Denemark 已提交
1192 1193 1194
            goto error;
        }

1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
        if (policy == -1) {
            switch (fpol) {
            case VIR_CPU_FEATURE_FORCE:
            case VIR_CPU_FEATURE_REQUIRE:
                if (x86DataAdd(&model->data, &feature->data) < 0)
                    goto error;
                break;

            case VIR_CPU_FEATURE_DISABLE:
            case VIR_CPU_FEATURE_FORBID:
                x86DataSubtract(&model->data, &feature->data);
                break;

            /* coverity[dead_error_condition] */
            case VIR_CPU_FEATURE_OPTIONAL:
            case VIR_CPU_FEATURE_LAST:
                break;
            }
        } else if (x86DataAdd(&model->data, &feature->data) < 0) {
1214
            goto error;
1215
        }
J
Jiri Denemark 已提交
1216 1217 1218 1219
    }

    return model;

1220
 error:
J
Jiri Denemark 已提交
1221 1222 1223 1224 1225
    x86ModelFree(model);
    return NULL;
}


1226
static virCPUx86CompareResult
J
Jiri Denemark 已提交
1227 1228
x86ModelCompare(virCPUx86ModelPtr model1,
                virCPUx86ModelPtr model2)
J
Jiri Denemark 已提交
1229
{
1230
    virCPUx86CompareResult result = EQUAL;
1231 1232
    virCPUx86DataIterator iter1 = virCPUx86DataIteratorInit(&model1->data);
    virCPUx86DataIterator iter2 = virCPUx86DataIteratorInit(&model2->data);
1233 1234
    virCPUx86DataItemPtr item1;
    virCPUx86DataItemPtr item2;
J
Jiri Denemark 已提交
1235

1236
    while ((item1 = virCPUx86DataNext(&iter1))) {
1237
        virCPUx86CompareResult match = SUPERSET;
J
Jiri Denemark 已提交
1238

J
Jiri Denemark 已提交
1239
        if ((item2 = virCPUx86DataGet(&model2->data, item1))) {
1240
            if (virCPUx86DataItemMatch(item1, item2))
J
Jiri Denemark 已提交
1241
                continue;
1242
            else if (!virCPUx86DataItemMatchMasked(item1, item2))
J
Jiri Denemark 已提交
1243 1244 1245 1246 1247 1248 1249 1250 1251
                match = SUBSET;
        }

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

1252
    while ((item2 = virCPUx86DataNext(&iter2))) {
1253
        virCPUx86CompareResult match = SUBSET;
J
Jiri Denemark 已提交
1254

J
Jiri Denemark 已提交
1255
        if ((item1 = virCPUx86DataGet(&model1->data, item2))) {
1256
            if (virCPUx86DataItemMatch(item2, item1))
J
Jiri Denemark 已提交
1257
                continue;
1258
            else if (!virCPUx86DataItemMatchMasked(item2, item1))
J
Jiri Denemark 已提交
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
                match = SUPERSET;
        }

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

    return result;
}


1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
static int
x86ModelParseAncestor(virCPUx86ModelPtr model,
                      xmlXPathContextPtr ctxt,
                      virCPUx86MapPtr map)
{
    VIR_AUTOFREE(char *) name = NULL;
    virCPUx86ModelPtr ancestor;
    int rc;

    if ((rc = virXPathBoolean("boolean(./model)", ctxt)) <= 0)
        return rc;

    name = virXPathString("string(./model/@name)", ctxt);
    if (!name) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Missing ancestor's name in CPU model %s"),
                       model->name);
        return -1;
    }

    if (!(ancestor = x86ModelFind(map, name))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Ancestor model %s not found for CPU model %s"),
                       name, model->name);
        return -1;
    }

    model->vendor = ancestor->vendor;
1300 1301
    if (x86ModelCopySignatures(model, ancestor) < 0 ||
        x86DataCopy(&model->data, &ancestor->data) < 0)
1302 1303 1304 1305 1306 1307
        return -1;

    return 0;
}


1308
static int
1309 1310
x86ModelParseSignatures(virCPUx86ModelPtr model,
                        xmlXPathContextPtr ctxt)
J
Jiri Denemark 已提交
1311
{
1312 1313 1314 1315 1316 1317 1318 1319
    VIR_AUTOFREE(xmlNodePtr *) nodes = NULL;
    xmlNodePtr root = ctxt->node;
    size_t i;
    int n;

    if ((n = virXPathNodeSet("./signature", ctxt, &nodes)) <= 0)
        return n;

1320 1321
    /* Remove inherited signatures. */
    VIR_FREE(model->signatures);
J
Jiri Denemark 已提交
1322

1323 1324 1325 1326 1327
    model->nsignatures = n;
    if (VIR_ALLOC_N(model->signatures, n) < 0)
       return -1;

    for (i = 0; i < n; i++) {
1328 1329 1330 1331
        unsigned int sigFamily = 0;
        unsigned int sigModel = 0;
        int rc;

1332
        ctxt->node = nodes[i];
1333

1334
        rc = virXPathUInt("string(@family)", ctxt, &sigFamily);
1335 1336 1337 1338
        if (rc < 0 || sigFamily == 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid CPU signature family in model %s"),
                           model->name);
1339
            return -1;
1340 1341
        }

1342
        rc = virXPathUInt("string(@model)", ctxt, &sigModel);
1343 1344 1345 1346
        if (rc < 0 || sigModel == 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid CPU signature model in model %s"),
                           model->name);
1347
            return -1;
1348 1349
        }

1350
        model->signatures[i] = x86MakeSignature(sigFamily, sigModel, 0);
1351 1352
    }

1353
    ctxt->node = root;
1354 1355 1356 1357
    return 0;
}


1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
static int
x86ModelParseVendor(virCPUx86ModelPtr model,
                    xmlXPathContextPtr ctxt,
                    virCPUx86MapPtr map)
{
    VIR_AUTOFREE(char *) vendor = NULL;
    int rc;

    if ((rc = virXPathBoolean("boolean(./vendor)", ctxt)) <= 0)
        return rc;

    vendor = virXPathString("string(./vendor/@name)", ctxt);
    if (!vendor) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid vendor element in CPU model %s"),
                       model->name);
        return -1;
    }

    if (!(model->vendor = x86VendorFind(map, vendor))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown vendor %s referenced by CPU model %s"),
                       vendor, model->name);
        return -1;
    }

    return 0;
}


1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
static int
x86ModelParseFeatures(virCPUx86ModelPtr model,
                      xmlXPathContextPtr ctxt,
                      virCPUx86MapPtr map)
{
    VIR_AUTOFREE(xmlNodePtr *) nodes = NULL;
    size_t i;
    int n;

    if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) <= 0)
        return n;

    for (i = 0; i < n; i++) {
        VIR_AUTOFREE(char *) ftname = NULL;
        virCPUx86FeaturePtr feature;

        if (!(ftname = virXMLPropString(nodes[i], "name"))) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing feature name for CPU model %s"),
                           model->name);
            return -1;
        }

        if (!(feature = x86FeatureFind(map, ftname))) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Feature %s required by CPU model %s not found"),
                           ftname, model->name);
            return -1;
        }

        if (x86DataAdd(&model->data, &feature->data))
            return -1;
    }

    return 0;
}


1426 1427 1428 1429 1430 1431
static int
x86ModelParse(xmlXPathContextPtr ctxt,
              const char *name,
              void *data)
{
    virCPUx86MapPtr map = data;
1432
    virCPUx86ModelPtr model = NULL;
1433 1434
    int ret = -1;

1435 1436 1437 1438 1439 1440
    if (x86ModelFind(map, name)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Multiple definitions of CPU model '%s'"), name);
        goto cleanup;
    }

1441 1442 1443 1444 1445 1446 1447 1448 1449
    if (!(model = x86ModelNew()))
        goto cleanup;

    if (VIR_STRDUP(model->name, name) < 0)
        goto cleanup;

    if (x86ModelParseAncestor(model, ctxt, map) < 0)
        goto cleanup;

1450
    if (x86ModelParseSignatures(model, ctxt) < 0)
1451 1452
        goto cleanup;

1453 1454
    if (x86ModelParseVendor(model, ctxt, map) < 0)
        goto cleanup;
J
Jiri Denemark 已提交
1455

1456
    if (x86ModelParseFeatures(model, ctxt, map) < 0)
1457
        goto cleanup;
J
Jiri Denemark 已提交
1458

1459
    if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0)
1460
        goto cleanup;
1461 1462 1463

    ret = 0;

J
Jiri Denemark 已提交
1464
 cleanup:
1465
    x86ModelFree(model);
1466
    return ret;
J
Jiri Denemark 已提交
1467 1468 1469
}


J
Jiri Denemark 已提交
1470
static void
J
Jiri Denemark 已提交
1471
x86MapFree(virCPUx86MapPtr map)
J
Jiri Denemark 已提交
1472
{
1473 1474
    size_t i;

1475
    if (!map)
J
Jiri Denemark 已提交
1476 1477
        return;

1478 1479 1480
    for (i = 0; i < map->nfeatures; i++)
        x86FeatureFree(map->features[i]);
    VIR_FREE(map->features);
J
Jiri Denemark 已提交
1481

1482 1483 1484
    for (i = 0; i < map->nmodels; i++)
        x86ModelFree(map->models[i]);
    VIR_FREE(map->models);
J
Jiri Denemark 已提交
1485

1486 1487 1488
    for (i = 0; i < map->nvendors; i++)
        x86VendorFree(map->vendors[i]);
    VIR_FREE(map->vendors);
1489

1490 1491 1492 1493
    /* migrate_blockers only points to the features from map->features list,
     * which were already freed above
     */
    VIR_FREE(map->migrate_blockers);
1494

J
Jiri Denemark 已提交
1495 1496 1497 1498
    VIR_FREE(map);
}


J
Jiri Denemark 已提交
1499
static virCPUx86MapPtr
1500
virCPUx86LoadMap(void)
J
Jiri Denemark 已提交
1501
{
J
Jiri Denemark 已提交
1502
    virCPUx86MapPtr map;
J
Jiri Denemark 已提交
1503

1504
    if (VIR_ALLOC(map) < 0)
J
Jiri Denemark 已提交
1505 1506
        return NULL;

1507
    if (cpuMapLoad("x86", x86VendorParse, x86FeatureParse, x86ModelParse, map) < 0)
J
Jiri Denemark 已提交
1508 1509 1510 1511
        goto error;

    return map;

1512
 error:
J
Jiri Denemark 已提交
1513 1514 1515 1516 1517
    x86MapFree(map);
    return NULL;
}


1518
int
1519
virCPUx86DriverOnceInit(void)
1520
{
J
Jiri Denemark 已提交
1521
    if (!(cpuMap = virCPUx86LoadMap()))
1522 1523 1524 1525 1526 1527
        return -1;

    return 0;
}


J
Jiri Denemark 已提交
1528
static virCPUx86MapPtr
1529 1530
virCPUx86GetMap(void)
{
1531
    if (virCPUx86DriverInitialize() < 0)
1532 1533
        return NULL;

J
Jiri Denemark 已提交
1534
    return cpuMap;
1535 1536 1537
}


1538
static char *
J
Jiri Denemark 已提交
1539
virCPUx86DataFormat(const virCPUData *data)
1540
{
1541
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(&data->data.x86);
1542
    virCPUx86DataItemPtr item;
1543 1544 1545
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virBufferAddLit(&buf, "<cpudata arch='x86'>\n");
1546
    while ((item = virCPUx86DataNext(&iter))) {
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
        virCPUx86CPUIDPtr cpuid;

        switch (item->type) {
        case VIR_CPU_X86_DATA_CPUID:
            cpuid = &item->data.cpuid;
            virBufferAsprintf(&buf,
                              "  <cpuid eax_in='0x%08x' ecx_in='0x%08x'"
                              " eax='0x%08x' ebx='0x%08x'"
                              " ecx='0x%08x' edx='0x%08x'/>\n",
                              cpuid->eax_in, cpuid->ecx_in,
                              cpuid->eax, cpuid->ebx, cpuid->ecx, cpuid->edx);
            break;

        case VIR_CPU_X86_DATA_NONE:
        default:
            break;
        }
1564 1565 1566
    }
    virBufferAddLit(&buf, "</cpudata>\n");

1567
    if (virBufferCheckError(&buf) < 0)
1568 1569 1570 1571 1572 1573 1574
        return NULL;

    return virBufferContentAndReset(&buf);
}


static virCPUDataPtr
J
Jiri Denemark 已提交
1575
virCPUx86DataParse(xmlXPathContextPtr ctxt)
1576 1577 1578
{
    xmlNodePtr *nodes = NULL;
    virCPUDataPtr cpuData = NULL;
1579
    virCPUx86DataItem item;
1580 1581 1582
    size_t i;
    int n;

1583
    n = virXPathNodeSet("/cpudata/cpuid", ctxt, &nodes);
J
Jiri Denemark 已提交
1584
    if (n <= 0) {
1585 1586
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("no x86 CPU data found"));
1587
        goto error;
1588 1589
    }

1590 1591 1592
    if (!(cpuData = virCPUDataNew(VIR_ARCH_X86_64)))
        goto error;

1593 1594
    for (i = 0; i < n; i++) {
        ctxt->node = nodes[i];
1595
        if (x86ParseCPUID(ctxt, &item) < 0) {
1596 1597
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("failed to parse cpuid[%zu]"), i);
1598
            goto error;
1599
        }
1600
        if (virCPUx86DataAdd(cpuData, &item) < 0)
1601
            goto error;
1602 1603
    }

1604
 cleanup:
1605 1606
    VIR_FREE(nodes);
    return cpuData;
1607 1608

 error:
J
Jiri Denemark 已提交
1609
    virCPUx86DataFree(cpuData);
1610 1611
    cpuData = NULL;
    goto cleanup;
1612 1613 1614
}


1615 1616 1617
/* A helper macro to exit the cpu computation function without writing
 * redundant code:
 * MSG: error message
1618
 * CPU_DEF: a virCPUx86Data pointer with flags that are conflicting
1619 1620 1621 1622
 * RET: return code to set
 *
 * This macro generates the error string outputs it into logs.
 */
1623 1624 1625 1626 1627 1628 1629 1630
#define virX86CpuIncompatible(MSG, CPU_DEF) \
        do { \
            char *flagsStr = NULL; \
            if (!(flagsStr = x86FeatureNames(map, ", ", (CPU_DEF)))) { \
                virReportOOMError(); \
                goto error; \
            } \
            if (message && \
1631
                virAsprintf(message, "%s: %s", _(MSG), flagsStr) < 0) { \
1632 1633 1634 1635 1636 1637
                VIR_FREE(flagsStr); \
                goto error; \
            } \
            VIR_DEBUG("%s: %s", MSG, flagsStr); \
            VIR_FREE(flagsStr); \
            ret = VIR_CPU_COMPARE_INCOMPATIBLE; \
1638 1639
        } while (0)

1640

J
Jiri Denemark 已提交
1641 1642 1643
static virCPUCompareResult
x86Compute(virCPUDefPtr host,
           virCPUDefPtr cpu,
1644
           virCPUDataPtr *guest,
1645
           char **message)
J
Jiri Denemark 已提交
1646
{
J
Jiri Denemark 已提交
1647
    virCPUx86MapPtr map = NULL;
J
Jiri Denemark 已提交
1648 1649 1650 1651 1652 1653 1654 1655
    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;
1656
    virCPUDataPtr guestData = NULL;
J
Jiri Denemark 已提交
1657
    virCPUCompareResult ret;
1658
    virCPUx86CompareResult result;
J
Jiri Denemark 已提交
1659
    virArch arch;
1660
    size_t i;
J
Jiri Denemark 已提交
1661

1662
    if (cpu->arch != VIR_ARCH_NONE) {
J
Jiri Denemark 已提交
1663 1664 1665
        bool found = false;

        for (i = 0; i < ARRAY_CARDINALITY(archs); i++) {
1666
            if (archs[i] == cpu->arch) {
J
Jiri Denemark 已提交
1667 1668 1669 1670 1671
                found = true;
                break;
            }
        }

1672
        if (!found) {
1673 1674
            VIR_DEBUG("CPU arch %s does not match host arch",
                      virArchToString(cpu->arch));
1675 1676 1677
            if (message &&
                virAsprintf(message,
                            _("CPU arch %s does not match host arch"),
1678
                            virArchToString(cpu->arch)) < 0)
1679
                goto error;
J
Jiri Denemark 已提交
1680
            return VIR_CPU_COMPARE_INCOMPATIBLE;
1681
        }
J
Jiri Denemark 已提交
1682 1683 1684
        arch = cpu->arch;
    } else {
        arch = host->arch;
J
Jiri Denemark 已提交
1685 1686
    }

J
Jiri Denemark 已提交
1687 1688 1689 1690
    if (cpu->vendor &&
        (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) {
        VIR_DEBUG("host CPU vendor does not match required CPU vendor %s",
                  cpu->vendor);
1691 1692 1693 1694 1695
        if (message &&
            virAsprintf(message,
                        _("host CPU vendor does not match required "
                          "CPU vendor %s"),
                        cpu->vendor) < 0)
1696
            goto error;
1697

J
Jiri Denemark 已提交
1698 1699 1700
        return VIR_CPU_COMPARE_INCOMPATIBLE;
    }

1701
    if (!(map = virCPUx86GetMap()) ||
J
Jiri Denemark 已提交
1702
        !(host_model = x86ModelFromCPU(host, map, -1)) ||
J
Jiri Denemark 已提交
1703 1704 1705 1706 1707
        !(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 已提交
1708 1709
        goto error;

1710 1711
    x86DataIntersect(&cpu_forbid->data, &host_model->data);
    if (!x86DataIsEmpty(&cpu_forbid->data)) {
1712
        virX86CpuIncompatible(N_("Host CPU provides forbidden features"),
1713
                              &cpu_forbid->data);
1714
        goto cleanup;
J
Jiri Denemark 已提交
1715 1716
    }

1717 1718 1719
    /* first remove features that were inherited from the CPU model and were
     * explicitly forced, disabled, or made optional
     */
1720 1721 1722
    x86DataSubtract(&cpu_require->data, &cpu_force->data);
    x86DataSubtract(&cpu_require->data, &cpu_optional->data);
    x86DataSubtract(&cpu_require->data, &cpu_disable->data);
J
Jiri Denemark 已提交
1723 1724
    result = x86ModelCompare(host_model, cpu_require);
    if (result == SUBSET || result == UNRELATED) {
1725
        x86DataSubtract(&cpu_require->data, &host_model->data);
1726 1727
        virX86CpuIncompatible(N_("Host CPU does not provide required "
                                 "features"),
1728
                              &cpu_require->data);
1729
        goto cleanup;
J
Jiri Denemark 已提交
1730 1731 1732 1733
    }

    ret = VIR_CPU_COMPARE_IDENTICAL;

1734
    if (!(diff = x86ModelCopy(host_model)))
1735
        goto error;
J
Jiri Denemark 已提交
1736

1737 1738 1739 1740
    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 已提交
1741

1742
    if (!x86DataIsEmpty(&diff->data))
J
Jiri Denemark 已提交
1743
        ret = VIR_CPU_COMPARE_SUPERSET;
J
Jiri Denemark 已提交
1744 1745 1746 1747

    if (ret == VIR_CPU_COMPARE_SUPERSET
        && cpu->type == VIR_CPU_TYPE_GUEST
        && cpu->match == VIR_CPU_MATCH_STRICT) {
1748 1749
        virX86CpuIncompatible(N_("Host CPU does not strictly match guest CPU: "
                                 "Extra features"),
1750
                              &diff->data);
1751
        goto cleanup;
J
Jiri Denemark 已提交
1752 1753
    }

1754 1755
    if (guest) {
        if (!(guest_model = x86ModelCopy(host_model)))
1756
            goto error;
J
Jiri Denemark 已提交
1757

1758
        if (cpu->vendor && host_model->vendor &&
1759 1760
            virCPUx86DataAddItem(&guest_model->data,
                                 &host_model->vendor->data) < 0)
1761 1762
            goto error;

1763 1764
        if (host_model->signatures &&
            x86DataAddSignature(&guest_model->data, *host_model->signatures) < 0)
1765 1766
            goto error;

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

1771
        if (x86DataAdd(&guest_model->data, &cpu_force->data))
1772
            goto error;
J
Jiri Denemark 已提交
1773

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

1776 1777
        if (!(guestData = virCPUDataNew(arch)) ||
            x86DataCopy(&guestData->data.x86, &guest_model->data) < 0)
1778
            goto error;
1779 1780

        *guest = guestData;
J
Jiri Denemark 已提交
1781 1782
    }

1783
 cleanup:
J
Jiri Denemark 已提交
1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794
    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;

1795
 error:
J
Jiri Denemark 已提交
1796
    virCPUx86DataFree(guestData);
J
Jiri Denemark 已提交
1797
    ret = VIR_CPU_COMPARE_ERROR;
1798
    goto cleanup;
J
Jiri Denemark 已提交
1799
}
1800
#undef virX86CpuIncompatible
J
Jiri Denemark 已提交
1801 1802 1803


static virCPUCompareResult
J
Jiri Denemark 已提交
1804 1805 1806
virCPUx86Compare(virCPUDefPtr host,
                 virCPUDefPtr cpu,
                 bool failIncompatible)
J
Jiri Denemark 已提交
1807
{
J
Jiri Denemark 已提交
1808 1809 1810
    virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;
    virCPUx86MapPtr map;
    virCPUx86ModelPtr model = NULL;
1811 1812
    char *message = NULL;

J
Jiri Denemark 已提交
1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823
    if (!host || !host->model) {
        if (failIncompatible) {
            virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s",
                           _("unknown host CPU"));
        } else {
            VIR_WARN("unknown host CPU");
            ret = VIR_CPU_COMPARE_INCOMPATIBLE;
        }
        goto cleanup;
    }

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

J
Jiri Denemark 已提交
1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859
    if (ret == VIR_CPU_COMPARE_INCOMPATIBLE) {
        bool noTSX = false;

        if (STREQ_NULLABLE(cpu->model, "Haswell") ||
            STREQ_NULLABLE(cpu->model, "Broadwell")) {
            if (!(map = virCPUx86GetMap()))
                goto cleanup;

            if (!(model = x86ModelFromCPU(cpu, map, -1)))
                goto cleanup;

            noTSX = !x86FeatureInData("hle", &model->data, map) ||
                    !x86FeatureInData("rtm", &model->data, map);
        }

        if (failIncompatible) {
            ret = VIR_CPU_COMPARE_ERROR;
            if (message) {
                if (noTSX) {
                    virReportError(VIR_ERR_CPU_INCOMPATIBLE,
                                   _("%s; try using '%s-noTSX' CPU model"),
                                   message, cpu->model);
                } else {
                    virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", message);
                }
            } else {
                if (noTSX) {
                    virReportError(VIR_ERR_CPU_INCOMPATIBLE,
                                   _("try using '%s-noTSX' CPU model"),
                                   cpu->model);
                } else {
                    virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL);
                }
            }
1860 1861 1862
        }
    }

J
Jiri Denemark 已提交
1863 1864 1865
 cleanup:
    VIR_FREE(message);
    x86ModelFree(model);
1866
    return ret;
J
Jiri Denemark 已提交
1867 1868 1869
}


1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884
static bool
x86ModelHasSignature(virCPUx86ModelPtr model,
                     uint32_t signature)
{
    size_t i;

    for (i = 0; i < model->nsignatures; i++) {
        if (model->signatures[i] == signature)
            return true;
    }

    return false;
}


1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904
static char *
x86FormatSignatures(virCPUx86ModelPtr model)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    size_t i;

    for (i = 0; i < model->nsignatures; i++) {
        virBufferAsprintf(&buf, "%06lx,",
                          (unsigned long)model->signatures[i]);
    }

    virBufferTrim(&buf, ",", -1);

    if (virBufferCheckError(&buf) < 0)
        return NULL;

    return virBufferContentAndReset(&buf);
}


1905
/*
1906 1907
 * Checks whether a candidate model is a better fit for the CPU data than the
 * current model.
1908
 *
1909 1910 1911
 * Returns 0 if current is better,
 *         1 if candidate is better,
 *         2 if candidate is the best one (search should stop now).
1912 1913
 */
static int
1914 1915 1916
x86DecodeUseCandidate(virCPUx86ModelPtr current,
                      virCPUDefPtr cpuCurrent,
                      virCPUx86ModelPtr candidate,
1917
                      virCPUDefPtr cpuCandidate,
1918
                      uint32_t signature,
1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930
                      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;
        }
    }

1931 1932
    if (preferred && STREQ(cpuCandidate->model, preferred)) {
        VIR_DEBUG("%s is the preferred model", cpuCandidate->model);
1933
        return 2;
1934
    }
1935

1936 1937
    if (!cpuCurrent) {
        VIR_DEBUG("%s is better than nothing", cpuCandidate->model);
1938
        return 1;
1939
    }
1940

1941 1942 1943 1944 1945
    /* Ideally we want to select a model with family/model equal to
     * family/model of the real CPU. Once we found such model, we only
     * consider candidates with matching family/model.
     */
    if (signature &&
1946 1947
        x86ModelHasSignature(current, signature) &&
        !x86ModelHasSignature(candidate, signature)) {
1948 1949
        VIR_DEBUG("%s differs in signature from matching %s",
                  cpuCandidate->model, cpuCurrent->model);
1950
        return 0;
1951
    }
1952

1953 1954 1955
    if (cpuCurrent->nfeatures > cpuCandidate->nfeatures) {
        VIR_DEBUG("%s results in shorter feature list than %s",
                  cpuCandidate->model, cpuCurrent->model);
1956
        return 1;
1957
    }
1958

1959 1960 1961 1962
    /* Prefer a candidate with matching signature even though it would
     * result in longer list of features.
     */
    if (signature &&
1963 1964
        x86ModelHasSignature(candidate, signature) &&
        !x86ModelHasSignature(current, signature)) {
1965
        VIR_DEBUG("%s provides matching signature", cpuCandidate->model);
1966
        return 1;
1967
    }
1968

1969 1970
    VIR_DEBUG("%s does not result in shorter feature list than %s",
              cpuCandidate->model, cpuCurrent->model);
1971 1972 1973 1974
    return 0;
}


1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009
/**
 * Drop broken TSX features.
 */
static void
x86DataFilterTSX(virCPUx86Data *data,
                 virCPUx86VendorPtr vendor,
                 virCPUx86MapPtr map)
{
    unsigned int family;
    unsigned int model;
    unsigned int stepping;

    if (!vendor || STRNEQ(vendor->name, "Intel"))
        return;

    x86DataToSignatureFull(data, &family, &model, &stepping);

    if (family == 6 &&
        ((model == 63 && stepping < 4) ||
         model == 60 ||
         model == 69 ||
         model == 70)) {
        virCPUx86FeaturePtr feature;

        VIR_DEBUG("Dropping broken TSX");

        if ((feature = x86FeatureFind(map, "hle")))
            x86DataSubtract(data, &feature->data);

        if ((feature = x86FeatureFind(map, "rtm")))
            x86DataSubtract(data, &feature->data);
    }
}


J
Jiri Denemark 已提交
2010 2011
static int
x86Decode(virCPUDefPtr cpu,
2012
          const virCPUx86Data *cpuData,
2013
          virDomainCapsCPUModelsPtr models,
2014
          const char *preferred,
2015
          bool migratable)
J
Jiri Denemark 已提交
2016 2017
{
    int ret = -1;
J
Jiri Denemark 已提交
2018
    virCPUx86MapPtr map;
J
Jiri Denemark 已提交
2019
    virCPUx86ModelPtr candidate;
2020
    virCPUDefPtr cpuCandidate;
2021
    virCPUx86ModelPtr model = NULL;
2022
    virCPUDefPtr cpuModel = NULL;
2023
    virCPUx86Data data = VIR_CPU_X86_DATA_INIT;
2024 2025
    virCPUx86Data copy = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data features = VIR_CPU_X86_DATA_INIT;
J
Jiri Denemark 已提交
2026
    virCPUx86VendorPtr vendor;
2027
    virDomainCapsCPUModelPtr hvModel = NULL;
2028
    VIR_AUTOFREE(char *) sigs = NULL;
2029
    uint32_t signature;
2030
    ssize_t i;
2031
    int rc;
J
Jiri Denemark 已提交
2032

2033
    if (!cpuData || x86DataCopy(&data, cpuData) < 0)
J
Jiri Denemark 已提交
2034 2035
        return -1;

2036 2037 2038 2039 2040 2041 2042
    if (!(map = virCPUx86GetMap()))
        goto cleanup;

    vendor = x86DataToVendor(&data, map);
    signature = x86DataToSignature(&data);

    x86DataFilterTSX(&data, vendor, map);
J
Jiri Denemark 已提交
2043

2044 2045 2046 2047 2048
    /* 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];
2049 2050
        if (models &&
            !(hvModel = virDomainCapsCPUModelsGet(models, candidate->name))) {
2051 2052
            if (preferred && STREQ(candidate->name, preferred)) {
                if (cpu->fallback != VIR_CPU_FALLBACK_ALLOW) {
2053 2054 2055
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("CPU model %s is not supported by hypervisor"),
                                   preferred);
J
Jiri Denemark 已提交
2056
                    goto cleanup;
2057 2058 2059 2060 2061 2062 2063 2064 2065
                } 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);
            }
2066
            continue;
J
Jiri Denemark 已提交
2067 2068
        }

J
Jiri Denemark 已提交
2069 2070 2071 2072
        /* 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 已提交
2073
            VIR_DEBUG("CPU vendor %s of model %s differs from %s; ignoring",
J
Jiri Denemark 已提交
2074
                      candidate->vendor->name, candidate->name, vendor->name);
2075
            continue;
J
Jiri Denemark 已提交
2076 2077
        }

2078
        if (!(cpuCandidate = x86DataToCPU(&data, candidate, map, hvModel)))
J
Jiri Denemark 已提交
2079 2080 2081
            goto cleanup;
        cpuCandidate->type = cpu->type;

2082 2083 2084
        if ((rc = x86DecodeUseCandidate(model, cpuModel,
                                        candidate, cpuCandidate,
                                        signature, preferred,
2085
                                        cpu->type == VIR_CPU_TYPE_HOST))) {
2086 2087
            virCPUDefFree(cpuModel);
            cpuModel = cpuCandidate;
2088
            model = candidate;
2089 2090
            if (rc == 2)
                break;
2091
        } else {
2092
            virCPUDefFree(cpuCandidate);
2093
        }
J
Jiri Denemark 已提交
2094 2095
    }

2096
    if (!cpuModel) {
2097 2098
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Cannot find suitable CPU model for given data"));
J
Jiri Denemark 已提交
2099
        goto cleanup;
J
Jiri Denemark 已提交
2100 2101
    }

2102 2103 2104
    /* Remove non-migratable features if requested
     * Note: this only works as long as no CPU model contains non-migratable
     * features directly */
2105
    if (migratable) {
2106 2107 2108 2109 2110
        i = 0;
        while (i < cpuModel->nfeatures) {
            if (x86FeatureIsMigratable(cpuModel->features[i].name, map)) {
                i++;
            } else {
2111 2112 2113
                VIR_FREE(cpuModel->features[i].name);
                VIR_DELETE_ELEMENT_INPLACE(cpuModel->features, i,
                                           cpuModel->nfeatures);
2114 2115 2116 2117
            }
        }
    }

J
Jiri Denemark 已提交
2118 2119 2120
    if (vendor && VIR_STRDUP(cpu->vendor, vendor->name) < 0)
        goto cleanup;

2121 2122 2123 2124 2125
    sigs = x86FormatSignatures(model);

    VIR_DEBUG("Using CPU model %s (signatures %s) for CPU with signature %06lx",
              model->name, NULLSTR(sigs), (unsigned long)signature);

2126 2127
    VIR_STEAL_PTR(cpu->model, cpuModel->model);
    VIR_STEAL_PTR(cpu->features, cpuModel->features);
2128
    cpu->nfeatures = cpuModel->nfeatures;
2129 2130 2131
    cpuModel->nfeatures = 0;
    cpu->nfeatures_max = cpuModel->nfeatures_max;
    cpuModel->nfeatures_max = 0;
J
Jiri Denemark 已提交
2132 2133 2134

    ret = 0;

J
Jiri Denemark 已提交
2135
 cleanup:
2136
    virCPUDefFree(cpuModel);
2137
    virCPUx86DataClear(&data);
2138 2139
    virCPUx86DataClear(&copy);
    virCPUx86DataClear(&features);
J
Jiri Denemark 已提交
2140 2141 2142
    return ret;
}

2143 2144
static int
x86DecodeCPUData(virCPUDefPtr cpu,
2145
                 const virCPUData *data,
2146
                 virDomainCapsCPUModelsPtr models)
2147
{
2148
    return x86Decode(cpu, &data->data.x86, models, NULL, false);
2149
}
J
Jiri Denemark 已提交
2150

2151

2152 2153 2154
static int
x86EncodePolicy(virCPUx86Data *data,
                const virCPUDef *cpu,
J
Jiri Denemark 已提交
2155
                virCPUx86MapPtr map,
2156
                virCPUFeaturePolicy policy)
J
Jiri Denemark 已提交
2157
{
J
Jiri Denemark 已提交
2158
    virCPUx86ModelPtr model;
J
Jiri Denemark 已提交
2159 2160

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

2163 2164
    *data = model->data;
    model->data.len = 0;
2165
    model->data.items = NULL;
J
Jiri Denemark 已提交
2166 2167
    x86ModelFree(model);

2168
    return 0;
J
Jiri Denemark 已提交
2169 2170 2171 2172
}


static int
J
Jiri Denemark 已提交
2173
x86Encode(virArch arch,
2174
          const virCPUDef *cpu,
2175 2176 2177 2178 2179 2180
          virCPUDataPtr *forced,
          virCPUDataPtr *required,
          virCPUDataPtr *optional,
          virCPUDataPtr *disabled,
          virCPUDataPtr *forbidden,
          virCPUDataPtr *vendor)
J
Jiri Denemark 已提交
2181
{
J
Jiri Denemark 已提交
2182
    virCPUx86MapPtr map = NULL;
2183 2184 2185 2186 2187 2188
    virCPUDataPtr data_forced = NULL;
    virCPUDataPtr data_required = NULL;
    virCPUDataPtr data_optional = NULL;
    virCPUDataPtr data_disabled = NULL;
    virCPUDataPtr data_forbidden = NULL;
    virCPUDataPtr data_vendor = NULL;
J
Jiri Denemark 已提交
2189

2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202
    if (forced)
        *forced = NULL;
    if (required)
        *required = NULL;
    if (optional)
        *optional = NULL;
    if (disabled)
        *disabled = NULL;
    if (forbidden)
        *forbidden = NULL;
    if (vendor)
        *vendor = NULL;

2203
    if (!(map = virCPUx86GetMap()))
J
Jiri Denemark 已提交
2204 2205
        goto error;

2206
    if (forced &&
2207 2208 2209
        (!(data_forced = virCPUDataNew(arch)) ||
         x86EncodePolicy(&data_forced->data.x86, cpu, map,
                         VIR_CPU_FEATURE_FORCE) < 0))
2210
        goto error;
J
Jiri Denemark 已提交
2211

2212
    if (required &&
2213 2214 2215
        (!(data_required = virCPUDataNew(arch)) ||
         x86EncodePolicy(&data_required->data.x86, cpu, map,
                         VIR_CPU_FEATURE_REQUIRE) < 0))
2216
        goto error;
J
Jiri Denemark 已提交
2217

2218
    if (optional &&
2219 2220 2221
        (!(data_optional = virCPUDataNew(arch)) ||
         x86EncodePolicy(&data_optional->data.x86, cpu, map,
                         VIR_CPU_FEATURE_OPTIONAL) < 0))
2222
        goto error;
J
Jiri Denemark 已提交
2223

2224
    if (disabled &&
2225 2226 2227
        (!(data_disabled = virCPUDataNew(arch)) ||
         x86EncodePolicy(&data_disabled->data.x86, cpu, map,
                         VIR_CPU_FEATURE_DISABLE) < 0))
2228
        goto error;
J
Jiri Denemark 已提交
2229

2230
    if (forbidden &&
2231 2232 2233
        (!(data_forbidden = virCPUDataNew(arch)) ||
         x86EncodePolicy(&data_forbidden->data.x86, cpu, map,
                         VIR_CPU_FEATURE_FORBID) < 0))
2234
        goto error;
J
Jiri Denemark 已提交
2235

J
Jiri Denemark 已提交
2236
    if (vendor) {
2237
        virCPUx86VendorPtr v = NULL;
J
Jiri Denemark 已提交
2238 2239

        if (cpu->vendor && !(v = x86VendorFind(map, cpu->vendor))) {
2240 2241
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("CPU vendor %s not found"), cpu->vendor);
J
Jiri Denemark 已提交
2242 2243 2244
            goto error;
        }

2245
        if (!(data_vendor = virCPUDataNew(arch)))
J
Jiri Denemark 已提交
2246 2247
            goto error;

2248
        if (v && virCPUx86DataAdd(data_vendor, &v->data) < 0)
2249 2250
            goto error;
    }
J
Jiri Denemark 已提交
2251

2252
    if (forced)
2253
        *forced = data_forced;
2254
    if (required)
2255
        *required = data_required;
2256
    if (optional)
2257
        *optional = data_optional;
2258
    if (disabled)
2259
        *disabled = data_disabled;
2260
    if (forbidden)
2261
        *forbidden = data_forbidden;
2262
    if (vendor)
2263 2264 2265 2266 2267
        *vendor = data_vendor;

    return 0;

 error:
J
Jiri Denemark 已提交
2268 2269 2270 2271 2272 2273
    virCPUx86DataFree(data_forced);
    virCPUx86DataFree(data_required);
    virCPUx86DataFree(data_optional);
    virCPUx86DataFree(data_disabled);
    virCPUx86DataFree(data_forbidden);
    virCPUx86DataFree(data_vendor);
2274
    return -1;
J
Jiri Denemark 已提交
2275 2276 2277
}


P
Pavel Hrdina 已提交
2278
#if defined(__i386__) || defined(__x86_64__)
J
Jiri Denemark 已提交
2279
static inline void
2280
cpuidCall(virCPUx86CPUID *cpuid)
J
Jiri Denemark 已提交
2281
{
2282
# if __x86_64__
2283
    asm("xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */
2284
        "xor %%edx, %%edx;" /* functions may use them as additional arguments */
2285
        "cpuid;"
J
Jiri Denemark 已提交
2286 2287 2288 2289
        : "=a" (cpuid->eax),
          "=b" (cpuid->ebx),
          "=c" (cpuid->ecx),
          "=d" (cpuid->edx)
2290 2291
        : "a" (cpuid->eax_in),
          "c" (cpuid->ecx_in));
2292
# else
J
Jiri Denemark 已提交
2293 2294 2295 2296
    /* 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;"
2297
        "xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */
2298
        "xor %%edx, %%edx;" /* functions may use them as additional arguments */
J
Jiri Denemark 已提交
2299 2300 2301 2302 2303 2304 2305
        "cpuid;"
        "mov %%ebx, %1;"
        "pop %%ebx;"
        : "=a" (cpuid->eax),
          "=r" (cpuid->ebx),
          "=c" (cpuid->ecx),
          "=d" (cpuid->edx)
2306 2307
        : "a" (cpuid->eax_in),
          "c" (cpuid->ecx_in)
J
Jiri Denemark 已提交
2308
        : "cc");
2309
# endif
J
Jiri Denemark 已提交
2310 2311 2312
}


2313 2314 2315 2316 2317
/* Leaf 0x04: deterministic cache parameters
 *
 * Sub leaf n+1 is invalid if eax[4:0] in sub leaf n equals 0.
 */
static int
2318
cpuidSetLeaf4(virCPUDataPtr data,
2319
              virCPUx86DataItemPtr subLeaf0)
2320
{
2321
    virCPUx86DataItem item = *subLeaf0;
2322
    virCPUx86CPUIDPtr cpuid = &item.data.cpuid;
2323

2324
    if (virCPUx86DataAdd(data, subLeaf0) < 0)
2325 2326
        return -1;

2327 2328 2329
    while (cpuid->eax & 0x1f) {
        cpuid->ecx_in++;
        cpuidCall(cpuid);
2330
        if (virCPUx86DataAdd(data, &item) < 0)
2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341
            return -1;
    }
    return 0;
}


/* Leaf 0x07: structured extended feature flags enumeration
 *
 * Sub leaf n is invalid if n > eax in sub leaf 0.
 */
static int
2342
cpuidSetLeaf7(virCPUDataPtr data,
2343
              virCPUx86DataItemPtr subLeaf0)
2344
{
2345
    virCPUx86DataItem item = CPUID(.eax_in = 0x7);
2346
    virCPUx86CPUIDPtr cpuid = &item.data.cpuid;
2347 2348
    uint32_t sub;

2349
    if (virCPUx86DataAdd(data, subLeaf0) < 0)
2350 2351
        return -1;

2352
    for (sub = 1; sub <= subLeaf0->data.cpuid.eax; sub++) {
2353 2354
        cpuid->ecx_in = sub;
        cpuidCall(cpuid);
2355
        if (virCPUx86DataAdd(data, &item) < 0)
2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369
            return -1;
    }
    return 0;
}


/* Leaf 0x0b: extended topology enumeration
 *
 * Sub leaf n is invalid if it returns 0 in ecx[15:8].
 * Sub leaf n+1 is invalid if sub leaf n is invalid.
 * Some output values do not depend on ecx, thus sub leaf 0 provides
 * meaningful data even if it was (theoretically) considered invalid.
 */
static int
2370
cpuidSetLeafB(virCPUDataPtr data,
2371
              virCPUx86DataItemPtr subLeaf0)
2372
{
2373
    virCPUx86DataItem item = *subLeaf0;
2374
    virCPUx86CPUIDPtr cpuid = &item.data.cpuid;
2375

2376
    while (cpuid->ecx & 0xff00) {
2377
        if (virCPUx86DataAdd(data, &item) < 0)
2378
            return -1;
2379 2380
        cpuid->ecx_in++;
        cpuidCall(cpuid);
2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394
    }
    return 0;
}


/* Leaf 0x0d: processor extended state enumeration
 *
 * Sub leaves 0 and 1 are valid.
 * Sub leaf n (2 <= n < 32) is invalid if eax[n] from sub leaf 0 is not set
 * and ecx[n] from sub leaf 1 is not set.
 * Sub leaf n (32 <= n < 64) is invalid if edx[n-32] from sub leaf 0 is not set
 * and edx[n-32] from sub leaf 1 is not set.
 */
static int
2395
cpuidSetLeafD(virCPUDataPtr data,
2396
              virCPUx86DataItemPtr subLeaf0)
2397
{
2398
    virCPUx86DataItem item = CPUID(.eax_in = 0xd);
2399
    virCPUx86CPUIDPtr cpuid = &item.data.cpuid;
2400 2401 2402 2403
    virCPUx86CPUID sub0;
    virCPUx86CPUID sub1;
    uint32_t sub;

2404
    if (virCPUx86DataAdd(data, subLeaf0) < 0)
2405 2406
        return -1;

2407 2408
    cpuid->ecx_in = 1;
    cpuidCall(cpuid);
2409
    if (virCPUx86DataAdd(data, &item) < 0)
2410 2411
        return -1;

2412
    sub0 = subLeaf0->data.cpuid;
2413
    sub1 = *cpuid;
2414 2415 2416 2417 2418 2419 2420 2421 2422 2423
    for (sub = 2; sub < 64; sub++) {
        if (sub < 32 &&
            !(sub0.eax & (1 << sub)) &&
            !(sub1.ecx & (1 << sub)))
            continue;
        if (sub >= 32 &&
            !(sub0.edx & (1 << (sub - 32))) &&
            !(sub1.edx & (1 << (sub - 32))))
            continue;

2424 2425
        cpuid->ecx_in = sub;
        cpuidCall(cpuid);
2426
        if (virCPUx86DataAdd(data, &item) < 0)
2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442
            return -1;
    }
    return 0;
}


/* Leaf 0x0f: L3 cached RDT monitoring capability enumeration
 * Leaf 0x10: RDT allocation enumeration
 *
 * res reports valid resource identification (ResID) starting at bit 1.
 * Values associated with each valid ResID are reported by ResID sub leaf.
 *
 * 0x0f: Sub leaf n is valid if edx[n] (= res[ResID]) from sub leaf 0 is set.
 * 0x10: Sub leaf n is valid if ebx[n] (= res[ResID]) from sub leaf 0 is set.
 */
static int
2443
cpuidSetLeafResID(virCPUDataPtr data,
2444
                  virCPUx86DataItemPtr subLeaf0,
2445 2446
                  uint32_t res)
{
2447 2448
    virCPUx86DataItem item = CPUID(.eax_in = subLeaf0->data.cpuid.eax_in);
    virCPUx86CPUIDPtr cpuid = &item.data.cpuid;
2449 2450
    uint32_t sub;

2451
    if (virCPUx86DataAdd(data, subLeaf0) < 0)
2452 2453 2454 2455 2456
        return -1;

    for (sub = 1; sub < 32; sub++) {
        if (!(res & (1 << sub)))
            continue;
2457 2458
        cpuid->ecx_in = sub;
        cpuidCall(cpuid);
2459
        if (virCPUx86DataAdd(data, &item) < 0)
2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471
            return -1;
    }
    return 0;
}


/* Leaf 0x12: SGX capability enumeration
 *
 * Sub leaves 0 and 1 is supported if ebx[2] from leaf 0x7 (SGX) is set.
 * Sub leaves n >= 2 are valid as long as eax[3:0] != 0.
 */
static int
2472
cpuidSetLeaf12(virCPUDataPtr data,
2473
               virCPUx86DataItemPtr subLeaf0)
2474
{
2475
    virCPUx86DataItem item = CPUID(.eax_in = 0x7);
2476
    virCPUx86CPUIDPtr cpuid = &item.data.cpuid;
2477
    virCPUx86DataItemPtr leaf7;
2478

J
Jiri Denemark 已提交
2479
    if (!(leaf7 = virCPUx86DataGet(&data->data.x86, &item)) ||
2480
        !(leaf7->data.cpuid.ebx & (1 << 2)))
2481 2482
        return 0;

2483
    if (virCPUx86DataAdd(data, subLeaf0) < 0)
2484 2485
        return -1;

2486 2487 2488
    cpuid->eax_in = 0x12;
    cpuid->ecx_in = 1;
    cpuidCall(cpuid);
2489
    if (virCPUx86DataAdd(data, &item) < 0)
2490 2491
        return -1;

2492 2493 2494
    cpuid->ecx_in = 2;
    cpuidCall(cpuid);
    while (cpuid->eax & 0xf) {
2495
        if (virCPUx86DataAdd(data, &item) < 0)
2496
            return -1;
2497 2498
        cpuid->ecx_in++;
        cpuidCall(cpuid);
2499 2500 2501 2502 2503 2504 2505 2506 2507 2508
    }
    return 0;
}


/* Leaf 0x14: processor trace enumeration
 *
 * Sub leaf 0 reports the maximum supported sub leaf in eax.
 */
static int
2509
cpuidSetLeaf14(virCPUDataPtr data,
2510
               virCPUx86DataItemPtr subLeaf0)
2511
{
2512
    virCPUx86DataItem item = CPUID(.eax_in = 0x14);
2513
    virCPUx86CPUIDPtr cpuid = &item.data.cpuid;
2514 2515
    uint32_t sub;

2516
    if (virCPUx86DataAdd(data, subLeaf0) < 0)
2517 2518
        return -1;

2519
    for (sub = 1; sub <= subLeaf0->data.cpuid.eax; sub++) {
2520 2521
        cpuid->ecx_in = sub;
        cpuidCall(cpuid);
2522
        if (virCPUx86DataAdd(data, &item) < 0)
2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534
            return -1;
    }
    return 0;
}


/* Leaf 0x17: SOC Vendor
 *
 * Sub leaf 0 is valid if eax >= 3.
 * Sub leaf 0 reports the maximum supported sub leaf in eax.
 */
static int
2535
cpuidSetLeaf17(virCPUDataPtr data,
2536
               virCPUx86DataItemPtr subLeaf0)
2537
{
2538
    virCPUx86DataItem item = CPUID(.eax_in = 0x17);
2539
    virCPUx86CPUIDPtr cpuid = &item.data.cpuid;
2540 2541
    uint32_t sub;

2542
    if (subLeaf0->data.cpuid.eax < 3)
2543 2544
        return 0;

2545
    if (virCPUx86DataAdd(data, subLeaf0) < 0)
2546 2547
        return -1;

2548
    for (sub = 1; sub <= subLeaf0->data.cpuid.eax; sub++) {
2549 2550
        cpuid->ecx_in = sub;
        cpuidCall(cpuid);
2551
        if (virCPUx86DataAdd(data, &item) < 0)
2552 2553 2554 2555 2556 2557
            return -1;
    }
    return 0;
}


J
Jiri Denemark 已提交
2558
static int
2559
cpuidSet(uint32_t base, virCPUDataPtr data)
J
Jiri Denemark 已提交
2560
{
2561
    int rc;
J
Jiri Denemark 已提交
2562
    uint32_t max;
2563
    uint32_t leaf;
2564
    virCPUx86DataItem item = CPUID(.eax_in = base);
2565
    virCPUx86CPUIDPtr cpuid = &item.data.cpuid;
J
Jiri Denemark 已提交
2566

2567 2568
    cpuidCall(cpuid);
    max = cpuid->eax;
J
Jiri Denemark 已提交
2569

2570
    for (leaf = base; leaf <= max; leaf++) {
2571 2572 2573
        cpuid->eax_in = leaf;
        cpuid->ecx_in = 0;
        cpuidCall(cpuid);
2574 2575 2576 2577 2578

        /* Handle CPUID leaves that depend on previously queried bits or
         * which provide additional sub leaves for ecx_in > 0
         */
        if (leaf == 0x4)
2579
            rc = cpuidSetLeaf4(data, &item);
2580
        else if (leaf == 0x7)
2581
            rc = cpuidSetLeaf7(data, &item);
2582
        else if (leaf == 0xb)
2583
            rc = cpuidSetLeafB(data, &item);
2584
        else if (leaf == 0xd)
2585
            rc = cpuidSetLeafD(data, &item);
2586
        else if (leaf == 0xf)
2587
            rc = cpuidSetLeafResID(data, &item, cpuid->edx);
2588
        else if (leaf == 0x10)
2589
            rc = cpuidSetLeafResID(data, &item, cpuid->ebx);
2590
        else if (leaf == 0x12)
2591
            rc = cpuidSetLeaf12(data, &item);
2592
        else if (leaf == 0x14)
2593
            rc = cpuidSetLeaf14(data, &item);
2594
        else if (leaf == 0x17)
2595
            rc = cpuidSetLeaf17(data, &item);
2596
        else
2597
            rc = virCPUx86DataAdd(data, &item);
2598 2599

        if (rc < 0)
2600
            return -1;
J
Jiri Denemark 已提交
2601 2602
    }

2603
    return 0;
J
Jiri Denemark 已提交
2604 2605 2606
}


2607
static int
2608
virCPUx86GetHost(virCPUDefPtr cpu,
2609
                 virDomainCapsCPUModelsPtr models)
J
Jiri Denemark 已提交
2610
{
2611
    virCPUDataPtr cpuData = NULL;
2612
    int ret = -1;
J
Jiri Denemark 已提交
2613

2614 2615 2616
    if (virCPUx86DriverInitialize() < 0)
        goto cleanup;

2617 2618
    if (!(cpuData = virCPUDataNew(archs[0])))
        goto cleanup;
J
Jiri Denemark 已提交
2619

2620 2621 2622
    if (cpuidSet(CPUX86_BASIC, cpuData) < 0 ||
        cpuidSet(CPUX86_EXTENDED, cpuData) < 0)
        goto cleanup;
2623

2624
    ret = x86DecodeCPUData(cpu, cpuData, models);
2625
    cpu->microcodeVersion = virHostCPUGetMicrocodeVersion();
J
Jiri Denemark 已提交
2626

2627
 cleanup:
J
Jiri Denemark 已提交
2628
    virCPUx86DataFree(cpuData);
2629
    return ret;
J
Jiri Denemark 已提交
2630 2631 2632 2633
}
#endif


2634
static virCPUDefPtr
2635 2636 2637
virCPUx86Baseline(virCPUDefPtr *cpus,
                  unsigned int ncpus,
                  virDomainCapsCPUModelsPtr models,
2638
                  const char **features,
2639
                  bool migratable)
2640
{
J
Jiri Denemark 已提交
2641
    virCPUx86MapPtr map = NULL;
J
Jiri Denemark 已提交
2642
    virCPUx86ModelPtr base_model = NULL;
2643
    virCPUDefPtr cpu = NULL;
2644
    size_t i;
2645
    virCPUx86VendorPtr vendor = NULL;
J
Jiri Denemark 已提交
2646
    virCPUx86ModelPtr model = NULL;
2647
    bool outputVendor = true;
2648 2649
    const char *modelName;
    bool matchingNames = true;
2650
    virCPUDataPtr featData = NULL;
2651

2652
    if (!(map = virCPUx86GetMap()))
2653 2654
        goto error;

2655
    if (!(base_model = x86ModelFromCPU(cpus[0], map, -1)))
2656 2657
        goto error;

2658
    if (VIR_ALLOC(cpu) < 0)
2659
        goto error;
2660

2661 2662
    cpu->type = VIR_CPU_TYPE_GUEST;
    cpu->match = VIR_CPU_MATCH_EXACT;
2663

2664
    if (!cpus[0]->vendor) {
2665
        outputVendor = false;
2666
    } else if (!(vendor = x86VendorFind(map, cpus[0]->vendor))) {
2667 2668
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Unknown CPU vendor %s"), cpus[0]->vendor);
J
Jiri Denemark 已提交
2669 2670 2671
        goto error;
    }

2672
    modelName = cpus[0]->model;
2673
    for (i = 1; i < ncpus; i++) {
J
Jiri Denemark 已提交
2674 2675
        const char *vn = NULL;

2676 2677 2678 2679 2680 2681 2682 2683 2684
        if (matchingNames && cpus[i]->model) {
            if (!modelName) {
                modelName = cpus[i]->model;
            } else if (STRNEQ(modelName, cpus[i]->model)) {
                modelName = NULL;
                matchingNames = false;
            }
        }

2685
        if (!(model = x86ModelFromCPU(cpus[i], map, -1)))
2686 2687
            goto error;

J
Jiri Denemark 已提交
2688 2689
        if (cpus[i]->vendor && model->vendor &&
            STRNEQ(cpus[i]->vendor, model->vendor->name)) {
2690 2691 2692
            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 已提交
2693 2694 2695
            goto error;
        }

2696
        if (cpus[i]->vendor) {
J
Jiri Denemark 已提交
2697
            vn = cpus[i]->vendor;
2698
        } else {
2699 2700 2701 2702
            outputVendor = false;
            if (model->vendor)
                vn = model->vendor->name;
        }
J
Jiri Denemark 已提交
2703 2704 2705 2706

        if (vn) {
            if (!vendor) {
                if (!(vendor = x86VendorFind(map, vn))) {
2707 2708
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("Unknown CPU vendor %s"), vn);
J
Jiri Denemark 已提交
2709 2710 2711
                    goto error;
                }
            } else if (STRNEQ(vendor->name, vn)) {
2712 2713
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("CPU vendors do not match"));
J
Jiri Denemark 已提交
2714 2715 2716 2717
                goto error;
            }
        }

2718
        x86DataIntersect(&base_model->data, &model->data);
2719
        x86ModelFree(model);
J
Jiri Denemark 已提交
2720
        model = NULL;
2721 2722
    }

2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737
    if (features) {
        virCPUx86FeaturePtr feat;

        if (!(featData = virCPUDataNew(archs[0])))
            goto cleanup;

        for (i = 0; features[i]; i++) {
            if ((feat = x86FeatureFind(map, features[i])) &&
                x86DataAdd(&featData->data.x86, &feat->data) < 0)
                goto cleanup;
        }

        x86DataIntersect(&base_model->data, &featData->data.x86);
    }

2738
    if (x86DataIsEmpty(&base_model->data)) {
2739 2740
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("CPUs are incompatible"));
2741 2742 2743
        goto error;
    }

2744
    if (vendor &&
2745
        virCPUx86DataAddItem(&base_model->data, &vendor->data) < 0)
2746
        goto error;
J
Jiri Denemark 已提交
2747

2748
    if (x86Decode(cpu, &base_model->data, models, modelName, migratable) < 0)
2749 2750
        goto error;

2751 2752 2753
    if (STREQ_NULLABLE(cpu->model, modelName))
        cpu->fallback = VIR_CPU_FALLBACK_FORBID;

2754 2755 2756
    if (!outputVendor)
        VIR_FREE(cpu->vendor);

2757
 cleanup:
2758
    x86ModelFree(base_model);
2759
    virCPUx86DataFree(featData);
2760 2761 2762

    return cpu;

2763
 error:
J
Jiri Denemark 已提交
2764
    x86ModelFree(model);
2765 2766 2767 2768 2769 2770
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
}


2771
static int
J
Jiri Denemark 已提交
2772
x86UpdateHostModel(virCPUDefPtr guest,
2773
                   const virCPUDef *host)
2774
{
J
Jiri Denemark 已提交
2775
    virCPUDefPtr updated = NULL;
2776
    size_t i;
J
Jiri Denemark 已提交
2777
    int ret = -1;
2778

J
Jiri Denemark 已提交
2779
    if (!(updated = virCPUDefCopyWithoutModel(host)))
2780 2781
        goto cleanup;

J
Jiri Denemark 已提交
2782 2783
    updated->type = VIR_CPU_TYPE_GUEST;
    updated->mode = VIR_CPU_MODE_CUSTOM;
2784
    if (virCPUDefCopyModel(updated, host, true) < 0)
J
Jiri Denemark 已提交
2785
        goto cleanup;
2786

J
Jiri Denemark 已提交
2787 2788 2789 2790 2791 2792 2793 2794 2795 2796
    if (guest->vendor_id) {
        VIR_FREE(updated->vendor_id);
        if (VIR_STRDUP(updated->vendor_id, guest->vendor_id) < 0)
            goto cleanup;
    }

    for (i = 0; i < guest->nfeatures; i++) {
        if (virCPUDefUpdateFeature(updated,
                                   guest->features[i].name,
                                   guest->features[i].policy) < 0)
2797 2798 2799
            goto cleanup;
    }

2800 2801
    virCPUDefStealModel(guest, updated,
                        guest->mode == VIR_CPU_MODE_CUSTOM);
J
Jiri Denemark 已提交
2802 2803
    guest->mode = VIR_CPU_MODE_CUSTOM;
    guest->match = VIR_CPU_MATCH_EXACT;
2804 2805
    ret = 0;

2806
 cleanup:
J
Jiri Denemark 已提交
2807
    virCPUDefFree(updated);
2808 2809 2810
    return ret;
}

2811 2812

static int
J
Jiri Denemark 已提交
2813 2814
virCPUx86Update(virCPUDefPtr guest,
                const virCPUDef *host)
2815
{
J
Jiri Denemark 已提交
2816
    virCPUx86ModelPtr model = NULL;
J
Jiri Denemark 已提交
2817
    virCPUx86MapPtr map;
2818
    int ret = -1;
J
Jiri Denemark 已提交
2819
    size_t i;
2820

J
Jiri Denemark 已提交
2821 2822 2823 2824 2825
    if (!host) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("unknown host CPU model"));
        return -1;
    }
2826

J
Jiri Denemark 已提交
2827 2828
    if (!(map = virCPUx86GetMap()))
        return -1;
2829

J
Jiri Denemark 已提交
2830
    if (!(model = x86ModelFromCPU(host, map, -1)))
2831
        goto cleanup;
2832

J
Jiri Denemark 已提交
2833 2834 2835 2836 2837 2838 2839 2840 2841 2842
    for (i = 0; i < guest->nfeatures; i++) {
        if (guest->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) {
            int supported = x86FeatureInData(guest->features[i].name,
                                             &model->data, map);
            if (supported < 0)
                goto cleanup;
            else if (supported)
                guest->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
            else
                guest->features[i].policy = VIR_CPU_FEATURE_DISABLE;
2843 2844
        }
    }
2845

J
Jiri Denemark 已提交
2846 2847
    if (guest->mode == VIR_CPU_MODE_HOST_MODEL ||
        guest->match == VIR_CPU_MATCH_MINIMUM)
2848
        ret = x86UpdateHostModel(guest, host);
J
Jiri Denemark 已提交
2849 2850
    else
        ret = 0;
2851 2852

 cleanup:
J
Jiri Denemark 已提交
2853
    x86ModelFree(model);
2854
    return ret;
2855 2856 2857
}


2858 2859 2860 2861 2862 2863 2864 2865 2866
static int
virCPUx86UpdateLive(virCPUDefPtr cpu,
                    virCPUDataPtr dataEnabled,
                    virCPUDataPtr dataDisabled)
{
    virCPUx86MapPtr map;
    virCPUx86ModelPtr model = NULL;
    virCPUx86Data enabled = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data disabled = VIR_CPU_X86_DATA_INIT;
2867 2868 2869 2870
    virBuffer bufAdded = VIR_BUFFER_INITIALIZER;
    virBuffer bufRemoved = VIR_BUFFER_INITIALIZER;
    char *added = NULL;
    char *removed = NULL;
2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890
    size_t i;
    int ret = -1;

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

    if (!(model = x86ModelFromCPU(cpu, map, -1)))
        goto cleanup;

    if (dataEnabled &&
        x86DataCopy(&enabled, &dataEnabled->data.x86) < 0)
        goto cleanup;

    if (dataDisabled &&
        x86DataCopy(&disabled, &dataDisabled->data.x86) < 0)
        goto cleanup;

    for (i = 0; i < map->nfeatures; i++) {
        virCPUx86FeaturePtr feature = map->features[i];

2891 2892
        if (x86DataIsSubset(&enabled, &feature->data) &&
            !x86DataIsSubset(&model->data, &feature->data)) {
2893 2894 2895 2896 2897
            VIR_DEBUG("Feature '%s' enabled by the hypervisor", feature->name);
            if (cpu->check == VIR_CPU_CHECK_FULL)
                virBufferAsprintf(&bufAdded, "%s,", feature->name);
            else if (virCPUDefUpdateFeature(cpu, feature->name,
                                            VIR_CPU_FEATURE_REQUIRE) < 0)
2898 2899 2900
                goto cleanup;
        }

2901 2902 2903
        if (x86DataIsSubset(&disabled, &feature->data) ||
            (x86DataIsSubset(&model->data, &feature->data) &&
             !x86DataIsSubset(&enabled, &feature->data))) {
2904 2905 2906 2907 2908
            VIR_DEBUG("Feature '%s' disabled by the hypervisor", feature->name);
            if (cpu->check == VIR_CPU_CHECK_FULL)
                virBufferAsprintf(&bufRemoved, "%s,", feature->name);
            else if (virCPUDefUpdateFeature(cpu, feature->name,
                                            VIR_CPU_FEATURE_DISABLE) < 0)
2909 2910 2911 2912
                goto cleanup;
        }
    }

2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948
    virBufferTrim(&bufAdded, ",", -1);
    virBufferTrim(&bufRemoved, ",", -1);

    if (virBufferCheckError(&bufAdded) < 0 ||
        virBufferCheckError(&bufRemoved) < 0)
        goto cleanup;

    added = virBufferContentAndReset(&bufAdded);
    removed = virBufferContentAndReset(&bufRemoved);

    if (added || removed) {
        if (added && removed)
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("guest CPU doesn't match specification: "
                             "extra features: %s, missing features: %s"),
                           added, removed);
        else if (added)
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("guest CPU doesn't match specification: "
                             "extra features: %s"),
                           added);
        else
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("guest CPU doesn't match specification: "
                             "missing features: %s"),
                           removed);
        goto cleanup;
    }

    if (cpu->check == VIR_CPU_CHECK_FULL &&
        !x86DataIsEmpty(&disabled)) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("guest CPU doesn't match specification"));
        goto cleanup;
    }

2949 2950 2951 2952 2953 2954
    ret = 0;

 cleanup:
    x86ModelFree(model);
    virCPUx86DataClear(&enabled);
    virCPUx86DataClear(&disabled);
2955 2956 2957 2958
    VIR_FREE(added);
    VIR_FREE(removed);
    virBufferFreeAndReset(&bufAdded);
    virBufferFreeAndReset(&bufRemoved);
2959 2960 2961 2962
    return ret;
}


2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984
static int
virCPUx86CheckFeature(const virCPUDef *cpu,
                      const char *name)
{
    int ret = -1;
    virCPUx86MapPtr map;
    virCPUx86ModelPtr model = NULL;

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

    if (!(model = x86ModelFromCPU(cpu, map, -1)))
        goto cleanup;

    ret = x86FeatureInData(name, &model->data, map);

 cleanup:
    x86ModelFree(model);
    return ret;
}


2985
static int
2986 2987
virCPUx86DataCheckFeature(const virCPUData *data,
                          const char *name)
D
Daniel P. Berrange 已提交
2988
{
J
Jiri Denemark 已提交
2989
    virCPUx86MapPtr map;
D
Daniel P. Berrange 已提交
2990

2991
    if (!(map = virCPUx86GetMap()))
D
Daniel P. Berrange 已提交
2992 2993
        return -1;

J
Jiri Denemark 已提交
2994
    return x86FeatureInData(name, &data->data.x86, map);
D
Daniel P. Berrange 已提交
2995
}
2996

2997
static int
J
Jiri Denemark 已提交
2998
virCPUx86GetModels(char ***models)
2999
{
J
Jiri Denemark 已提交
3000
    virCPUx86MapPtr map;
3001
    size_t i;
3002 3003 3004 3005

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

3006 3007 3008
    if (models) {
        if (VIR_ALLOC_N(*models, map->nmodels + 1) < 0)
            goto error;
3009

3010 3011
        for (i = 0; i < map->nmodels; i++) {
            if (VIR_STRDUP((*models)[i], map->models[i]->name) < 0)
3012 3013
                goto error;
        }
3014 3015
    }

3016
    return map->nmodels;
3017 3018

 error:
3019
    if (models) {
3020
        virStringListFree(*models);
3021 3022
        *models = NULL;
    }
3023 3024 3025
    return -1;
}

3026

J
Jiri Denemark 已提交
3027 3028
static int
virCPUx86Translate(virCPUDefPtr cpu,
3029
                   virDomainCapsCPUModelsPtr models)
J
Jiri Denemark 已提交
3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043
{
    virCPUDefPtr translated = NULL;
    virCPUx86MapPtr map;
    virCPUx86ModelPtr model = NULL;
    size_t i;
    int ret = -1;

    if (!(map = virCPUx86GetMap()))
        goto cleanup;

    if (!(model = x86ModelFromCPU(cpu, map, -1)))
        goto cleanup;

    if (model->vendor &&
3044
        virCPUx86DataAddItem(&model->data, &model->vendor->data) < 0)
J
Jiri Denemark 已提交
3045 3046
        goto cleanup;

3047 3048
    if (model->signatures &&
        x86DataAddSignature(&model->data, model->signatures[0]) < 0)
J
Jiri Denemark 已提交
3049 3050 3051 3052 3053
        goto cleanup;

    if (!(translated = virCPUDefCopyWithoutModel(cpu)))
        goto cleanup;

3054
    if (x86Decode(translated, &model->data, models, NULL, false) < 0)
J
Jiri Denemark 已提交
3055 3056 3057 3058 3059 3060 3061 3062
        goto cleanup;

    for (i = 0; i < cpu->nfeatures; i++) {
        virCPUFeatureDefPtr f = cpu->features + i;
        if (virCPUDefUpdateFeature(translated, f->name, f->policy) < 0)
            goto cleanup;
    }

3063
    virCPUDefStealModel(cpu, translated, true);
J
Jiri Denemark 已提交
3064 3065 3066 3067 3068 3069 3070 3071 3072
    ret = 0;

 cleanup:
    virCPUDefFree(translated);
    x86ModelFree(model);
    return ret;
}


3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124
static int
virCPUx86ExpandFeatures(virCPUDefPtr cpu)
{
    virCPUx86MapPtr map;
    virCPUDefPtr expanded = NULL;
    virCPUx86ModelPtr model = NULL;
    bool host = cpu->type == VIR_CPU_TYPE_HOST;
    size_t i;
    int ret = -1;

    if (!(map = virCPUx86GetMap()))
        goto cleanup;

    if (!(expanded = virCPUDefCopy(cpu)))
        goto cleanup;

    virCPUDefFreeFeatures(expanded);

    if (!(model = x86ModelFind(map, cpu->model))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown CPU model %s"), cpu->model);
        goto cleanup;
    }

    if (!(model = x86ModelCopy(model)) ||
        x86DataToCPUFeatures(expanded, host ? -1 : VIR_CPU_FEATURE_REQUIRE,
                             &model->data, map) < 0)
        goto cleanup;

    for (i = 0; i < cpu->nfeatures; i++) {
        virCPUFeatureDefPtr f = cpu->features + i;

        if (!host &&
            f->policy != VIR_CPU_FEATURE_REQUIRE &&
            f->policy != VIR_CPU_FEATURE_DISABLE)
            continue;

        if (virCPUDefUpdateFeature(expanded, f->name, f->policy) < 0)
            goto cleanup;
    }

    virCPUDefFreeModel(cpu);

    ret = virCPUDefCopyModel(cpu, expanded, false);

 cleanup:
    virCPUDefFree(expanded);
    x86ModelFree(model);
    return ret;
}


3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148
static virCPUDefPtr
virCPUx86CopyMigratable(virCPUDefPtr cpu)
{
    virCPUDefPtr copy;
    virCPUx86MapPtr map;

    if (!(map = virCPUx86GetMap()))
        return NULL;

    if (!(copy = virCPUDefCopyWithoutModel(cpu)))
        return NULL;

    if (virCPUDefCopyModelFilter(copy, cpu, false,
                                 x86FeatureIsMigratable, map) < 0)
        goto error;

    return copy;

 error:
    virCPUDefFree(copy);
    return NULL;
}


3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170
static int
virCPUx86ValidateFeatures(virCPUDefPtr cpu)
{
    virCPUx86MapPtr map;
    size_t i;

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

    for (i = 0; i < cpu->nfeatures; i++) {
        if (!x86FeatureFind(map, cpu->features[i].name)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown CPU feature: %s"),
                           cpu->features[i].name);
            return -1;
        }
    }

    return 0;
}


3171
int
3172 3173
virCPUx86DataAdd(virCPUDataPtr cpuData,
                 const virCPUx86DataItem *item)
3174
{
3175
    return virCPUx86DataAddItem(&cpuData->data.x86, item);
3176 3177 3178
}


3179 3180 3181
int
virCPUx86DataSetSignature(virCPUDataPtr cpuData,
                          unsigned int family,
3182 3183
                          unsigned int model,
                          unsigned int stepping)
3184
{
3185
    uint32_t signature = x86MakeSignature(family, model, stepping);
3186 3187 3188 3189 3190

    return x86DataAddSignature(&cpuData->data.x86, signature);
}


3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202
uint32_t
virCPUx86DataGetSignature(virCPUDataPtr cpuData,
                          unsigned int *family,
                          unsigned int *model,
                          unsigned int *stepping)
{
    x86DataToSignatureFull(&cpuData->data.x86, family, model, stepping);

    return x86MakeSignature(*family, *model, *stepping);
}


3203 3204 3205 3206
int
virCPUx86DataSetVendor(virCPUDataPtr cpuData,
                       const char *vendor)
{
3207
    virCPUx86DataItem item = CPUID(0);
3208

3209
    if (virCPUx86VendorToData(vendor, &item) < 0)
3210 3211
        return -1;

3212
    return virCPUx86DataAdd(cpuData, &item);
3213 3214 3215
}


3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237
int
virCPUx86DataAddFeature(virCPUDataPtr cpuData,
                        const char *name)
{
    virCPUx86FeaturePtr feature;
    virCPUx86MapPtr map;

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

    /* ignore unknown features */
    if (!(feature = x86FeatureFind(map, name)) &&
        !(feature = x86FeatureFindInternal(name)))
        return 0;

    if (x86DataAdd(&cpuData->data.x86, &feature->data) < 0)
        return -1;

    return 0;
}


J
Jiri Denemark 已提交
3238 3239 3240 3241
struct cpuArchDriver cpuDriverX86 = {
    .name = "x86",
    .arch = archs,
    .narch = ARRAY_CARDINALITY(archs),
J
Jiri Denemark 已提交
3242
    .compare    = virCPUx86Compare,
3243
    .decode     = x86DecodeCPUData,
J
Jiri Denemark 已提交
3244
    .encode     = x86Encode,
J
Jiri Denemark 已提交
3245
    .dataFree   = virCPUx86DataFree,
P
Pavel Hrdina 已提交
3246
#if defined(__i386__) || defined(__x86_64__)
3247
    .getHost    = virCPUx86GetHost,
J
Jiri Denemark 已提交
3248
#endif
3249
    .baseline   = virCPUx86Baseline,
J
Jiri Denemark 已提交
3250
    .update     = virCPUx86Update,
3251
    .updateLive = virCPUx86UpdateLive,
3252
    .checkFeature = virCPUx86CheckFeature,
3253
    .dataCheckFeature = virCPUx86DataCheckFeature,
J
Jiri Denemark 已提交
3254
    .dataFormat = virCPUx86DataFormat,
J
Jiri Denemark 已提交
3255
    .dataParse  = virCPUx86DataParse,
J
Jiri Denemark 已提交
3256
    .getModels  = virCPUx86GetModels,
J
Jiri Denemark 已提交
3257
    .translate  = virCPUx86Translate,
3258
    .expandFeatures = virCPUx86ExpandFeatures,
3259
    .copyMigratable = virCPUx86CopyMigratable,
3260
    .validateFeatures = virCPUx86ValidateFeatures,
J
Jiri Denemark 已提交
3261
};