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

#include <config.h>

#include <stdint.h>

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

#define VIR_FROM_THIS VIR_FROM_CPU

39 40
VIR_LOG_INIT("cpu.cpu_x86");

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

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

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

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

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

62 63 64
typedef struct _virCPUx86KVMFeature virCPUx86KVMFeature;
typedef virCPUx86KVMFeature *virCPUx86KVMFeaturePtr;
struct _virCPUx86KVMFeature {
65 66 67 68
    const char *name;
    const virCPUx86CPUID cpuid;
};

69
static const virCPUx86KVMFeature x86_kvm_features[] =
70
{
71 72 73 74 75 76 77 78
    {VIR_CPU_x86_KVM_CLOCKSOURCE,  { .eax_in = 0x40000001, .eax = 0x00000001 }},
    {VIR_CPU_x86_KVM_NOP_IO_DELAY, { .eax_in = 0x40000001, .eax = 0x00000002 }},
    {VIR_CPU_x86_KVM_MMU_OP,       { .eax_in = 0x40000001, .eax = 0x00000004 }},
    {VIR_CPU_x86_KVM_CLOCKSOURCE2, { .eax_in = 0x40000001, .eax = 0x00000008 }},
    {VIR_CPU_x86_KVM_ASYNC_PF,     { .eax_in = 0x40000001, .eax = 0x00000010 }},
    {VIR_CPU_x86_KVM_STEAL_TIME,   { .eax_in = 0x40000001, .eax = 0x00000020 }},
    {VIR_CPU_x86_KVM_PV_EOI,       { .eax_in = 0x40000001, .eax = 0x00000040 }},
    {VIR_CPU_x86_KVM_PV_UNHALT,    { .eax_in = 0x40000001, .eax = 0x00000080 }},
79
    {VIR_CPU_x86_KVM_CLOCKSOURCE_STABLE_BIT,
80 81 82 83 84 85 86 87 88
                                   { .eax_in = 0x40000001, .eax = 0x01000000 }},
    {VIR_CPU_x86_KVM_HV_RUNTIME,   { .eax_in = 0x40000003, .eax = 0x00000001 }},
    {VIR_CPU_x86_KVM_HV_SYNIC,     { .eax_in = 0x40000003, .eax = 0x00000004 }},
    {VIR_CPU_x86_KVM_HV_STIMER,    { .eax_in = 0x40000003, .eax = 0x00000008 }},
    {VIR_CPU_x86_KVM_HV_RELAXED,   { .eax_in = 0x40000003, .eax = 0x00000020 }},
    {VIR_CPU_x86_KVM_HV_SPINLOCK,  { .eax_in = 0x40000003, .eax = 0x00000022 }},
    {VIR_CPU_x86_KVM_HV_VAPIC,     { .eax_in = 0x40000003, .eax = 0x00000030 }},
    {VIR_CPU_x86_KVM_HV_VPINDEX,   { .eax_in = 0x40000003, .eax = 0x00000040 }},
    {VIR_CPU_x86_KVM_HV_RESET,     { .eax_in = 0x40000003, .eax = 0x00000080 }},
89 90
};

J
Jiri Denemark 已提交
91 92 93
typedef struct _virCPUx86Model virCPUx86Model;
typedef virCPUx86Model *virCPUx86ModelPtr;
struct _virCPUx86Model {
J
Jiri Denemark 已提交
94
    char *name;
95
    virCPUx86VendorPtr vendor;
96
    virCPUx86Data data;
J
Jiri Denemark 已提交
97 98
};

J
Jiri Denemark 已提交
99 100 101
typedef struct _virCPUx86Map virCPUx86Map;
typedef virCPUx86Map *virCPUx86MapPtr;
struct _virCPUx86Map {
102 103
    size_t nvendors;
    virCPUx86VendorPtr *vendors;
104 105
    size_t nfeatures;
    virCPUx86FeaturePtr *features;
106 107
    size_t nmodels;
    virCPUx86ModelPtr *models;
108 109
    size_t nblockers;
    virCPUx86FeaturePtr *migrate_blockers;
J
Jiri Denemark 已提交
110 111
};

J
Jiri Denemark 已提交
112
static virCPUx86MapPtr cpuMap;
113 114 115
int virCPUx86MapOnceInit(void);
VIR_ONCE_GLOBAL_INIT(virCPUx86Map);

J
Jiri Denemark 已提交
116

117
typedef enum {
J
Jiri Denemark 已提交
118 119 120 121
    SUBSET,
    EQUAL,
    SUPERSET,
    UNRELATED
122
} virCPUx86CompareResult;
J
Jiri Denemark 已提交
123 124


125 126 127
typedef struct _virCPUx86DataIterator virCPUx86DataIterator;
typedef virCPUx86DataIterator *virCPUx86DataIteratorPtr;
struct _virCPUx86DataIterator {
128
    const virCPUx86Data *data;
J
Jiri Denemark 已提交
129 130
    int pos;
};
J
Jiri Denemark 已提交
131 132


133
#define virCPUx86DataIteratorInit(data) \
134
    { data, -1 }
J
Jiri Denemark 已提交
135 136


137
static bool
138 139
x86cpuidMatch(const virCPUx86CPUID *cpuid1,
              const virCPUx86CPUID *cpuid2)
J
Jiri Denemark 已提交
140 141 142 143 144 145 146 147
{
    return (cpuid1->eax == cpuid2->eax &&
            cpuid1->ebx == cpuid2->ebx &&
            cpuid1->ecx == cpuid2->ecx &&
            cpuid1->edx == cpuid2->edx);
}


148
static bool
149 150
x86cpuidMatchMasked(const virCPUx86CPUID *cpuid,
                    const virCPUx86CPUID *mask)
J
Jiri Denemark 已提交
151 152 153 154 155 156 157 158
{
    return ((cpuid->eax & mask->eax) == mask->eax &&
            (cpuid->ebx & mask->ebx) == mask->ebx &&
            (cpuid->ecx & mask->ecx) == mask->ecx &&
            (cpuid->edx & mask->edx) == mask->edx);
}


J
Jiri Denemark 已提交
159
static void
160 161
x86cpuidSetBits(virCPUx86CPUID *cpuid,
                const virCPUx86CPUID *mask)
J
Jiri Denemark 已提交
162
{
163 164 165
    if (!mask)
        return;

J
Jiri Denemark 已提交
166 167 168 169 170 171 172
    cpuid->eax |= mask->eax;
    cpuid->ebx |= mask->ebx;
    cpuid->ecx |= mask->ecx;
    cpuid->edx |= mask->edx;
}


J
Jiri Denemark 已提交
173
static void
174 175
x86cpuidClearBits(virCPUx86CPUID *cpuid,
                  const virCPUx86CPUID *mask)
J
Jiri Denemark 已提交
176
{
177 178 179
    if (!mask)
        return;

J
Jiri Denemark 已提交
180 181 182 183 184 185 186
    cpuid->eax &= ~mask->eax;
    cpuid->ebx &= ~mask->ebx;
    cpuid->ecx &= ~mask->ecx;
    cpuid->edx &= ~mask->edx;
}


J
Jiri Denemark 已提交
187
static void
188 189
x86cpuidAndBits(virCPUx86CPUID *cpuid,
                const virCPUx86CPUID *mask)
190
{
191 192 193
    if (!mask)
        return;

194 195 196 197 198 199
    cpuid->eax &= mask->eax;
    cpuid->ebx &= mask->ebx;
    cpuid->ecx &= mask->ecx;
    cpuid->edx &= mask->edx;
}

200 201 202 203 204 205
static int
virCPUx86CPUIDSorter(const void *a, const void *b)
{
    virCPUx86CPUID *da = (virCPUx86CPUID *) a;
    virCPUx86CPUID *db = (virCPUx86CPUID *) b;

206
    if (da->eax_in > db->eax_in)
207
        return 1;
208
    else if (da->eax_in < db->eax_in)
209 210 211 212 213
        return -1;

    return 0;
}

214

J
Jiri Denemark 已提交
215
/* skips all zero CPUID leafs */
216
static virCPUx86CPUID *
217
x86DataCpuidNext(virCPUx86DataIteratorPtr iterator)
J
Jiri Denemark 已提交
218
{
219
    const virCPUx86Data *data = iterator->data;
J
Jiri Denemark 已提交
220

221
    if (!data)
J
Jiri Denemark 已提交
222 223
        return NULL;

224 225 226 227
    while (++iterator->pos < data->len) {
        if (!x86cpuidMatch(data->data + iterator->pos, &cpuidNull))
            return data->data + iterator->pos;
    }
J
Jiri Denemark 已提交
228

229
    return NULL;
J
Jiri Denemark 已提交
230 231 232
}


233
static virCPUx86CPUID *
234
x86DataCpuid(const virCPUx86Data *data,
235
             uint32_t eax_in)
J
Jiri Denemark 已提交
236
{
237
    size_t i;
J
Jiri Denemark 已提交
238

239
    for (i = 0; i < data->len; i++) {
240
        if (data->data[i].eax_in == eax_in)
241
            return data->data + i;
J
Jiri Denemark 已提交
242 243
    }

244
    return NULL;
J
Jiri Denemark 已提交
245 246
}

J
Jiri Denemark 已提交
247
void
248
virCPUx86DataClear(virCPUx86Data *data)
J
Jiri Denemark 已提交
249
{
250
    if (!data)
J
Jiri Denemark 已提交
251 252
        return;

253
    VIR_FREE(data->data);
J
Jiri Denemark 已提交
254 255 256
}


J
Jiri Denemark 已提交
257
virCPUDataPtr
258
virCPUx86MakeData(virArch arch, virCPUx86Data *data)
259
{
260
    virCPUDataPtr cpuData;
261 262 263 264

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

J
Jiri Denemark 已提交
265 266
    cpuData->arch = arch;
    cpuData->data.x86 = *data;
267 268
    data->len = 0;
    data->data = NULL;
269 270 271 272 273

    return cpuData;
}

