cpu_ppc64.c 22.5 KB
Newer Older
P
Prerna Saxena 已提交
1
/*
2
 * cpu_ppc64.c: CPU driver for 64-bit PowerPC CPUs
P
Prerna Saxena 已提交
3
 *
4
 * Copyright (C) 2013 Red Hat, Inc.
L
Li Zhang 已提交
5
 * Copyright (C) IBM Corporation, 2010
P
Prerna Saxena 已提交
6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
P
Prerna Saxena 已提交
20 21 22 23
 *
 * Authors:
 *      Anton Blanchard <anton@au.ibm.com>
 *      Prerna Saxena <prerna@linux.vnet.ibm.com>
L
Li Zhang 已提交
24
 *      Li Zhang <zhlcindy@linux.vnet.ibm.com>
P
Prerna Saxena 已提交
25 26 27
 */

#include <config.h>
L
Li Zhang 已提交
28
#include <stdint.h>
P
Prerna Saxena 已提交
29

30
#include "virlog.h"
31
#include "viralloc.h"
P
Prerna Saxena 已提交
32
#include "cpu.h"
33
#include "virstring.h"
L
Li Zhang 已提交
34
#include "cpu_map.h"
35
#include "virbuffer.h"
P
Prerna Saxena 已提交
36 37 38

#define VIR_FROM_THIS VIR_FROM_CPU

39
VIR_LOG_INIT("cpu.cpu_ppc64");
40

41
static const virArch archs[] = { VIR_ARCH_PPC64, VIR_ARCH_PPC64LE };
P
Prerna Saxena 已提交
42

43
struct ppc64_vendor {
L
Li Zhang 已提交
44 45 46
    char *name;
};

47
struct ppc64_model {
L
Li Zhang 已提交
48
    char *name;
49
    const struct ppc64_vendor *vendor;
50
    virCPUppc64Data data;
L
Li Zhang 已提交
51 52
};

53
struct ppc64_map {
54 55
    size_t nvendors;
    struct ppc64_vendor **vendors;
56 57
    size_t nmodels;
    struct ppc64_model **models;
L
Li Zhang 已提交
58 59
};

60 61 62 63 64 65 66 67 68 69 70 71 72 73
/* Convert a legacy CPU definition by transforming
 * model names to generation names:
 *   POWER7_v2.1  => POWER7
 *   POWER7_v2.3  => POWER7
 *   POWER7+_v2.1 => POWER7
 *   POWER8_v1.0  => POWER8 */
static virCPUDefPtr
ppc64ConvertLegacyCPUDef(const virCPUDef *legacy)
{
    virCPUDefPtr cpu;

    if (!(cpu = virCPUDefCopy(legacy)))
        goto out;

74 75
    if (!cpu->model ||
        !(STREQ(cpu->model, "POWER7_v2.1") ||
76 77 78 79 80 81 82 83 84 85 86 87
          STREQ(cpu->model, "POWER7_v2.3") ||
          STREQ(cpu->model, "POWER7+_v2.1") ||
          STREQ(cpu->model, "POWER8_v1.0"))) {
        goto out;
    }

    cpu->model[strlen("POWERx")] = 0;

 out:
    return cpu;
}

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
/* Some hosts can run guests in compatibility mode, but not all
 * host CPUs support this and not all combinations are valid.
 * This function performs the necessary checks */
