cpu_ppc64.c 22.8 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
J
Jiri Denemark 已提交
637
virCPUppc64Compare(virCPUDefPtr host,
638 639
                   virCPUDefPtr cpu,
                   bool failIncompatible)
L
Li Zhang 已提交
640
{
641 642
    virCPUCompareResult ret;
    char *message = NULL;
L
Li Zhang 已提交
643

J
Jiri Denemark 已提交
644 645 646 647 648 649 650 651 652 653 654
    if (!host || !host->model) {
        if (failIncompatible) {
            virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s",
                           _("unknown host CPU"));
        } else {
            VIR_WARN("unknown host CPU");
            ret = VIR_CPU_COMPARE_INCOMPATIBLE;
        }
        return -1;
    }

655 656 657 658 659 660 661 662 663
    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);
        }
664
    }
665 666 667
    VIR_FREE(message);

    return ret;
L
Li Zhang 已提交
668 669 670
}

static int
671 672 673 674 675 676
ppc64DriverDecode(virCPUDefPtr cpu,
                  const virCPUData *data,
                  const char **models,
                  unsigned int nmodels,
                  const char *preferred ATTRIBUTE_UNUSED,
                  unsigned int flags)
L
Li Zhang 已提交
677 678
{
    int ret = -1;
679 680
    struct ppc64_map *map;
    const struct ppc64_model *model;
L
Li Zhang 已提交
681

682 683
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1);

684
    if (!data || !(map = ppc64LoadMap()))
L
Li Zhang 已提交
685 686
        return -1;

687
    if (!(model = ppc64ModelFindPVR(map, data->data.ppc64.pvr[0].value))) {
688 689
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Cannot find CPU model with PVR 0x%08x"),
690
                       data->data.ppc64.pvr[0].value);
J
Jiri Denemark 已提交
691
        goto cleanup;
692
    }
L
Li Zhang 已提交
693

694
    if (!cpuModelIsAllowed(model->name, models, nmodels)) {
J
Jiri Denemark 已提交
695 696
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("CPU model %s is not supported by hypervisor"),
697
                       model->name);
J
Jiri Denemark 已提交
698
        goto cleanup;
L
Li Zhang 已提交
699 700
    }

701 702
    if (VIR_STRDUP(cpu->model, model->name) < 0 ||
        (model->vendor && VIR_STRDUP(cpu->vendor, model->vendor->name) < 0)) {
703 704
        goto cleanup;
    }
L
Li Zhang 已提交
705 706 707

    ret = 0;

708
 cleanup:
709
    ppc64MapFree(map);
L
Li Zhang 已提交
710 711 712 713 714

    return ret;
}

static void
715
ppc64DriverFree(virCPUDataPtr data)
L
Li Zhang 已提交
716
{
717
    if (!data)
L
Li Zhang 已提交
718 719
        return;

720
    ppc64DataClear(&data->data.ppc64);
L
Li Zhang 已提交
721 722 723
    VIR_FREE(data);
}