static void
274
x86FreeCPUData(virCPUDataPtr data)
275 276 277 278
{
    if (!data)
        return;

279
    virCPUx86DataClear(&data->data.x86);
280 281 282 283
    VIR_FREE(data);
}


284 285
static int
x86DataCopy(virCPUx86Data *dst, const virCPUx86Data *src)
J
Jiri Denemark 已提交
286
{
287
    size_t i;
J
Jiri Denemark 已提交
288

289 290
    if (VIR_ALLOC_N(dst->data, src->len) < 0)
        return -1;
J
Jiri Denemark 已提交
291

292 293 294
    dst->len = src->len;
    for (i = 0; i < src->len; i++)
        dst->data[i] = src->data[i];
J
Jiri Denemark 已提交
295

296
    return 0;
J
Jiri Denemark 已提交
297 298 299
}


J
Jiri Denemark 已提交
300
int
301 302
virCPUx86DataAddCPUID(virCPUx86Data *data,
                      const virCPUx86CPUID *cpuid)
J
Jiri Denemark 已提交
303
{
304
    virCPUx86CPUID *existing;
J
Jiri Denemark 已提交
305

306
    if ((existing = x86DataCpuid(data, cpuid->eax_in))) {
307 308 309 310 311
        x86cpuidSetBits(existing, cpuid);
    } else {
        if (VIR_APPEND_ELEMENT_COPY(data->data, data->len,
                                    *((virCPUx86CPUID *)cpuid)) < 0)
            return -1;
J
Jiri Denemark 已提交
312

313 314 315
        qsort(data->data, data->len,
              sizeof(virCPUx86CPUID), virCPUx86CPUIDSorter);
    }
J
Jiri Denemark 已提交
316

J
Jiri Denemark 已提交
317 318 319 320 321
    return 0;
}


static int
322 323
x86DataAdd(virCPUx86Data *data1,
           const virCPUx86Data *data2)
J
Jiri Denemark 已提交
324
{
325
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data2);
326 327
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
J
Jiri Denemark 已提交
328

329
    while ((cpuid2 = x86DataCpuidNext(&iter))) {
330
        cpuid1 = x86DataCpuid(data1, cpuid2->eax_in);
J
Jiri Denemark 已提交
331

332 333 334 335 336 337
        if (cpuid1) {
            x86cpuidSetBits(cpuid1, cpuid2);
        } else {
            if (virCPUx86DataAddCPUID(data1, cpuid2) < 0)
                return -1;
        }
J
Jiri Denemark 已提交
338
    }
J
Jiri Denemark 已提交
339 340 341 342 343

    return 0;
}


344
static void
345 346
x86DataSubtract(virCPUx86Data *data1,
                const virCPUx86Data *data2)
347
{
348
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data1);
349 350
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
351

352
    while ((cpuid1 = x86DataCpuidNext(&iter))) {
353
        cpuid2 = x86DataCpuid(data2, cpuid1->eax_in);
354
        x86cpuidClearBits(cpuid1, cpuid2);
355 356 357 358
    }
}


J
Jiri Denemark 已提交
359
static void
360 361
x86DataIntersect(virCPUx86Data *data1,
                 const virCPUx86Data *data2)
362
{
363
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data1);
364 365
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
366

J
Jiri Denemark 已提交
367
    while ((cpuid1 = x86DataCpuidNext(&iter))) {
368
        cpuid2 = x86DataCpuid(data2, cpuid1->eax_in);
J
Jiri Denemark 已提交
369 370 371 372
        if (cpuid2)
            x86cpuidAndBits(cpuid1, cpuid2);
        else
            x86cpuidClearBits(cpuid1, cpuid1);
373 374 375 376
    }
}


J
Jiri Denemark 已提交
377
static bool
378
x86DataIsEmpty(virCPUx86Data *data)
J
Jiri Denemark 已提交
379
{
380
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(data);
J
Jiri Denemark 已提交
381

382
    return !x86DataCpuidNext(&iter);
J
Jiri Denemark 已提交
383
}
J
Jiri Denemark 已提交
384 385


J
Jiri Denemark 已提交
386
static bool
387 388
x86DataIsSubset(const virCPUx86Data *data,
                const virCPUx86Data *subset)
J
Jiri Denemark 已提交
389 390
{

391
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit((virCPUx86Data *)subset);
392 393
    const virCPUx86CPUID *cpuid;
    const virCPUx86CPUID *cpuidSubset;
J
Jiri Denemark 已提交
394

J
Jiri Denemark 已提交
395
    while ((cpuidSubset = x86DataCpuidNext(&iter))) {
396
        if (!(cpuid = x86DataCpuid(data, cpuidSubset->eax_in)) ||
J
Jiri Denemark 已提交
397 398
            !x86cpuidMatchMasked(cpuid, cpuidSubset))
            return false;
J
Jiri Denemark 已提交
399 400
    }

J
Jiri Denemark 已提交
401
    return true;
J
Jiri Denemark 已提交
402 403 404
}


405 406 407 408
/* also removes all detected features from data */
static int
x86DataToCPUFeatures(virCPUDefPtr cpu,
                     int policy,
409
                     virCPUx86Data *data,
J
Jiri Denemark 已提交
410
                     virCPUx86MapPtr map)
411
{
412
    size_t i;
413

414 415
    for (i = 0; i < map->nfeatures; i++) {
        virCPUx86FeaturePtr feature = map->features[i];
416 417
        if (x86DataIsSubset(data, &feature->data)) {
            x86DataSubtract(data, &feature->data);
J
Jiri Denemark 已提交
418 419
            if (virCPUDefAddFeature(cpu, feature->name, policy) < 0)
                return -1;
420 421 422 423 424 425 426
        }
    }

    return 0;
}


J
Jiri Denemark 已提交
427
/* also removes bits corresponding to vendor string from data */
428
static virCPUx86VendorPtr
J
Jiri Denemark 已提交
429
x86DataToVendor(const virCPUx86Data *data,
J
Jiri Denemark 已提交
430
                virCPUx86MapPtr map)
J
Jiri Denemark 已提交
431
{
432
    virCPUx86CPUID *cpuid;
433
    size_t i;
J
Jiri Denemark 已提交
434

435 436
    for (i = 0; i < map->nvendors; i++) {
        virCPUx86VendorPtr vendor = map->vendors[i];
437
        if ((cpuid = x86DataCpuid(data, vendor->cpuid.eax_in)) &&
J
Jiri Denemark 已提交
438 439 440 441 442 443 444 445 446 447
            x86cpuidMatchMasked(cpuid, &vendor->cpuid)) {
            x86cpuidClearBits(cpuid, &vendor->cpuid);
            return vendor;
        }
    }

    return NULL;
}


448
static virCPUDefPtr
449
x86DataToCPU(const virCPUx86Data *data,
J
Jiri Denemark 已提交
450
             virCPUx86ModelPtr model,
J
Jiri Denemark 已提交
451
             virCPUx86MapPtr map)
452 453
{
    virCPUDefPtr cpu;
454 455
    virCPUx86Data copy = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data modelData = VIR_CPU_X86_DATA_INIT;
456
    virCPUx86VendorPtr vendor;
457 458

    if (VIR_ALLOC(cpu) < 0 ||
459
        VIR_STRDUP(cpu->model, model->name) < 0 ||
460 461
        x86DataCopy(&copy, data) < 0 ||
        x86DataCopy(&modelData, &model->data) < 0)
462
        goto error;
463

464
    if ((vendor = x86DataToVendor(&copy, map)) &&
465
        VIR_STRDUP(cpu->vendor, vendor->name) < 0)
466
        goto error;
J
Jiri Denemark 已提交
467

468 469
    x86DataSubtract(&copy, &modelData);
    x86DataSubtract(&modelData, data);
470 471 472

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

474 475
    if (x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_REQUIRE, &copy, map) ||
        x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_DISABLE, &modelData, map))
476
        goto error;
477

478
 cleanup:
479 480
    virCPUx86DataClear(&modelData);
    virCPUx86DataClear(&copy);
481 482
    return cpu;

483
 error:
484 485 486 487 488 489
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
}


J
Jiri Denemark 已提交
490
static void
491
x86VendorFree(virCPUx86VendorPtr vendor)
J
Jiri Denemark 已提交
492 493 494 495 496 497
{
    if (!vendor)
        return;

    VIR_FREE(vendor->name);
    VIR_FREE(vendor);
J
Jiri Denemark 已提交
498
}
J
Jiri Denemark 已提交
499 500


501
static virCPUx86VendorPtr
J
Jiri Denemark 已提交
502
x86VendorFind(virCPUx86MapPtr map,
J
Jiri Denemark 已提交
503 504
              const char *name)
{
505
    size_t i;
J
Jiri Denemark 已提交
506

507 508 509
    for (i = 0; i < map->nvendors; i++) {
        if (STREQ(map->vendors[i]->name, name))
            return map->vendors[i];
J
Jiri Denemark 已提交
510 511 512 513 514 515
    }

    return NULL;
}


J
Jiri Denemark 已提交
516 517 518
static virCPUx86VendorPtr
x86VendorParse(xmlXPathContextPtr ctxt,
               virCPUx86MapPtr map)
J
Jiri Denemark 已提交
519
{
520
    virCPUx86VendorPtr vendor = NULL;
J
Jiri Denemark 已提交
521 522 523
    char *string = NULL;

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

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

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

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

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

J
Jiri Denemark 已提交
557
 cleanup:
J
Jiri Denemark 已提交
558
    VIR_FREE(string);
J
Jiri Denemark 已提交
559 560 561
    return vendor;

 error:
J
Jiri Denemark 已提交
562
    x86VendorFree(vendor);
J
Jiri Denemark 已提交
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
    vendor = NULL;
    goto cleanup;
}


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

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

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

    return 0;