static virCPUCompareResult
ppc64CheckCompatibilityMode(const char *host_model,
                            const char *compat_mode)
{
    int host;
    int compat;
    char *tmp;
    virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;

    if (!compat_mode)
        return VIR_CPU_COMPARE_IDENTICAL;

    /* Valid host CPUs: POWER6, POWER7, POWER8 */
    if (!STRPREFIX(host_model, "POWER") ||
        !(tmp = (char *) host_model + strlen("POWER")) ||
        virStrToLong_i(tmp, NULL, 10, &host) < 0 ||
        host < 6 || host > 8) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s",
                       _("Host CPU does not support compatibility modes"));
        goto out;
    }

    /* Valid compatibility modes: power6, power7, power8 */
    if (!STRPREFIX(compat_mode, "power") ||
        !(tmp = (char *) compat_mode + strlen("power")) ||
        virStrToLong_i(tmp, NULL, 10, &compat) < 0 ||
        compat < 6 || compat > 8) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown compatibility mode %s"),
                       compat_mode);
        goto out;
    }

    /* Version check */
    if (compat > host)
        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
    else
        ret = VIR_CPU_COMPARE_IDENTICAL;

 out:
    return ret;
}

135
static void
136
ppc64DataClear(virCPUppc64Data *data)
137
{
138 139 140 141
    if (!data)
        return;

    VIR_FREE(data->pvr);
142 143
}

144 145
static int
ppc64DataCopy(virCPUppc64Data *dst, const virCPUppc64Data *src)
146
{
147
    size_t i;
148

149 150
    if (VIR_ALLOC_N(dst->pvr, src->len) < 0)
        return -1;
151

152
    dst->len = src->len;
153

154 155 156
    for (i = 0; i < src->len; i++) {
        dst->pvr[i].value = src->pvr[i].value;
        dst->pvr[i].mask = src->pvr[i].mask;
157
    }
158

159
    return 0;
160 161
}

162 163 164 165 166 167 168 169 170 171 172 173 174 175
static void
ppc64VendorFree(struct ppc64_vendor *vendor)
{
    if (!vendor)
        return;

    VIR_FREE(vendor->name);
    VIR_FREE(vendor);
}

static struct ppc64_vendor *
ppc64VendorFind(const struct ppc64_map *map,
                const char *name)
{
176
    size_t i;
177

178 179 180
    for (i = 0; i < map->nvendors; i++) {
        if (STREQ(map->vendors[i]->name, name))
            return map->vendors[i];
181 182 183 184
    }

    return NULL;
}
L
Li Zhang 已提交
185 186

static void
187
ppc64ModelFree(struct ppc64_model *model)
L
Li Zhang 已提交
188
{
189
    if (!model)
L
Li Zhang 已提交
190 191
        return;

192
    ppc64DataClear(&model->data);
L
Li Zhang 已提交
193 194 195 196
    VIR_FREE(model->name);
    VIR_FREE(model);
}

197 198 199 200 201
static struct ppc64_model *
ppc64ModelCopy(const struct ppc64_model *model)
{
    struct ppc64_model *copy;

202 203 204 205 206 207
    if (VIR_ALLOC(copy) < 0)
        goto error;

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

208
    if (ppc64DataCopy(&copy->data, &model->data) < 0)
209
        goto error;
210 211 212 213

    copy->vendor = model->vendor;

    return copy;
214 215 216 217

 error:
    ppc64ModelFree(copy);
    return NULL;
218 219
}

220 221 222
static struct ppc64_model *
ppc64ModelFind(const struct ppc64_map *map,
               const char *name)
L
Li Zhang 已提交
223
{
224
    size_t i;
L
Li Zhang 已提交
225

226 227 228
    for (i = 0; i < map->nmodels; i++) {
        if (STREQ(map->models[i]->name, name))
            return map->models[i];
L
Li Zhang 已提交
229 230 231 232 233
    }

    return NULL;
}

234 235 236
static struct ppc64_model *
ppc64ModelFindPVR(const struct ppc64_map *map,
                  uint32_t pvr)
237
{
238
    size_t i;
239
    size_t j;
240

241 242
    for (i = 0; i < map->nmodels; i++) {
        struct ppc64_model *model = map->models[i];
243 244
        for (j = 0; j < model->data.len; j++) {
            if ((pvr & model->data.pvr[j].mask) == model->data.pvr[j].value)
245 246
                return model;
        }
247 248 249 250 251
    }

    return NULL;
}