724
static virCPUDataPtr
725
ppc64DriverNodeData(virArch arch)
P
Prerna Saxena 已提交
726
{
727 728
    virCPUDataPtr nodeData;
    virCPUppc64Data *data;
P
Prerna Saxena 已提交
729

730 731
    if (VIR_ALLOC(nodeData) < 0)
        goto error;
P
Prerna Saxena 已提交
732

733
    data = &nodeData->data.ppc64;
734

735 736 737 738 739
    if (VIR_ALLOC_N(data->pvr, 1) < 0)
        goto error;

    data->len = 1;

740
#if defined(__powerpc__) || defined(__powerpc64__)
J
Jiri Denemark 已提交
741
    asm("mfpvr %0"
742
        : "=r" (data->pvr[0].value));
743
#endif
744
    data->pvr[0].mask = 0xfffffffful;
L
Li Zhang 已提交
745

746 747 748 749 750 751 752
    nodeData->arch = arch;

    return nodeData;

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

755
static virCPUCompareResult
756 757 758 759
ppc64DriverGuestData(virCPUDefPtr host,
                     virCPUDefPtr guest,
                     virCPUDataPtr *data,
                     char **message)
760
{
761
    return ppc64Compute(host, guest, data, message);
762 763
}

P
Prerna Saxena 已提交
764
static int
J
Jiri Denemark 已提交
765 766
virCPUppc64Update(virCPUDefPtr guest,
                  const virCPUDef *host ATTRIBUTE_UNUSED)
P
Prerna Saxena 已提交
767
{
J
Jiri Denemark 已提交
768 769 770 771 772 773 774 775 776
    /*
     * - 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)
777 778
        guest->match = VIR_CPU_MATCH_EXACT;

J
Jiri Denemark 已提交
779
    return 0;
P
Prerna Saxena 已提交
780
}
781

L
Li Zhang 已提交
782
static virCPUDefPtr
783 784 785 786 787
ppc64DriverBaseline(virCPUDefPtr *cpus,
                    unsigned int ncpus,
                    const char **models ATTRIBUTE_UNUSED,
                    unsigned int nmodels ATTRIBUTE_UNUSED,
                    unsigned int flags)
P
Prerna Saxena 已提交
788
{
789
    struct ppc64_map *map;
790 791
    const struct ppc64_model *model;
    const struct ppc64_vendor *vendor = NULL;
L
Li Zhang 已提交
792
    virCPUDefPtr cpu = NULL;
793
    size_t i;
J
Jiri Denemark 已提交
794

795 796
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL);
797

798
    if (!(map = ppc64LoadMap()))
J
Jiri Denemark 已提交
799
        goto error;
L
Li Zhang 已提交
800

801
    if (!(model = ppc64ModelFind(map, cpus[0]->model))) {
J
Jiri Denemark 已提交
802 803
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown CPU model %s"), cpus[0]->model);
L
Li Zhang 已提交
804 805 806
        goto error;
    }

J
Jiri Denemark 已提交
807
    for (i = 0; i < ncpus; i++) {
808
        const struct ppc64_vendor *vnd;
809

810 811 812 813 814 815 816 817 818 819 820
        /* 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 已提交
821 822 823 824 825
        if (STRNEQ(cpus[i]->model, model->name)) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("CPUs are incompatible"));
            goto error;
        }
L
Li Zhang 已提交
826

J
Jiri Denemark 已提交
827 828 829
        if (!cpus[i]->vendor)
            continue;

830
        if (!(vnd = ppc64VendorFind(map, cpus[i]->vendor))) {
J
Jiri Denemark 已提交
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853
            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 已提交
854 855
    }

J
Jiri Denemark 已提交
856
    if (VIR_ALLOC(cpu) < 0 ||
857
        VIR_STRDUP(cpu->model, model->name) < 0)
858
        goto error;
L
Li Zhang 已提交
859

860 861
    if (vendor && VIR_STRDUP(cpu->vendor, vendor->name) < 0)
        goto error;
J
Jiri Denemark 已提交
862 863 864

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

867
 cleanup:
868
    ppc64MapFree(map);
P
Prerna Saxena 已提交
869

L
Li Zhang 已提交
870
    return cpu;
J
Jiri Denemark 已提交
871

872
 error:
L
Li Zhang 已提交
873 874 875
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
P
Prerna Saxena 已提交
876 877
}

878
static int
J
Jiri Denemark 已提交
879
virCPUppc64DriverGetModels(char ***models)
880
{
881
    struct ppc64_map *map;
882 883
    size_t i;
    int ret = -1;
884

885
    if (!(map = ppc64LoadMap()))
886 887
        goto error;

888 889 890
    if (models) {
        if (VIR_ALLOC_N(*models, map->nmodels + 1) < 0)
            goto error;
891

892 893
        for (i = 0; i < map->nmodels; i++) {
            if (VIR_STRDUP((*models)[i], map->models[i]->name) < 0)
894 895
                goto error;
        }
896 897
    }

898 899
    ret = map->nmodels;

900
 cleanup:
901
    ppc64MapFree(map);
902
    return ret;
903 904

 error:
905 906 907 908
    if (models) {
        virStringFreeList(*models);
        *models = NULL;
    }
909 910 911
    goto cleanup;
}

912
struct cpuArchDriver cpuDriverPPC64 = {
913 914 915
    .name       = "ppc64",
    .arch       = archs,
    .narch      = ARRAY_CARDINALITY(archs),
J
Jiri Denemark 已提交
916
    .compare    = virCPUppc64Compare,
917
    .decode     = ppc64DriverDecode,
P
Prerna Saxena 已提交
918
    .encode     = NULL,
919 920 921 922
    .free       = ppc64DriverFree,
    .nodeData   = ppc64DriverNodeData,
    .guestData  = ppc64DriverGuestData,
    .baseline   = ppc64DriverBaseline,
J
Jiri Denemark 已提交
923
    .update     = virCPUppc64Update,
J
Jiri Denemark 已提交
924
    .getModels  = virCPUppc64DriverGetModels,
P
Prerna Saxena 已提交
925
};