J
Jiri Denemark 已提交
588 589 590
}


591
static virCPUx86FeaturePtr
J
Jiri Denemark 已提交
592 593
x86FeatureNew(void)
{
594
    virCPUx86FeaturePtr feature;
J
Jiri Denemark 已提交
595 596 597 598 599 600 601 602

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

    return feature;
}


J
Jiri Denemark 已提交
603
static void
604
x86FeatureFree(virCPUx86FeaturePtr feature)
J
Jiri Denemark 已提交
605
{
606
    if (!feature)
J
Jiri Denemark 已提交
607 608 609
        return;

    VIR_FREE(feature->name);
610
    virCPUx86DataClear(&feature->data);
J
Jiri Denemark 已提交
611 612 613 614
    VIR_FREE(feature);
}


615
static virCPUx86FeaturePtr
J
Jiri Denemark 已提交
616
x86FeatureFind(virCPUx86MapPtr map,
J
Jiri Denemark 已提交
617 618
               const char *name)
{
619
    size_t i;
J
Jiri Denemark 已提交
620

621 622 623
    for (i = 0; i < map->nfeatures; i++) {
        if (STREQ(map->features[i]->name, name))
            return map->features[i];
J
Jiri Denemark 已提交
624 625 626 627 628 629
    }

    return NULL;
}


630
static char *
J
Jiri Denemark 已提交
631
x86FeatureNames(virCPUx86MapPtr map,
632
                const char *separator,
633
                virCPUx86Data *data)
634 635 636
{
    virBuffer ret = VIR_BUFFER_INITIALIZER;
    bool first = true;
637
    size_t i;
638 639 640

    virBufferAdd(&ret, "", 0);

641 642
    for (i = 0; i < map->nfeatures; i++) {
        virCPUx86FeaturePtr feature = map->features[i];
643
        if (x86DataIsSubset(data, &feature->data)) {
644 645 646 647 648
            if (!first)
                virBufferAdd(&ret, separator, -1);
            else
                first = false;

649
            virBufferAdd(&ret, feature->name, -1);
650 651 652 653 654 655 656
        }
    }

    return virBufferContentAndReset(&ret);
}


657 658
static int
x86ParseCPUID(xmlXPathContextPtr ctxt,
659
              virCPUx86CPUID *cpuid)
660
{
661 662 663
    unsigned long eax_in;
    unsigned long eax, ebx, ecx, edx;
    int ret_eax_in, ret_eax, ret_ebx, ret_ecx, ret_edx;
664 665 666

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

667 668 669
    eax_in = 0;
    eax = ebx = ecx = edx = 0;
    ret_eax_in = virXPathULongHex("string(@eax_in)", ctxt, &eax_in);
670 671 672 673 674
    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);

675 676
    if (ret_eax_in < 0 ||
        ret_eax == -2 || ret_ebx == -2 || ret_ecx == -2 || ret_edx == -2)
677 678
        return -1;

679
    cpuid->eax_in = eax_in;
680 681 682 683 684 685 686 687
    cpuid->eax = eax;
    cpuid->ebx = ebx;
    cpuid->ecx = ecx;
    cpuid->edx = edx;
    return 0;
}


J
Jiri Denemark 已提交
688 689 690
static virCPUx86FeaturePtr
x86FeatureParse(xmlXPathContextPtr ctxt,
                virCPUx86MapPtr map)
J
Jiri Denemark 已提交
691 692
{
    xmlNodePtr *nodes = NULL;
693
    virCPUx86FeaturePtr feature;
694
    virCPUx86CPUID cpuid;
695
    size_t i;
J
Jiri Denemark 已提交
696
    int n;
697
    char *str = NULL;
J
Jiri Denemark 已提交
698

J
Jiri Denemark 已提交
699
    if (!(feature = x86FeatureNew()))
J
Jiri Denemark 已提交
700
        goto error;
J
Jiri Denemark 已提交
701

J
Jiri Denemark 已提交
702
    feature->migratable = true;
703
    feature->name = virXPathString("string(@name)", ctxt);
704
    if (!feature->name) {
705 706
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing CPU feature name"));
J
Jiri Denemark 已提交
707
        goto error;
J
Jiri Denemark 已提交
708 709 710
    }

    if (x86FeatureFind(map, feature->name)) {
711 712
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU feature %s already defined"), feature->name);
J
Jiri Denemark 已提交
713
        goto error;
J
Jiri Denemark 已提交
714 715
    }

716 717
    str = virXPathString("string(@migratable)", ctxt);
    if (STREQ_NULLABLE(str, "no"))
J
Jiri Denemark 已提交
718
        feature->migratable = false;
719

720
    n = virXPathNodeSet("./cpuid", ctxt, &nodes);
J
Jiri Denemark 已提交
721
    if (n < 0)
J
Jiri Denemark 已提交
722
        goto error;
J
Jiri Denemark 已提交
723 724 725

    for (i = 0; i < n; i++) {
        ctxt->node = nodes[i];
726
        if (x86ParseCPUID(ctxt, &cpuid) < 0) {
727
            virReportError(VIR_ERR_INTERNAL_ERROR,
728 729
                           _("Invalid cpuid[%zu] in %s feature"),
                           i, feature->name);
J
Jiri Denemark 已提交
730
            goto error;
J
Jiri Denemark 已提交
731
        }
732
        if (virCPUx86DataAddCPUID(&feature->data, &cpuid))
J
Jiri Denemark 已提交
733
            goto error;
J
Jiri Denemark 已提交
734 735
    }

J
Jiri Denemark 已提交
736
 cleanup:
737
    VIR_FREE(nodes);
738
    VIR_FREE(str);
J
Jiri Denemark 已提交
739
    return feature;
740

J
Jiri Denemark 已提交
741 742 743 744
 error:
    x86FeatureFree(feature);
    feature = NULL;
    goto cleanup;
J
Jiri Denemark 已提交
745 746 747
}


J
Jiri Denemark 已提交
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
static int
x86FeaturesLoad(virCPUx86MapPtr map,
                xmlXPathContextPtr ctxt,
                xmlNodePtr *nodes,
                int n)
{
    virCPUx86FeaturePtr feature;
    size_t i;

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

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

    return 0;
}

775 776 777
static int
x86DataFromCPUFeatures(virCPUx86Data *data,
                       virCPUDefPtr cpu,
J
Jiri Denemark 已提交
778
                       virCPUx86MapPtr map)
779 780 781 782
{
    size_t i;

    for (i = 0; i < cpu->nfeatures; i++) {
783
        virCPUx86FeaturePtr feature;
784 785 786
        if (!(feature = x86FeatureFind(map, cpu->features[i].name))) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU feature %s"), cpu->features[i].name);
787
            return -1;
788 789
        }

790 791
        if (x86DataAdd(data, &feature->data) < 0)
            return -1;
792 793
    }

794
    return 0;
795 796 797
}


J
Jiri Denemark 已提交
798
static virCPUx86ModelPtr
J
Jiri Denemark 已提交
799 800
x86ModelNew(void)
{
J
Jiri Denemark 已提交
801
    virCPUx86ModelPtr model;
J
Jiri Denemark 已提交
802 803 804 805 806 807 808 809

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

    return model;
}


J
Jiri Denemark 已提交
810
static void
J
Jiri Denemark 已提交
811
x86ModelFree(virCPUx86ModelPtr model)
J
Jiri Denemark 已提交
812
{
813
    if (!model)
J
Jiri Denemark 已提交
814 815 816
        return;

    VIR_FREE(model->name);
817
    virCPUx86DataClear(&model->data);
J
Jiri Denemark 已提交
818 819 820 821
    VIR_FREE(model);
}


J
Jiri Denemark 已提交
822 823
static virCPUx86ModelPtr
x86ModelCopy(virCPUx86ModelPtr model)
J
Jiri Denemark 已提交
824
{
J
Jiri Denemark 已提交
825
    virCPUx86ModelPtr copy;
J
Jiri Denemark 已提交
826

827 828
    if (VIR_ALLOC(copy) < 0 ||
        VIR_STRDUP(copy->name, model->name) < 0 ||
829
        x86DataCopy(&copy->data, &model->data) < 0) {
J
Jiri Denemark 已提交
830 831 832 833
        x86ModelFree(copy);
        return NULL;
    }

J
Jiri Denemark 已提交
834
    copy->vendor = model->vendor;
J
Jiri Denemark 已提交
835 836 837 838 839

    return copy;
}


J
Jiri Denemark 已提交
840
static virCPUx86ModelPtr
J
Jiri Denemark 已提交
841
x86ModelFind(virCPUx86MapPtr map,
J
Jiri Denemark 已提交
842 843
             const char *name)
{
844
    size_t i;
J
Jiri Denemark 已提交
845

846 847 848
    for (i = 0; i < map->nmodels; i++) {
        if (STREQ(map->models[i]->name, name))
            return map->models[i];
J
Jiri Denemark 已提交
849 850 851 852 853 854
    }

    return NULL;
}