252
static struct ppc64_model *
253 254
ppc64ModelFromCPU(const virCPUDef *cpu,
                  const struct ppc64_map *map)
255
{
256
    struct ppc64_model *model;
257

258 259 260
    if (!(model = ppc64ModelFind(map, cpu->model))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown CPU model %s"), cpu->model);
261 262 263
        return NULL;
    }

264
    return ppc64ModelCopy(model);
L
Li Zhang 已提交
265 266 267
}

static void
268
ppc64MapFree(struct ppc64_map *map)
L
Li Zhang 已提交
269
{
270 271
    size_t i;

272
    if (!map)
L
Li Zhang 已提交
273 274
        return;

275 276 277
    for (i = 0; i < map->nmodels; i++)
        ppc64ModelFree(map->models[i]);
    VIR_FREE(map->models);
278

279 280 281
    for (i = 0; i < map->nvendors; i++)
        ppc64VendorFree(map->vendors[i]);
    VIR_FREE(map->vendors);
282

283
    VIR_FREE(map);
284 285
}

J
Jiri Denemark 已提交
286 287 288
static struct ppc64_vendor *
ppc64VendorParse(xmlXPathContextPtr ctxt,
                 struct ppc64_map *map)
L
Li Zhang 已提交
289
{
290
    struct ppc64_vendor *vendor;
L
Li Zhang 已提交
291

292
    if (VIR_ALLOC(vendor) < 0)
J
Jiri Denemark 已提交
293
        return NULL;
L
Li Zhang 已提交
294 295 296 297 298

    vendor->name = virXPathString("string(@name)", ctxt);
    if (!vendor->name) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing CPU vendor name"));
J
Jiri Denemark 已提交
299
        goto error;
L
Li Zhang 已提交
300 301
    }

302
    if (ppc64VendorFind(map, vendor->name)) {
L
Li Zhang 已提交
303 304
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU vendor %s already defined"), vendor->name);
J
Jiri Denemark 已提交
305
        goto error;
L
Li Zhang 已提交
306 307
    }

J
Jiri Denemark 已提交
308
    return vendor;
L
Li Zhang 已提交
309

J
Jiri Denemark 已提交
310
 error:
311
    ppc64VendorFree(vendor);
J
Jiri Denemark 已提交
312
    return NULL;
L
Li Zhang 已提交
313 314
}

J
Jiri Denemark 已提交
315

L
Li Zhang 已提交
316
static int
J
Jiri Denemark 已提交
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
ppc64VendorsLoad(struct ppc64_map *map,
                 xmlXPathContextPtr ctxt,
                 xmlNodePtr *nodes,
                 int n)
{
    struct ppc64_vendor *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 = ppc64VendorParse(ctxt, map)))
            return -1;
        map->vendors[map->nvendors++] = vendor;
    }

    return 0;
}


static struct ppc64_model *
ppc64ModelParse(xmlXPathContextPtr ctxt,
                struct ppc64_map *map)
L
Li Zhang 已提交
342
{
343
    struct ppc64_model *model;
344
    xmlNodePtr *nodes = NULL;
L
Li Zhang 已提交
345
    char *vendor = NULL;
346
    unsigned long pvr;
347 348 349
    size_t i;
    int n;

350
    if (VIR_ALLOC(model) < 0)
J
Jiri Denemark 已提交
351
        goto error;
L
Li Zhang 已提交
352 353

    model->name = virXPathString("string(@name)", ctxt);
354
    if (!model->name) {
L
Li Zhang 已提交
355 356
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing CPU model name"));
J
Jiri Denemark 已提交
357
        goto error;
L
Li Zhang 已提交
358 359
    }

360
    if (ppc64ModelFind(map, model->name)) {
361 362
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU model %s already defined"), model->name);
J
Jiri Denemark 已提交
363
        goto error;
364
    }
L
Li Zhang 已提交
365 366 367 368 369 370 371

    if (virXPathBoolean("boolean(./vendor)", ctxt)) {
        vendor = virXPathString("string(./vendor/@name)", ctxt);
        if (!vendor) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid vendor element in CPU model %s"),
                           model->name);
J
Jiri Denemark 已提交
372
            goto error;
L
Li Zhang 已提交
373 374
        }

375
        if (!(model->vendor = ppc64VendorFind(map, vendor))) {
L
Li Zhang 已提交
376 377 378
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unknown vendor %s referenced by CPU model %s"),
                           vendor, model->name);
J
Jiri Denemark 已提交
379
            goto error;
L
Li Zhang 已提交
380 381 382
        }
    }

383
    if ((n = virXPathNodeSet("./pvr", ctxt, &nodes)) <= 0) {
384
        virReportError(VIR_ERR_INTERNAL_ERROR,
385
                       _("Missing PVR information for CPU model %s"),
386
                       model->name);
J
Jiri Denemark 已提交
387
        goto error;
388
    }
389

390
    if (VIR_ALLOC_N(model->data.pvr, n) < 0)
J
Jiri Denemark 已提交
391
        goto error;
392

393
    model->data.len = n;
394 395 396 397 398 399 400 401

    for (i = 0; i < n; i++) {
        ctxt->node = nodes[i];

        if (virXPathULongHex("string(./@value)", ctxt, &pvr) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing or invalid PVR value in CPU model %s"),
                           model->name);
J
Jiri Denemark 已提交
402
            goto error;
403
        }
404
        model->data.pvr[i].value = pvr;
405 406 407 408 409

        if (virXPathULongHex("string(./@mask)", ctxt, &pvr) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing or invalid PVR mask in CPU model %s"),
                           model->name);
J
Jiri Denemark 已提交
410
            goto error;
411
        }
412
        model->data.pvr[i].mask = pvr;
413
    }
414

415
 cleanup:
L
Li Zhang 已提交
416
    VIR_FREE(vendor);
417
    VIR_FREE(nodes);
J
Jiri Denemark 已提交
418
    return model;
L
Li Zhang 已提交
419

J
Jiri Denemark 已提交
420
 error:
421
    ppc64ModelFree(model);
J
Jiri Denemark 已提交
422
    model = NULL;
423
    goto cleanup;
L
Li Zhang 已提交
424 425
}

J
Jiri Denemark 已提交
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449

static int
ppc64ModelsLoad(struct ppc64_map *map,
                xmlXPathContextPtr ctxt,
                xmlNodePtr *nodes,
                int n)
{
    struct ppc64_model *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 = ppc64ModelParse(ctxt, map)))
            return -1;
        map->models[map->nmodels++] = model;
    }

    return 0;
}


L
Li Zhang 已提交
450
static int
451 452
ppc64MapLoadCallback(cpuMapElement element,
                     xmlXPathContextPtr ctxt,
J
Jiri Denemark 已提交
453 454
                     xmlNodePtr *nodes,
                     int n,
455
                     void *data)
L
Li Zhang 已提交
456
{
457
    struct ppc64_map *map = data;
L
Li Zhang 已提交
458 459 460

    switch (element) {
    case CPU_MAP_ELEMENT_VENDOR:
J
Jiri Denemark 已提交
461
        return ppc64VendorsLoad(map, ctxt, nodes, n);
L
Li Zhang 已提交
462
    case CPU_MAP_ELEMENT_MODEL:
J
Jiri Denemark 已提交
463
        return ppc64ModelsLoad(map, ctxt, nodes, n);
464 465
    case CPU_MAP_ELEMENT_FEATURE:
    case CPU_MAP_ELEMENT_LAST:
L
Li Zhang 已提交
466 467 468 469 470 471
        break;
    }

    return 0;
}