J
Jiri Denemark 已提交
855
static virCPUx86ModelPtr
856
x86ModelFromCPU(const virCPUDef *cpu,
J
Jiri Denemark 已提交
857
                virCPUx86MapPtr map,
J
Jiri Denemark 已提交
858 859
                int policy)
{
J
Jiri Denemark 已提交
860
    virCPUx86ModelPtr model = NULL;
861
    size_t i;
J
Jiri Denemark 已提交
862

863
    if (policy == VIR_CPU_FEATURE_REQUIRE) {
864
        if (!(model = x86ModelFind(map, cpu->model))) {
865 866
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU model %s"), cpu->model);
J
Jiri Denemark 已提交
867 868 869
            goto error;
        }

870
        if (!(model = x86ModelCopy(model)))
871
            goto error;
J
Jiri Denemark 已提交
872
    } else if (!(model = x86ModelNew())) {
873
        goto error;
J
Jiri Denemark 已提交
874
    } else if (cpu->type == VIR_CPU_TYPE_HOST) {
875
        return model;
J
Jiri Denemark 已提交
876
    }
J
Jiri Denemark 已提交
877 878

    for (i = 0; i < cpu->nfeatures; i++) {
879
        virCPUx86FeaturePtr feature;
J
Jiri Denemark 已提交
880 881 882 883 884

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

885
        if (!(feature = x86FeatureFind(map, cpu->features[i].name))) {
886 887
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU feature %s"), cpu->features[i].name);
J
Jiri Denemark 已提交
888 889 890
            goto error;
        }

891
        if (x86DataAdd(&model->data, &feature->data))
892
            goto error;
J
Jiri Denemark 已提交
893 894 895 896
    }

    return model;

897
 error:
J
Jiri Denemark 已提交
898 899 900 901 902
    x86ModelFree(model);
    return NULL;
}


903
static int
J
Jiri Denemark 已提交
904
x86ModelSubtractCPU(virCPUx86ModelPtr model,
905
                    const virCPUDef *cpu,
J
Jiri Denemark 已提交
906
                    virCPUx86MapPtr map)
907
{
J
Jiri Denemark 已提交
908
    virCPUx86ModelPtr cpu_model;
909
    size_t i;
910 911

    if (!(cpu_model = x86ModelFind(map, cpu->model))) {
912 913 914
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown CPU model %s"),
                       cpu->model);
915 916 917
        return -1;
    }

918
    x86DataSubtract(&model->data, &cpu_model->data);
919 920

    for (i = 0; i < cpu->nfeatures; i++) {
921
        virCPUx86FeaturePtr feature;
922 923

        if (!(feature = x86FeatureFind(map, cpu->features[i].name))) {
924 925 926
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown CPU feature %s"),
                           cpu->features[i].name);
927 928 929
            return -1;
        }

930
        x86DataSubtract(&model->data, &feature->data);
931 932 933 934 935 936
    }

    return 0;
}


937
static virCPUx86CompareResult
J
Jiri Denemark 已提交
938 939
x86ModelCompare(virCPUx86ModelPtr model1,
                virCPUx86ModelPtr model2)
J
Jiri Denemark 已提交
940
{
941
    virCPUx86CompareResult result = EQUAL;
942 943
    virCPUx86DataIterator iter1 = virCPUx86DataIteratorInit(&model1->data);
    virCPUx86DataIterator iter2 = virCPUx86DataIteratorInit(&model2->data);
944 945
    virCPUx86CPUID *cpuid1;
    virCPUx86CPUID *cpuid2;
J
Jiri Denemark 已提交
946

J
Jiri Denemark 已提交
947
    while ((cpuid1 = x86DataCpuidNext(&iter1))) {
948
        virCPUx86CompareResult match = SUPERSET;
J
Jiri Denemark 已提交
949

950
        if ((cpuid2 = x86DataCpuid(&model2->data, cpuid1->eax_in))) {
J
Jiri Denemark 已提交
951 952 953 954 955 956 957 958 959 960 961 962
            if (x86cpuidMatch(cpuid1, cpuid2))
                continue;
            else if (!x86cpuidMatchMasked(cpuid1, cpuid2))
                match = SUBSET;
        }

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

J
Jiri Denemark 已提交
963
    while ((cpuid2 = x86DataCpuidNext(&iter2))) {
964
        virCPUx86CompareResult match = SUBSET;
J
Jiri Denemark 已提交
965

966
        if ((cpuid1 = x86DataCpuid(&model1->data, cpuid2->eax_in))) {
J
Jiri Denemark 已提交
967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
            if (x86cpuidMatch(cpuid2, cpuid1))
                continue;
            else if (!x86cpuidMatchMasked(cpuid2, cpuid1))
                match = SUPERSET;
        }

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

    return result;
}


J
Jiri Denemark 已提交
983 984 985
static virCPUx86ModelPtr
x86ModelParse(xmlXPathContextPtr ctxt,
              virCPUx86MapPtr map)
J
Jiri Denemark 已提交
986 987
{
    xmlNodePtr *nodes = NULL;
J
Jiri Denemark 已提交
988
    virCPUx86ModelPtr model;
J
Jiri Denemark 已提交
989
    char *vendor = NULL;
990
    size_t i;
J
Jiri Denemark 已提交
991 992
    int n;

J
Jiri Denemark 已提交
993
    if (!(model = x86ModelNew()))
J
Jiri Denemark 已提交
994
        goto error;
J
Jiri Denemark 已提交
995

996
    model->name = virXPathString("string(@name)", ctxt);
997
    if (!model->name) {
998 999
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing CPU model name"));
J
Jiri Denemark 已提交
1000
        goto error;
J
Jiri Denemark 已提交
1001 1002
    }

1003
    if (virXPathNode("./model", ctxt)) {
J
Jiri Denemark 已提交
1004
        virCPUx86ModelPtr ancestor;
J
Jiri Denemark 已提交
1005 1006
        char *name;

1007
        name = virXPathString("string(./model/@name)", ctxt);
1008
        if (!name) {
1009 1010 1011
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing ancestor's name in CPU model %s"),
                           model->name);
J
Jiri Denemark 已提交
1012
            goto error;
J
Jiri Denemark 已提交
1013 1014
        }

1015
        if (!(ancestor = x86ModelFind(map, name))) {
1016 1017 1018
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Ancestor model %s not found for CPU model %s"),
                           name, model->name);
J
Jiri Denemark 已提交
1019
            VIR_FREE(name);
J
Jiri Denemark 已提交
1020
            goto error;
J
Jiri Denemark 已提交
1021 1022 1023 1024
        }

        VIR_FREE(name);

J
Jiri Denemark 已提交
1025
        model->vendor = ancestor->vendor;
1026
        if (x86DataCopy(&model->data, &ancestor->data) < 0)
J
Jiri Denemark 已提交
1027
            goto error;
J
Jiri Denemark 已提交
1028 1029
    }

1030 1031 1032
    if (virXPathBoolean("boolean(./vendor)", ctxt)) {
        vendor = virXPathString("string(./vendor/@name)", ctxt);
        if (!vendor) {
1033 1034 1035
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid vendor element in CPU model %s"),
                           model->name);
J
Jiri Denemark 已提交
1036
            goto error;
1037 1038
        }

J
Jiri Denemark 已提交
1039
        if (!(model->vendor = x86VendorFind(map, vendor))) {
1040 1041 1042
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown vendor %s referenced by CPU model %s"),
                           vendor, model->name);
J
Jiri Denemark 已提交
1043
            goto error;
J
Jiri Denemark 已提交
1044 1045 1046
        }
    }

1047
    n = virXPathNodeSet("./feature", ctxt, &nodes);
J
Jiri Denemark 已提交
1048
    if (n < 0)
J
Jiri Denemark 已提交
1049
        goto error;
J
Jiri Denemark 已提交
1050 1051

    for (i = 0; i < n; i++) {
1052
        virCPUx86FeaturePtr feature;
J
Jiri Denemark 已提交
1053 1054
        char *name;

1055
        if (!(name = virXMLPropString(nodes[i], "name"))) {
1056 1057
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing feature name for CPU model %s"), model->name);
J
Jiri Denemark 已提交
1058
            goto error;
J
Jiri Denemark 已提交
1059 1060
        }

1061
        if (!(feature = x86FeatureFind(map, name))) {
1062 1063 1064
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Feature %s required by CPU model %s not found"),
                           name, model->name);
J
Jiri Denemark 已提交
1065
            VIR_FREE(name);
J
Jiri Denemark 已提交
1066
            goto error;
J
Jiri Denemark 已提交
1067 1068 1069
        }
        VIR_FREE(name);

1070
        if (x86DataAdd(&model->data, &feature->data))
J
Jiri Denemark 已提交
1071
            goto error;
J
Jiri Denemark 已提交
1072 1073
    }

J
Jiri Denemark 已提交
1074
 cleanup:
J
Jiri Denemark 已提交
1075
    VIR_FREE(vendor);
1076
    VIR_FREE(nodes);
J
Jiri Denemark 已提交
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
    return model;

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


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

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

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

    return 0;
J
Jiri Denemark 已提交
1106 1107 1108 1109
}


static void
J
Jiri Denemark 已提交
1110
x86MapFree(virCPUx86MapPtr map)
J
Jiri Denemark 已提交
1111
{
1112 1113
    size_t i;

1114
    if (!map)
J
Jiri Denemark 已提交
1115 1116
        return;

1117 1118 1119
    for (i = 0; i < map->nfeatures; i++)
        x86FeatureFree(map->features[i]);
    VIR_FREE(map->features);
J
Jiri Denemark 已提交
1120

1121 1122 1123
    for (i = 0; i < map->nmodels; i++)
        x86ModelFree(map->models[i]);
    VIR_FREE(map->models);
J
Jiri Denemark 已提交
1124

1125 1126 1127
    for (i = 0; i < map->nvendors; i++)
        x86VendorFree(map->vendors[i]);
    VIR_FREE(map->vendors);
1128

1129 1130 1131 1132
    /* migrate_blockers only points to the features from map->features list,
     * which were already freed above
     */
    VIR_FREE(map->migrate_blockers);
1133

J
Jiri Denemark 已提交
1134 1135 1136 1137
    VIR_FREE(map);
}


J
Jiri Denemark 已提交
1138
static int
1139
x86MapLoadCallback(cpuMapElement element,
J
Jiri Denemark 已提交
1140
                   xmlXPathContextPtr ctxt,
J
Jiri Denemark 已提交
1141 1142
                   xmlNodePtr *nodes,
                   int n,
J
Jiri Denemark 已提交
1143 1144
                   void *data)
{
J
Jiri Denemark 已提交
1145
    virCPUx86MapPtr map = data;
J
Jiri Denemark 已提交
1146 1147 1148

    switch (element) {
    case CPU_MAP_ELEMENT_VENDOR:
J
Jiri Denemark 已提交
1149
        return x86VendorsLoad(map, ctxt, nodes, n);
J
Jiri Denemark 已提交
1150
    case CPU_MAP_ELEMENT_FEATURE:
J
Jiri Denemark 已提交
1151
        return x86FeaturesLoad(map, ctxt, nodes, n);
J
Jiri Denemark 已提交
1152
    case CPU_MAP_ELEMENT_MODEL:
J
Jiri Denemark 已提交
1153
        return x86ModelsLoad(map, ctxt, nodes, n);
J
Jiri Denemark 已提交
1154 1155 1156 1157 1158 1159 1160 1161
    case CPU_MAP_ELEMENT_LAST:
        break;
    }

    return 0;
}


1162
static int
J
Jiri Denemark 已提交
1163
x86MapLoadInternalFeatures(virCPUx86MapPtr map)
1164 1165
{
    size_t i;
1166
    virCPUx86FeaturePtr feature = NULL;
1167 1168 1169 1170 1171
    size_t nfeatures = map->nfeatures;
    size_t count = ARRAY_CARDINALITY(x86_kvm_features);

    if (VIR_EXPAND_N(map->features, nfeatures, count) < 0)
        goto error;
1172

1173
    for (i = 0; i < count; i++) {
1174 1175 1176 1177 1178
        const char *name = x86_kvm_features[i].name;

        if (x86FeatureFind(map, name)) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("CPU feature %s already defined"), name);
1179
            goto error;
1180 1181 1182 1183 1184 1185 1186 1187
        }

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

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

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

1191
        map->features[map->nfeatures++] = feature;
1192 1193 1194 1195 1196
        feature = NULL;
    }

    return 0;

1197
 error:
1198 1199 1200 1201 1202
    x86FeatureFree(feature);
    return -1;
}


J
Jiri Denemark 已提交
1203
static virCPUx86MapPtr
1204
virCPUx86LoadMap(void)
J
Jiri Denemark 已提交
1205
{
J
Jiri Denemark 已提交
1206
    virCPUx86MapPtr map;
J
Jiri Denemark 已提交
1207

1208
    if (VIR_ALLOC(map) < 0)
J
Jiri Denemark 已提交
1209 1210
        return NULL;

J
Jiri Denemark 已提交
1211
    if (cpuMapLoad("x86", x86MapLoadCallback, map) < 0)
J
Jiri Denemark 已提交
1212 1213
        goto error;

1214 1215 1216
    if (x86MapLoadInternalFeatures(map) < 0)
        goto error;

J
Jiri Denemark 已提交
1217 1218
    return map;

1219
 error:
J
Jiri Denemark 已提交
1220 1221 1222 1223 1224
    x86MapFree(map);
    return NULL;
}


1225 1226 1227
int
virCPUx86MapOnceInit(void)
{
J
Jiri Denemark 已提交
1228
    if (!(cpuMap = virCPUx86LoadMap()))
1229 1230 1231 1232 1233 1234
        return -1;

    return 0;
}


J
Jiri Denemark 已提交
1235
static virCPUx86MapPtr
1236 1237 1238 1239 1240
virCPUx86GetMap(void)
{
    if (virCPUx86MapInitialize() < 0)
        return NULL;

J
Jiri Denemark 已提交
1241
    return cpuMap;
1242 1243 1244
}


1245 1246 1247
static char *
x86CPUDataFormat(const virCPUData *data)
{
1248
    virCPUx86DataIterator iter = virCPUx86DataIteratorInit(&data->data.x86);
1249
    virCPUx86CPUID *cpuid;
1250 1251 1252 1253 1254
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virBufferAddLit(&buf, "<cpudata arch='x86'>\n");
    while ((cpuid = x86DataCpuidNext(&iter))) {
        virBufferAsprintf(&buf,
1255
                          "  <cpuid eax_in='0x%08x'"
1256 1257
                          " eax='0x%08x' ebx='0x%08x'"
                          " ecx='0x%08x' edx='0x%08x'/>\n",
1258
                          cpuid->eax_in,
1259 1260 1261 1262
                          cpuid->eax, cpuid->ebx, cpuid->ecx, cpuid->edx);
    }
    virBufferAddLit(&buf, "</cpudata>\n");

1263
    if (virBufferCheckError(&buf) < 0)
1264 1265 1266 1267 1268 1269 1270
        return NULL;

    return virBufferContentAndReset(&buf);
}


static virCPUDataPtr
1271
x86CPUDataParse(xmlXPathContextPtr ctxt)
1272 1273 1274
{
    xmlNodePtr *nodes = NULL;
    virCPUDataPtr cpuData = NULL;
1275
    virCPUx86Data data = VIR_CPU_X86_DATA_INIT;
1276
    virCPUx86CPUID cpuid;
1277 1278 1279
    size_t i;
    int n;

1280
    n = virXPathNodeSet("/cpudata/cpuid", ctxt, &nodes);
J
Jiri Denemark 已提交
1281
    if (n <= 0) {
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("no x86 CPU data found"));
        goto cleanup;
    }

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

1298
    cpuData = virCPUx86MakeData(VIR_ARCH_X86_64, &data);
1299

1300
 cleanup:
1301
    VIR_FREE(nodes);
1302
    virCPUx86DataClear(&data);
1303 1304 1305 1306
    return cpuData;
}


1307 1308 1309
/* A helper macro to exit the cpu computation function without writing
 * redundant code:
 * MSG: error message
1310
 * CPU_DEF: a virCPUx86Data pointer with flags that are conflicting
1311 1312 1313 1314 1315 1316 1317
 * RET: return code to set
 *
 * This macro generates the error string outputs it into logs.
 */
#define virX86CpuIncompatible(MSG, CPU_DEF)                             \
        do {                                                            \
            char *flagsStr = NULL;                                      \
1318 1319 1320 1321
            if (!(flagsStr = x86FeatureNames(map, ", ", (CPU_DEF)))) {  \
                virReportOOMError();                                    \
                goto error;                                             \
            }                                                           \
1322 1323 1324
            if (message &&                                              \
                virAsprintf(message, "%s: %s", _(MSG), flagsStr) < 0) { \
                VIR_FREE(flagsStr);                                     \
1325
                goto error;                                             \
1326 1327 1328 1329 1330 1331
            }                                                           \
            VIR_DEBUG("%s: %s", MSG, flagsStr);                         \
            VIR_FREE(flagsStr);                                         \
            ret = VIR_CPU_COMPARE_INCOMPATIBLE;                         \
        } while (0)

1332

J
Jiri Denemark 已提交
1333 1334 1335
static virCPUCompareResult
x86Compute(virCPUDefPtr host,
           virCPUDefPtr cpu,
1336
           virCPUDataPtr *guest,
1337
           char **message)
J
Jiri Denemark 已提交
1338
{
J
Jiri Denemark 已提交
1339
    virCPUx86MapPtr map = NULL;
J
Jiri Denemark 已提交
1340 1341 1342 1343 1344 1345 1346 1347
    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;
1348
    virCPUx86Data guestData = VIR_CPU_X86_DATA_INIT;
J
Jiri Denemark 已提交
1349
    virCPUCompareResult ret;
1350
    virCPUx86CompareResult result;
J
Jiri Denemark 已提交
1351
    virArch arch;
1352
    size_t i;
J
Jiri Denemark 已提交
1353

1354 1355 1356 1357 1358 1359
    if (!cpu->model) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("no guest CPU model specified"));
        return VIR_CPU_COMPARE_ERROR;
    }

1360
    if (cpu->arch != VIR_ARCH_NONE) {
J
Jiri Denemark 已提交
1361 1362 1363
        bool found = false;

        for (i = 0; i < ARRAY_CARDINALITY(archs); i++) {
1364
            if (archs[i] == cpu->arch) {
J
Jiri Denemark 已提交
1365 1366 1367 1368 1369
                found = true;
                break;
            }
        }

1370
        if (!found) {
1371 1372
            VIR_DEBUG("CPU arch %s does not match host arch",
                      virArchToString(cpu->arch));
1373 1374 1375
            if (message &&
                virAsprintf(message,
                            _("CPU arch %s does not match host arch"),
1376
                            virArchToString(cpu->arch)) < 0)
1377
                goto error;
J
Jiri Denemark 已提交
1378
            return VIR_CPU_COMPARE_INCOMPATIBLE;
1379
        }
J
Jiri Denemark 已提交
1380 1381 1382
        arch = cpu->arch;
    } else {
        arch = host->arch;
J
Jiri Denemark 已提交
1383 1384
    }

J
Jiri Denemark 已提交
1385 1386 1387 1388
    if (cpu->vendor &&
        (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) {
        VIR_DEBUG("host CPU vendor does not match required CPU vendor %s",
                  cpu->vendor);
1389 1390 1391 1392 1393
        if (message &&
            virAsprintf(message,
                        _("host CPU vendor does not match required "
                          "CPU vendor %s"),
                        cpu->vendor) < 0)
1394
            goto error;
1395

J
Jiri Denemark 已提交
1396 1397 1398
        return VIR_CPU_COMPARE_INCOMPATIBLE;
    }

1399
    if (!(map = virCPUx86GetMap()) ||
1400
        !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)) ||