472 473
static struct ppc64_map *
ppc64LoadMap(void)
L
Li Zhang 已提交
474
{
475
    struct ppc64_map *map;
L
Li Zhang 已提交
476

477
    if (VIR_ALLOC(map) < 0)
478
        goto error;
L
Li Zhang 已提交
479

480
    if (cpuMapLoad("ppc64", ppc64MapLoadCallback, map) < 0)
L
Li Zhang 已提交
481 482 483 484
        goto error;

    return map;

485
 error:
486
    ppc64MapFree(map);
L
Li Zhang 已提交
487 488 489
    return NULL;
}

490
static virCPUDataPtr
491
ppc64MakeCPUData(virArch arch,
492
                 virCPUppc64Data *data)
493 494 495 496 497 498 499
{
    virCPUDataPtr cpuData;

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

    cpuData->arch = arch;
500

501
    if (ppc64DataCopy(&cpuData->data.ppc64, data) < 0)
502
        VIR_FREE(cpuData);
503 504 505 506 507

    return cpuData;
}

static virCPUCompareResult
508
ppc64Compute(virCPUDefPtr host,
509
             const virCPUDef *other,
510 511
             virCPUDataPtr *guestData,
             char **message)
512
{
513 514 515
    struct ppc64_map *map = NULL;
    struct ppc64_model *host_model = NULL;
    struct ppc64_model *guest_model = NULL;
516
    virCPUDefPtr cpu = NULL;
517
    virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;
518 519 520
    virArch arch;
    size_t i;

521 522 523 524
    /* Ensure existing configurations are handled correctly */
    if (!(cpu = ppc64ConvertLegacyCPUDef(other)))
        goto cleanup;

525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
    if (cpu->arch != VIR_ARCH_NONE) {
        bool found = false;

        for (i = 0; i < ARRAY_CARDINALITY(archs); i++) {
            if (archs[i] == cpu->arch) {
                found = true;
                break;
            }
        }

        if (!found) {
            VIR_DEBUG("CPU arch %s does not match host arch",
                      virArchToString(cpu->arch));
            if (message &&
                virAsprintf(message,
                            _("CPU arch %s does not match host arch"),
                            virArchToString(cpu->arch)) < 0)
542 543 544 545
                goto cleanup;

            ret = VIR_CPU_COMPARE_INCOMPATIBLE;
            goto cleanup;
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
        }
        arch = cpu->arch;
    } else {
        arch = host->arch;
    }

    if (cpu->vendor &&
        (!host->vendor || STRNEQ(cpu->vendor, host->vendor))) {
        VIR_DEBUG("host CPU vendor does not match required CPU vendor %s",
                  cpu->vendor);
        if (message &&
            virAsprintf(message,
                        _("host CPU vendor does not match required "
                        "CPU vendor %s"),
                        cpu->vendor) < 0)
561 562 563 564
            goto cleanup;

        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
        goto cleanup;
565 566
    }

567 568 569 570 571
    if (!(map = ppc64LoadMap()))
        goto cleanup;

    /* Host CPU information */
    if (!(host_model = ppc64ModelFromCPU(host, map)))
572
        goto cleanup;
573

574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
    if (cpu->type == VIR_CPU_TYPE_GUEST) {
        /* Guest CPU information */
        virCPUCompareResult tmp;
        switch (cpu->mode) {
        case VIR_CPU_MODE_HOST_MODEL:
            /* host-model only:
             * we need to take compatibility modes into account */
            tmp = ppc64CheckCompatibilityMode(host->model, cpu->model);
            if (tmp != VIR_CPU_COMPARE_IDENTICAL) {
                ret = tmp;
                goto cleanup;
            }
            /* fallthrough */

        case VIR_CPU_MODE_HOST_PASSTHROUGH:
            /* host-model and host-passthrough:
             * the guest CPU is the same as the host */
591
            guest_model = ppc64ModelCopy(host_model);
592 593 594 595 596
            break;

        case VIR_CPU_MODE_CUSTOM:
            /* custom:
             * look up guest CPU information */
597
            guest_model = ppc64ModelFromCPU(cpu, map);
598 599 600 601
            break;
        }
    } else {
        /* Other host CPU information */
602
        guest_model = ppc64ModelFromCPU(cpu, map);
603 604
    }

605 606 607
    if (!guest_model)
        goto cleanup;

608
    if (STRNEQ(guest_model->name, host_model->name)) {
609 610 611 612 613 614 615
        VIR_DEBUG("host CPU model does not match required CPU model %s",
                  guest_model->name);
        if (message &&
            virAsprintf(message,
                        _("host CPU model does not match required "
                        "CPU model %s"),
                        guest_model->name) < 0)
616
            goto cleanup;
617

618 619 620 621 622
        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
        goto cleanup;
    }

    if (guestData)
623
        if (!(*guestData = ppc64MakeCPUData(arch, &guest_model->data)))
624
            goto cleanup;
625 626 627

    ret = VIR_CPU_COMPARE_IDENTICAL;

628
 cleanup:
629
    virCPUDefFree(cpu);
630 631 632
    ppc64MapFree(map);
    ppc64ModelFree(host_model);
    ppc64ModelFree(guest_model);
633 634 635
    return ret;
}