J
Jiri Denemark 已提交
1401 1402 1403 1404 1405
        !(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 已提交
1406 1407
        goto error;

1408 1409
    x86DataIntersect(&cpu_forbid->data, &host_model->data);
    if (!x86DataIsEmpty(&cpu_forbid->data)) {
1410
        virX86CpuIncompatible(N_("Host CPU provides forbidden features"),
1411
                              &cpu_forbid->data);
1412
        goto cleanup;
J
Jiri Denemark 已提交
1413 1414
    }

1415 1416 1417
    /* first remove features that were inherited from the CPU model and were
     * explicitly forced, disabled, or made optional
     */
1418 1419 1420
    x86DataSubtract(&cpu_require->data, &cpu_force->data);
    x86DataSubtract(&cpu_require->data, &cpu_optional->data);
    x86DataSubtract(&cpu_require->data, &cpu_disable->data);
J
Jiri Denemark 已提交
1421 1422
    result = x86ModelCompare(host_model, cpu_require);
    if (result == SUBSET || result == UNRELATED) {
1423
        x86DataSubtract(&cpu_require->data, &host_model->data);
1424 1425
        virX86CpuIncompatible(N_("Host CPU does not provide required "
                                 "features"),
1426
                              &cpu_require->data);
1427
        goto cleanup;
J
Jiri Denemark 已提交
1428 1429 1430 1431
    }

    ret = VIR_CPU_COMPARE_IDENTICAL;

1432
    if (!(diff = x86ModelCopy(host_model)))
1433
        goto error;
J
Jiri Denemark 已提交
1434

1435 1436 1437 1438
    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 已提交
1439

1440
    if (!x86DataIsEmpty(&diff->data))
J
Jiri Denemark 已提交
1441
        ret = VIR_CPU_COMPARE_SUPERSET;
J
Jiri Denemark 已提交
1442 1443 1444 1445

    if (ret == VIR_CPU_COMPARE_SUPERSET
        && cpu->type == VIR_CPU_TYPE_GUEST
        && cpu->match == VIR_CPU_MATCH_STRICT) {
1446 1447
        virX86CpuIncompatible(N_("Host CPU does not strictly match guest CPU: "
                                 "Extra features"),
1448
                              &diff->data);
1449
        goto cleanup;
J
Jiri Denemark 已提交
1450 1451
    }

1452 1453
    if (guest) {
        if (!(guest_model = x86ModelCopy(host_model)))
1454
            goto error;
J
Jiri Denemark 已提交
1455

1456
        if (cpu->vendor &&
1457
            virCPUx86DataAddCPUID(&guest_model->data,
1458 1459 1460
                                  &host_model->vendor->cpuid) < 0)
            goto error;

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

1465
        if (x86DataAdd(&guest_model->data, &cpu_force->data))
1466
            goto error;
J
Jiri Denemark 已提交
1467

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

1470 1471
        if (x86DataCopy(&guestData, &guest_model->data) < 0 ||
            !(*guest = virCPUx86MakeData(arch, &guestData)))
1472
            goto error;
J
Jiri Denemark 已提交
1473 1474
    }

1475
 cleanup:
J
Jiri Denemark 已提交
1476 1477 1478 1479 1480 1481 1482 1483
    x86ModelFree(host_model);
    x86ModelFree(diff);
    x86ModelFree(cpu_force);
    x86ModelFree(cpu_require);
    x86ModelFree(cpu_optional);
    x86ModelFree(cpu_disable);
    x86ModelFree(cpu_forbid);
    x86ModelFree(guest_model);
1484
    virCPUx86DataClear(&guestData);
J
Jiri Denemark 已提交
1485 1486 1487

    return ret;

1488
 error:
J
Jiri Denemark 已提交
1489
    ret = VIR_CPU_COMPARE_ERROR;
1490
    goto cleanup;
J
Jiri Denemark 已提交
1491
}
1492
#undef virX86CpuIncompatible
J
Jiri Denemark 已提交
1493 1494 1495 1496


static virCPUCompareResult
x86Compare(virCPUDefPtr host,
1497
           virCPUDefPtr cpu,
1498
           bool failIncompatible)
J
Jiri Denemark 已提交
1499
{
1500 1501 1502 1503 1504
    virCPUCompareResult ret;
    char *message = NULL;

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

1505
    if (failIncompatible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) {
1506 1507 1508 1509 1510 1511 1512 1513 1514 1515
        ret = VIR_CPU_COMPARE_ERROR;
        if (message) {
            virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", message);
        } else {
            virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL);
        }
    }
    VIR_FREE(message);

    return ret;
J
Jiri Denemark 已提交
1516 1517 1518 1519 1520 1521
}


static virCPUCompareResult
x86GuestData(virCPUDefPtr host,
             virCPUDefPtr guest,
1522
             virCPUDataPtr *data,
1523
             char **message)
J
Jiri Denemark 已提交
1524
{
1525
    return x86Compute(host, guest, data, message);
J
Jiri Denemark 已提交
1526 1527
}

1528

1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565
/*
 * Checks whether cpuCandidate is a better fit for the CPU data than the
 * currently selected one from cpuCurrent.
 *
 * Returns 0 if cpuCurrent is better,
 *         1 if cpuCandidate is better,
 *         2 if cpuCandidate is the best one (search should stop now).
 */
static int
x86DecodeUseCandidate(virCPUDefPtr cpuCurrent,
                      virCPUDefPtr cpuCandidate,
                      const char *preferred,
                      bool checkPolicy)
{
    if (checkPolicy) {
        size_t i;
        for (i = 0; i < cpuCandidate->nfeatures; i++) {
            if (cpuCandidate->features[i].policy == VIR_CPU_FEATURE_DISABLE)
                return 0;
            cpuCandidate->features[i].policy = -1;
        }
    }

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

    if (!cpuCurrent)
        return 1;

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

    return 0;
}


J
Jiri Denemark 已提交
1566 1567
static int
x86Decode(virCPUDefPtr cpu,
1568
          const virCPUx86Data *data,
1569
          const char **models,
1570
          unsigned int nmodels,
1571 1572
          const char *preferred,
          unsigned int flags)
J
Jiri Denemark 已提交
1573 1574
{
    int ret = -1;
J
Jiri Denemark 已提交
1575
    virCPUx86MapPtr map;
J
Jiri Denemark 已提交
1576
    virCPUx86ModelPtr candidate;
1577 1578
    virCPUDefPtr cpuCandidate;
    virCPUDefPtr cpuModel = NULL;
1579 1580
    virCPUx86Data copy = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data features = VIR_CPU_X86_DATA_INIT;
1581
    const virCPUx86Data *cpuData = NULL;
J
Jiri Denemark 已提交
1582
    virCPUx86VendorPtr vendor;
1583
    ssize_t i;
1584
    int rc;
J
Jiri Denemark 已提交
1585

1586 1587
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, -1);
1588

1589
    if (!data || !(map = virCPUx86GetMap()))
J
Jiri Denemark 已提交
1590 1591
        return -1;

J
Jiri Denemark 已提交
1592 1593
    vendor = x86DataToVendor(data, map);

1594 1595 1596 1597 1598
    /* 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];
1599
        if (!cpuModelIsAllowed(candidate->name, models, nmodels)) {
1600 1601
            if (preferred && STREQ(candidate->name, preferred)) {
                if (cpu->fallback != VIR_CPU_FALLBACK_ALLOW) {
1602 1603 1604
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("CPU model %s is not supported by hypervisor"),
                                   preferred);
J
Jiri Denemark 已提交
1605
                    goto cleanup;
1606 1607 1608 1609 1610 1611 1612 1613 1614
                } 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);
            }
1615
            continue;
J
Jiri Denemark 已提交
1616 1617
        }

J
Jiri Denemark 已提交
1618 1619 1620 1621
        /* 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 已提交
1622
            VIR_DEBUG("CPU vendor %s of model %s differs from %s; ignoring",
J
Jiri Denemark 已提交
1623
                      candidate->vendor->name, candidate->name, vendor->name);
1624
            continue;
J
Jiri Denemark 已提交
1625 1626
        }

J
Jiri Denemark 已提交
1627 1628 1629 1630
        if (!(cpuCandidate = x86DataToCPU(data, candidate, map)))
            goto cleanup;
        cpuCandidate->type = cpu->type;

1631 1632
        if ((rc = x86DecodeUseCandidate(cpuModel, cpuCandidate, preferred,
                                        cpu->type == VIR_CPU_TYPE_HOST))) {
1633 1634
            virCPUDefFree(cpuModel);
            cpuModel = cpuCandidate;
1635
            cpuData = &candidate->data;
1636 1637
            if (rc == 2)
                break;
1638
        } else {
1639
            virCPUDefFree(cpuCandidate);
1640
        }
J
Jiri Denemark 已提交
1641 1642
    }

1643
    if (!cpuModel) {
1644 1645
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Cannot find suitable CPU model for given data"));
J
Jiri Denemark 已提交
1646
        goto cleanup;
J
Jiri Denemark 已提交
1647 1648
    }

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

1666
    if (flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) {
1667 1668
        if (x86DataCopy(&copy, cpuData) < 0 ||
            x86DataFromCPUFeatures(&features, cpuModel, map) < 0)
J
Jiri Denemark 已提交
1669
            goto cleanup;
1670

1671
        x86DataSubtract(&copy, &features);
1672
        if (x86DataToCPUFeatures(cpuModel, VIR_CPU_FEATURE_REQUIRE,
1673
                                 &copy, map) < 0)
J
Jiri Denemark 已提交
1674
            goto cleanup;
1675 1676
    }

J
Jiri Denemark 已提交
1677 1678 1679
    if (vendor && VIR_STRDUP(cpu->vendor, vendor->name) < 0)
        goto cleanup;

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

    ret = 0;

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

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

1705

1706 1707 1708
static int
x86EncodePolicy(virCPUx86Data *data,
                const virCPUDef *cpu,
J
Jiri Denemark 已提交
1709
                virCPUx86MapPtr map,
1710
                virCPUFeaturePolicy policy)
J
Jiri Denemark 已提交
1711
{
J
Jiri Denemark 已提交
1712
    virCPUx86ModelPtr model;
J
Jiri Denemark 已提交
1713 1714

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

1717 1718 1719
    *data = model->data;
    model->data.len = 0;
    model->data.data = NULL;
J
Jiri Denemark 已提交
1720 1721
    x86ModelFree(model);

1722
    return 0;
J
Jiri Denemark 已提交
1723 1724 1725 1726
}


static int
J
Jiri Denemark 已提交
1727
x86Encode(virArch arch,
1728
          const virCPUDef *cpu,
1729 1730 1731 1732 1733 1734
          virCPUDataPtr *forced,
          virCPUDataPtr *required,
          virCPUDataPtr *optional,
          virCPUDataPtr *disabled,
          virCPUDataPtr *forbidden,
          virCPUDataPtr *vendor)
J
Jiri Denemark 已提交
1735
{
J
Jiri Denemark 已提交
1736
    virCPUx86MapPtr map = NULL;
1737 1738 1739 1740 1741 1742
    virCPUx86Data data_forced = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data data_required = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data data_optional = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data data_disabled = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data data_forbidden = VIR_CPU_X86_DATA_INIT;
    virCPUx86Data data_vendor = VIR_CPU_X86_DATA_INIT;
J
Jiri Denemark 已提交
1743

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

1757
    if (!(map = virCPUx86GetMap()))
J
Jiri Denemark 已提交
1758 1759
        goto error;

1760 1761 1762
    if (forced &&
        x86EncodePolicy(&data_forced, cpu, map, VIR_CPU_FEATURE_FORCE) < 0)
        goto error;
J
Jiri Denemark 已提交
1763

1764 1765 1766
    if (required &&
        x86EncodePolicy(&data_required, cpu, map, VIR_CPU_FEATURE_REQUIRE) < 0)
        goto error;
J
Jiri Denemark 已提交
1767

1768 1769 1770
    if (optional &&
        x86EncodePolicy(&data_optional, cpu, map, VIR_CPU_FEATURE_OPTIONAL) < 0)
        goto error;
J
Jiri Denemark 已提交
1771

1772 1773 1774
    if (disabled &&
        x86EncodePolicy(&data_disabled, cpu, map, VIR_CPU_FEATURE_DISABLE) < 0)
        goto error;
J
Jiri Denemark 已提交
1775

1776 1777 1778
    if (forbidden &&
        x86EncodePolicy(&data_forbidden, cpu, map, VIR_CPU_FEATURE_FORBID) < 0)
        goto error;
J
Jiri Denemark 已提交
1779

J
Jiri Denemark 已提交
1780
    if (vendor) {
1781
        virCPUx86VendorPtr v = NULL;
J
Jiri Denemark 已提交
1782 1783

        if (cpu->vendor && !(v = x86VendorFind(map, cpu->vendor))) {
1784 1785
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("CPU vendor %s not found"), cpu->vendor);
J
Jiri Denemark 已提交
1786 1787 1788
            goto error;
        }

1789
        if (v && virCPUx86DataAddCPUID(&data_vendor, &v->cpuid) < 0)
J
Jiri Denemark 已提交
1790 1791 1792
            goto error;
    }

1793
    if (forced &&
1794
        !(*forced = virCPUx86MakeData(arch, &data_forced)))
1795 1796
        goto error;
    if (required &&
1797
        !(*required = virCPUx86MakeData(arch, &data_required)))
1798 1799
        goto error;
    if (optional &&
1800
        !(*optional = virCPUx86MakeData(arch, &data_optional)))
1801 1802
        goto error;
    if (disabled &&
1803
        !(*disabled = virCPUx86MakeData(arch, &data_disabled)))
1804 1805
        goto error;
    if (forbidden &&
1806
        !(*forbidden = virCPUx86MakeData(arch, &data_forbidden)))
1807 1808
        goto error;
    if (vendor &&
1809
        !(*vendor = virCPUx86MakeData(arch, &data_vendor)))
1810
        goto error;
J
Jiri Denemark 已提交
1811

1812
    return 0;
J
Jiri Denemark 已提交
1813

1814
 error:
1815 1816 1817 1818 1819 1820
    virCPUx86DataClear(&data_forced);
    virCPUx86DataClear(&data_required);
    virCPUx86DataClear(&data_optional);
    virCPUx86DataClear(&data_disabled);
    virCPUx86DataClear(&data_forbidden);
    virCPUx86DataClear(&data_vendor);
1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832
    if (forced)
        x86FreeCPUData(*forced);
    if (required)
        x86FreeCPUData(*required);
    if (optional)
        x86FreeCPUData(*optional);
    if (disabled)
        x86FreeCPUData(*disabled);
    if (forbidden)
        x86FreeCPUData(*forbidden);
    if (vendor)
        x86FreeCPUData(*vendor);
1833
    return -1;
J
Jiri Denemark 已提交
1834 1835 1836 1837 1838
}


#if HAVE_CPUID
static inline void
1839
cpuidCall(virCPUx86CPUID *cpuid)
J
Jiri Denemark 已提交
1840
{
1841
# if __x86_64__
1842 1843 1844 1845
    asm("xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */
        "xor %%ecx, %%ecx;" /* functions may use them as additional */
        "xor %%edx, %%edx;" /* arguments */
        "cpuid;"
J
Jiri Denemark 已提交
1846 1847 1848 1849
        : "=a" (cpuid->eax),
          "=b" (cpuid->ebx),
          "=c" (cpuid->ecx),
          "=d" (cpuid->edx)
1850
        : "a" (cpuid->eax_in));
1851
# else
J
Jiri Denemark 已提交
1852 1853 1854 1855
    /* 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;"
1856 1857 1858
        "xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */
        "xor %%ecx, %%ecx;" /* functions may use them as additional */
        "xor %%edx, %%edx;" /* arguments */
J
Jiri Denemark 已提交
1859 1860 1861 1862 1863 1864 1865
        "cpuid;"
        "mov %%ebx, %1;"
        "pop %%ebx;"
        : "=a" (cpuid->eax),
          "=r" (cpuid->ebx),
          "=c" (cpuid->ecx),
          "=d" (cpuid->edx)
1866
        : "a" (cpuid->eax_in)
J
Jiri Denemark 已提交
1867
        : "cc");
1868
# endif
J
Jiri Denemark 已提交
1869 1870 1871 1872
}


static int
1873
cpuidSet(uint32_t base, virCPUx86Data *data)
J
Jiri Denemark 已提交
1874 1875 1876
{
    uint32_t max;
    uint32_t i;
1877
    virCPUx86CPUID cpuid = { base, 0, 0, 0, 0 };
J
Jiri Denemark 已提交
1878 1879

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

1882
    for (i = base; i <= max; i++) {
1883
        cpuid.eax_in = i;
J
Jiri Denemark 已提交
1884
        cpuidCall(&cpuid);
1885 1886
        if (virCPUx86DataAddCPUID(data, &cpuid) < 0)
            return -1;
J
Jiri Denemark 已提交
1887 1888
    }

1889
    return 0;
J
Jiri Denemark 已提交
1890 1891 1892
}


1893
static virCPUDataPtr
1894
x86NodeData(virArch arch)
J
Jiri Denemark 已提交
1895
{
1896
    virCPUDataPtr cpuData = NULL;
1897
    virCPUx86Data data = VIR_CPU_X86_DATA_INIT;
J
Jiri Denemark 已提交
1898

1899
    if (cpuidSet(CPUX86_BASIC, &data) < 0)
J
Jiri Denemark 已提交
1900 1901
        goto error;

1902
    if (cpuidSet(CPUX86_EXTENDED, &data) < 0)
J
Jiri Denemark 已提交
1903 1904
        goto error;

1905
    if (!(cpuData = virCPUx86MakeData(arch, &data)))
1906 1907 1908
        goto error;

    return cpuData;
J
Jiri Denemark 已提交
1909

1910
 error:
1911
    virCPUx86DataClear(&data);
J
Jiri Denemark 已提交
1912 1913 1914 1915 1916 1917

    return NULL;
}
#endif


1918 1919 1920 1921
static virCPUDefPtr
x86Baseline(virCPUDefPtr *cpus,
            unsigned int ncpus,
            const char **models,
1922 1923
            unsigned int nmodels,
            unsigned int flags)
1924
{
J
Jiri Denemark 已提交
1925
    virCPUx86MapPtr map = NULL;
J
Jiri Denemark 已提交
1926
    virCPUx86ModelPtr base_model = NULL;
1927
    virCPUDefPtr cpu = NULL;
1928
    size_t i;
1929
    virCPUx86VendorPtr vendor = NULL;
J
Jiri Denemark 已提交
1930
    virCPUx86ModelPtr model = NULL;
1931
    bool outputVendor = true;
1932 1933
    const char *modelName;
    bool matchingNames = true;
1934

1935 1936 1937
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL);

1938
    if (!(map = virCPUx86GetMap()))
1939 1940
        goto error;

1941
    if (!(base_model = x86ModelFromCPU(cpus[0], map, VIR_CPU_FEATURE_REQUIRE)))
1942 1943
        goto error;

1944
    if (VIR_ALLOC(cpu) < 0)
1945
        goto error;
1946 1947

    cpu->arch = cpus[0]->arch;
1948 1949
    cpu->type = VIR_CPU_TYPE_GUEST;
    cpu->match = VIR_CPU_MATCH_EXACT;
1950

1951
    if (!cpus[0]->vendor) {
1952
        outputVendor = false;
1953
    } else if (!(vendor = x86VendorFind(map, cpus[0]->vendor))) {
1954 1955
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Unknown CPU vendor %s"), cpus[0]->vendor);
J
Jiri Denemark 已提交
1956 1957 1958
        goto error;
    }

1959
    modelName = cpus[0]->model;