L
Li Zhang 已提交
636
static virCPUCompareResult
637 638 639
ppc64DriverCompare(virCPUDefPtr host,
                   virCPUDefPtr cpu,
                   bool failIncompatible)
L
Li Zhang 已提交
640
{
641 642
    virCPUCompareResult ret;
    char *message = NULL;
L
Li Zhang 已提交
643

644 645 646 647 648 649 650 651 652
    ret = ppc64Compute(host, cpu, NULL, &message);

    if (failIncompatible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) {
        ret = VIR_CPU_COMPARE_ERROR;
        if (message) {
            virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", message);
        } else {
            virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL);
        }
653
    }
654 655 656
    VIR_FREE(message);

    return ret;
L
Li Zhang 已提交
657 658 659
}

static int
660 661 662 663 664 665
ppc64DriverDecode(virCPUDefPtr cpu,
                  const virCPUData *data,
                  const char **models,
                  unsigned int nmodels,
                  const char *preferred ATTRIBUTE_UNUSED,
                  unsigned int flags)
L
Li Zhang 已提交
666 667
{
    int ret = -1;
668 669
    struct ppc64_map *map;
    const struct ppc64_model *model;
L
Li Zhang 已提交
670

671 672
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1);

673
    if (!data || !(map = ppc64LoadMap()))
L
Li Zhang 已提交
674 675
        return -1;

676
    if (!(model = ppc64ModelFindPVR(map, data->data.ppc64.pvr[0].value))) {
677 678
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Cannot find CPU model with PVR 0x%08x"),
679
                       data->data.ppc64.pvr[0].value);
J
Jiri Denemark 已提交
680
        goto cleanup;
681
    }
L
Li Zhang 已提交
682

683
    if (!cpuModelIsAllowed(model->name, models, nmodels)) {
J
Jiri Denemark 已提交
684 685
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("CPU model %s is not supported by hypervisor"),
686
                       model->name);
J
Jiri Denemark 已提交
687
        goto cleanup;
L
Li Zhang 已提交
688 689
    }

690 691
    if (VIR_STRDUP(cpu->model, model->name) < 0 ||
        (model->vendor && VIR_STRDUP(cpu->vendor, model->vendor->name) < 0)) {
692 693
        goto cleanup;
    }
L
Li Zhang 已提交
694 695 696

    ret = 0;

697
 cleanup:
698
    ppc64MapFree(map);
L
Li Zhang 已提交
699 700 701 702 703

    return ret;
}

static void
704
ppc64DriverFree(virCPUDataPtr data)
L
Li Zhang 已提交
705
{
706
    if (!data)
L
Li Zhang 已提交
707 708
        return;

709
    ppc64DataClear(&data->data.ppc64);
L
Li Zhang 已提交
710 711 712
    VIR_FREE(data);
}