1960
    for (i = 1; i < ncpus; i++) {
J
Jiri Denemark 已提交
1961 1962
        const char *vn = NULL;

1963 1964 1965 1966 1967 1968 1969 1970 1971
        if (matchingNames && cpus[i]->model) {
            if (!modelName) {
                modelName = cpus[i]->model;
            } else if (STRNEQ(modelName, cpus[i]->model)) {
                modelName = NULL;
                matchingNames = false;
            }
        }

1972
        if (!(model = x86ModelFromCPU(cpus[i], map, VIR_CPU_FEATURE_REQUIRE)))
1973 1974
            goto error;

J
Jiri Denemark 已提交
1975 1976
        if (cpus[i]->vendor && model->vendor &&
            STRNEQ(cpus[i]->vendor, model->vendor->name)) {
1977 1978 1979
            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 已提交
1980 1981 1982
            goto error;
        }

1983
        if (cpus[i]->vendor) {
J
Jiri Denemark 已提交
1984
            vn = cpus[i]->vendor;
1985
        } else {
1986 1987 1988 1989
            outputVendor = false;
            if (model->vendor)
                vn = model->vendor->name;
        }
J
Jiri Denemark 已提交
1990 1991 1992 1993

        if (vn) {
            if (!vendor) {
                if (!(vendor = x86VendorFind(map, vn))) {
1994 1995
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("Unknown CPU vendor %s"), vn);
J
Jiri Denemark 已提交
1996 1997 1998
                    goto error;
                }
            } else if (STRNEQ(vendor->name, vn)) {
1999 2000
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("CPU vendors do not match"));
J
Jiri Denemark 已提交
2001 2002 2003 2004
                goto error;
            }
        }

2005
        x86DataIntersect(&base_model->data, &model->data);
2006
        x86ModelFree(model);
J
Jiri Denemark 已提交
2007
        model = NULL;
2008 2009
    }

2010
    if (x86DataIsEmpty(&base_model->data)) {
2011 2012
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("CPUs are incompatible"));
2013 2014 2015
        goto error;
    }

2016
    if (vendor && virCPUx86DataAddCPUID(&base_model->data, &vendor->cpuid) < 0)
2017
        goto error;
J
Jiri Denemark 已提交
2018

2019
    if (x86Decode(cpu, &base_model->data, models, nmodels, modelName, flags) < 0)
2020 2021
        goto error;

2022 2023 2024
    if (STREQ_NULLABLE(cpu->model, modelName))
        cpu->fallback = VIR_CPU_FALLBACK_FORBID;

2025 2026 2027
    if (!outputVendor)
        VIR_FREE(cpu->vendor);

2028 2029
    cpu->arch = VIR_ARCH_NONE;

2030
 cleanup:
2031 2032 2033 2034
    x86ModelFree(base_model);

    return cpu;

2035
 error:
J
Jiri Denemark 已提交
2036
    x86ModelFree(model);
2037 2038 2039 2040 2041 2042
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
}


2043
static int
2044
x86UpdateCustom(virCPUDefPtr guest,
2045
                const virCPUDef *host)
2046 2047
{
    int ret = -1;
2048
    size_t i;
J
Jiri Denemark 已提交
2049
    virCPUx86MapPtr map;
J
Jiri Denemark 已提交
2050
    virCPUx86ModelPtr host_model = NULL;
2051

2052
    if (!(map = virCPUx86GetMap()) ||
2053
        !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)))
2054 2055 2056 2057
        goto cleanup;

    for (i = 0; i < guest->nfeatures; i++) {
        if (guest->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) {
2058
            virCPUx86FeaturePtr feature;
2059
            if (!(feature = x86FeatureFind(map, guest->features[i].name))) {
2060 2061 2062
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unknown CPU feature %s"),
                               guest->features[i].name);
2063 2064 2065
                goto cleanup;
            }

2066
            if (x86DataIsSubset(&host_model->data, &feature->data))
2067 2068 2069 2070 2071 2072 2073 2074
                guest->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
            else
                guest->features[i].policy = VIR_CPU_FEATURE_DISABLE;
        }
    }

    if (guest->match == VIR_CPU_MATCH_MINIMUM) {
        guest->match = VIR_CPU_MATCH_EXACT;
P
Peter Krempa 已提交
2075 2076
        if (x86ModelSubtractCPU(host_model, guest, map) ||
            x86DataToCPUFeatures(guest, VIR_CPU_FEATURE_REQUIRE,
2077
                                 &host_model->data, map))
2078 2079 2080 2081 2082
            goto cleanup;
    }

    ret = 0;

2083
 cleanup:
2084 2085 2086 2087
    x86ModelFree(host_model);
    return ret;
}

2088 2089 2090

static int
x86UpdateHostModel(virCPUDefPtr guest,
2091 2092
                   const virCPUDef *host,
                   bool passthrough)
2093
{
2094
    virCPUDefPtr oldguest = NULL;
J
Jiri Denemark 已提交
2095
    virCPUx86MapPtr map;
2096
    size_t i;
2097
    int ret = -1;
2098

2099 2100
    if (!(map = virCPUx86GetMap()))
        goto cleanup;
2101 2102 2103

    /* update the host model according to the desired configuration */
    if (!(oldguest = virCPUDefCopy(guest)))
2104
        goto cleanup;
2105 2106 2107

    virCPUDefFreeModel(guest);
    if (virCPUDefCopyModel(guest, host, true) < 0)
2108
        goto cleanup;
2109

2110 2111 2112 2113 2114 2115
    if (oldguest->vendor_id) {
        VIR_FREE(guest->vendor_id);
        if (VIR_STRDUP(guest->vendor_id, oldguest->vendor_id) < 0)
            goto cleanup;
    }

2116 2117 2118 2119
    /* Remove non-migratable features by default
     * Note: this only works as long as no CPU model contains non-migratable
     * features directly */
    for (i = 0; i < guest->nfeatures; i++) {
2120 2121 2122
        size_t j;
        for (j = 0; j < map->nblockers; j++) {
            if (STREQ(map->migrate_blockers[j]->name, guest->features[i].name)) {
J
Ján Tomko 已提交
2123
                VIR_FREE(guest->features[i].name);
2124
                VIR_DELETE_ELEMENT_INPLACE(guest->features, i, guest->nfeatures);
J
Ján Tomko 已提交
2125
            }
2126 2127
        }
    }
2128
    for (i = 0; !passthrough && i < oldguest->nfeatures; i++) {
2129 2130 2131
        if (virCPUDefUpdateFeature(guest,
                                   oldguest->features[i].name,
                                   oldguest->features[i].policy) < 0)
2132
            goto cleanup;
2133 2134
    }

2135 2136 2137 2138 2139
    ret = 0;

 cleanup:
    virCPUDefFree(oldguest);
    return ret;
2140 2141 2142
}


2143 2144
static int
x86Update(virCPUDefPtr guest,
2145
          const virCPUDef *host)
2146
{
2147
    switch ((virCPUMode) guest->mode) {
2148 2149 2150 2151
    case VIR_CPU_MODE_CUSTOM:
        return x86UpdateCustom(guest, host);

    case VIR_CPU_MODE_HOST_MODEL:
2152 2153
        guest->match = VIR_CPU_MATCH_EXACT;
        return x86UpdateHostModel(guest, host, false);
2154

2155
    case VIR_CPU_MODE_HOST_PASSTHROUGH:
2156
        guest->match = VIR_CPU_MATCH_MINIMUM;
2157
        return x86UpdateHostModel(guest, host, true);
2158 2159 2160 2161 2162

    case VIR_CPU_MODE_LAST:
        break;
    }

2163 2164
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Unexpected CPU mode: %d"), guest->mode);
2165 2166 2167
    return -1;
}

2168 2169 2170 2171

static int
x86HasFeature(const virCPUData *data,
              const char *name)
D
Daniel P. Berrange 已提交
2172
{
J
Jiri Denemark 已提交
2173
    virCPUx86MapPtr map;
2174
    virCPUx86FeaturePtr feature;
D
Daniel P. Berrange 已提交
2175 2176
    int ret = -1;

2177
    if (!(map = virCPUx86GetMap()))
D
Daniel P. Berrange 已提交
2178 2179 2180 2181 2182
        return -1;

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

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

2185
 cleanup:
D
Daniel P. Berrange 已提交
2186 2187
    return ret;
}
2188

2189 2190 2191
static int
x86GetModels(char ***models)
{
J
Jiri Denemark 已提交
2192
    virCPUx86MapPtr map;
2193
    size_t i;
2194 2195 2196 2197

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

2198 2199 2200
    if (models) {
        if (VIR_ALLOC_N(*models, map->nmodels + 1) < 0)
            goto error;
2201

2202 2203
        for (i = 0; i < map->nmodels; i++) {
            if (VIR_STRDUP((*models)[i], map->models[i]->name) < 0)
2204 2205
                goto error;
        }
2206 2207
    }

2208
    return map->nmodels;
2209 2210

 error:
2211 2212 2213 2214
    if (models) {
        virStringFreeList(*models);
        *models = NULL;
    }
2215 2216 2217
    return -1;
}

2218

J
Jiri Denemark 已提交
2219 2220 2221 2222 2223
struct cpuArchDriver cpuDriverX86 = {
    .name = "x86",
    .arch = archs,
    .narch = ARRAY_CARDINALITY(archs),
    .compare    = x86Compare,
2224
    .decode     = x86DecodeCPUData,
J
Jiri Denemark 已提交
2225
    .encode     = x86Encode,
2226
    .free       = x86FreeCPUData,
J
Jiri Denemark 已提交
2227 2228 2229 2230 2231
#if HAVE_CPUID
    .nodeData   = x86NodeData,
#else
    .nodeData   = NULL,
#endif
2232
    .guestData  = x86GuestData,
2233
    .baseline   = x86Baseline,
2234
    .update     = x86Update,
D
Daniel P. Berrange 已提交
2235
    .hasFeature = x86HasFeature,
2236 2237
    .dataFormat = x86CPUDataFormat,
    .dataParse  = x86CPUDataParse,
2238
    .getModels  = x86GetModels,
J
Jiri Denemark 已提交
2239
};