713
static virCPUDataPtr
714
ppc64DriverNodeData(virArch arch)
P
Prerna Saxena 已提交
715
{
716 717
    virCPUDataPtr nodeData;
    virCPUppc64Data *data;
P
Prerna Saxena 已提交
718

719 720
    if (VIR_ALLOC(nodeData) < 0)
        goto error;
P
Prerna Saxena 已提交
721

722
    data = &nodeData->data.ppc64;
723

724 725 726 727 728
    if (VIR_ALLOC_N(data->pvr, 1) < 0)
        goto error;

    data->len = 1;

729
#if defined(__powerpc__) || defined(__powerpc64__)
J
Jiri Denemark 已提交
730
    asm("mfpvr %0"
731
        : "=r" (data->pvr[0].value));
732
#endif
733
    data->pvr[0].mask = 0xfffffffful;
L
Li Zhang 已提交
734

735 736 737 738 739 740 741
    nodeData->arch = arch;

    return nodeData;

 error:
    ppc64DriverFree(nodeData);
    return NULL;
P
Prerna Saxena 已提交
742 743
}

744
static virCPUCompareResult
745 746 747 748
ppc64DriverGuestData(virCPUDefPtr host,
                     virCPUDefPtr guest,
                     virCPUDataPtr *data,
                     char **message)
749
{
750
    return ppc64Compute(host, guest, data, message);
751 752
}

P
Prerna Saxena 已提交
753
static int
J
Jiri Denemark 已提交
754 755
virCPUppc64Update(virCPUDefPtr guest,
                  const virCPUDef *host ATTRIBUTE_UNUSED)
P
Prerna Saxena 已提交
756
{
J
Jiri Denemark 已提交
757 758 759 760 761 762 763 764 765
    /*
     * - host-passthrough doesn't even get here
     * - host-model is used for host CPU running in a compatibility mode and
     *   it needs to remain unchanged
     * - custom doesn't support any optional features, there's nothing to
     *   update
     */

    if (guest->mode == VIR_CPU_MODE_CUSTOM)
766 767
        guest->match = VIR_CPU_MATCH_EXACT;

J
Jiri Denemark 已提交
768
    return 0;
P
Prerna Saxena 已提交
769
}
770

L
Li Zhang 已提交
771
static virCPUDefPtr
772 773 774 775 776
ppc64DriverBaseline(virCPUDefPtr *cpus,
                    unsigned int ncpus,
                    const char **models ATTRIBUTE_UNUSED,
                    unsigned int nmodels ATTRIBUTE_UNUSED,
                    unsigned int flags)
P
Prerna Saxena 已提交
777
{
778
    struct ppc64_map *map;
779 780
    const struct ppc64_model *model;
    const struct ppc64_vendor *vendor = NULL;
L
Li Zhang 已提交
781
    virCPUDefPtr cpu = NULL;
782
    size_t i;
J
Jiri Denemark 已提交
783

784 785
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL);
786

787
    if (!(map = ppc64LoadMap()))
J
Jiri Denemark 已提交
788
        goto error;
L
Li Zhang 已提交
789

790
    if (!(model = ppc64ModelFind(map, cpus[0]->model))) {
J
Jiri Denemark 已提交
791 792
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown CPU model %s"), cpus[0]->model);
L
Li Zhang 已提交
793 794 795
        goto error;
    }

J
Jiri Denemark 已提交
796
    for (i = 0; i < ncpus; i++) {
797
        const struct ppc64_vendor *vnd;
798

799 800 801 802 803 804 805 806 807 808 809
        /* Hosts running old (<= 1.2.18) versions of libvirt will report
         * strings like 'power7+' or 'power8e' instead of proper CPU model
         * names in the capabilities XML; moreover, they lack information
         * about some proper CPU models like 'POWER8'.
         * This implies two things:
         *   1) baseline among such hosts never worked
         *   2) while a few models, eg. 'POWER8_v1.0', could work on both
         *      old and new versions of libvirt, the information we have
         *      here is not enough to pick such a model
         * Hence we just compare models by name to decide whether or not
         * two hosts are compatible */
J
Jiri Denemark 已提交
810 811 812 813 814
        if (STRNEQ(cpus[i]->model, model->name)) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("CPUs are incompatible"));
            goto error;
        }
L
Li Zhang 已提交
815

J
Jiri Denemark 已提交
816 817 818
        if (!cpus[i]->vendor)
            continue;

819
        if (!(vnd = ppc64VendorFind(map, cpus[i]->vendor))) {
J
Jiri Denemark 已提交
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("Unknown CPU vendor %s"), cpus[i]->vendor);
            goto error;
        }

        if (model->vendor) {
            if (model->vendor != vnd) {
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("CPU vendor %s of model %s differs from "
                                 "vendor %s"),
                               model->vendor->name, model->name,
                               vnd->name);
                goto error;
            }
        } else if (vendor) {
            if (vendor != vnd) {
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("CPU vendors do not match"));
                goto error;
            }
        } else {
            vendor = vnd;
        }
L
Li Zhang 已提交
843 844
    }

J
Jiri Denemark 已提交
845
    if (VIR_ALLOC(cpu) < 0 ||
846
        VIR_STRDUP(cpu->model, model->name) < 0)
847
        goto error;
L
Li Zhang 已提交
848

849 850
    if (vendor && VIR_STRDUP(cpu->vendor, vendor->name) < 0)
        goto error;
J
Jiri Denemark 已提交
851 852 853

    cpu->type = VIR_CPU_TYPE_GUEST;
    cpu->match = VIR_CPU_MATCH_EXACT;
854
    cpu->fallback = VIR_CPU_FALLBACK_FORBID;
L
Li Zhang 已提交
855

856
 cleanup:
857
    ppc64MapFree(map);
P
Prerna Saxena 已提交
858

L
Li Zhang 已提交
859
    return cpu;
J
Jiri Denemark 已提交
860

861
 error:
L
Li Zhang 已提交
862 863 864
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
P
Prerna Saxena 已提交
865 866
}

867
static int
868
ppc64DriverGetModels(char ***models)
869
{
870
    struct ppc64_map *map;
871 872
    size_t i;
    int ret = -1;
873

874
    if (!(map = ppc64LoadMap()))
875 876
        goto error;

877 878 879
    if (models) {
        if (VIR_ALLOC_N(*models, map->nmodels + 1) < 0)
            goto error;
880

881 882
        for (i = 0; i < map->nmodels; i++) {
            if (VIR_STRDUP((*models)[i], map->models[i]->name) < 0)
883 884
                goto error;
        }
885 886
    }

887 888
    ret = map->nmodels;

889
 cleanup:
890
    ppc64MapFree(map);
891
    return ret;
892 893

 error:
894 895 896 897
    if (models) {
        virStringFreeList(*models);
        *models = NULL;
    }
898 899 900
    goto cleanup;
}

901
struct cpuArchDriver cpuDriverPPC64 = {
902 903 904
    .name       = "ppc64",
    .arch       = archs,
    .narch      = ARRAY_CARDINALITY(archs),
905 906
    .compare    = ppc64DriverCompare,
    .decode     = ppc64DriverDecode,
P
Prerna Saxena 已提交
907
    .encode     = NULL,
908 909 910 911
    .free       = ppc64DriverFree,
    .nodeData   = ppc64DriverNodeData,
    .guestData  = ppc64DriverGuestData,
    .baseline   = ppc64DriverBaseline,
J
Jiri Denemark 已提交
912
    .update     = virCPUppc64Update,
913
    .getModels  = ppc64DriverGetModels,
P
Prerna Saxena 已提交
914
};