cpu_powerpc.c 15.4 KB
Newer Older
P
Prerna Saxena 已提交
1
/*
L
Li Zhang 已提交
2
 * cpu_powerpc.c: CPU driver for 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 40
VIR_LOG_INIT("cpu.cpu_powerpc");

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

L
Li Zhang 已提交
43 44 45 46 47 48 49 50
struct ppc_vendor {
    char *name;
    struct ppc_vendor *next;
};

struct ppc_model {
    char *name;
    const struct ppc_vendor *vendor;
51
    struct cpuPPCData data;
L
Li Zhang 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
    struct ppc_model *next;
};

struct ppc_map {
    struct ppc_vendor *vendors;
    struct ppc_model *models;
};


static void
ppcModelFree(struct ppc_model *model)
{
    if (model == NULL)
        return;

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

static struct ppc_model *
ppcModelFind(const struct ppc_map *map,
             const char *name)
{
    struct ppc_model *model;

    model = map->models;
    while (model != NULL) {
        if (STREQ(model->name, name))
            return model;

        model = model->next;
    }

    return NULL;
}

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
static struct ppc_model *
ppcModelFindPVR(const struct ppc_map *map,
                uint32_t pvr)
{
    struct ppc_model *model;

    model = map->models;
    while (model != NULL) {
        if (model->data.pvr == pvr)
            return model;

        model = model->next;
    }

    return NULL;
}

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
static struct ppc_model *
ppcModelCopy(const struct ppc_model *model)
{
    struct ppc_model *copy;

    if (VIR_ALLOC(copy) < 0 ||
        VIR_STRDUP(copy->name, model->name) < 0) {
        ppcModelFree(copy);
        return NULL;
    }

    copy->data.pvr = model->data.pvr;
    copy->vendor = model->vendor;

    return copy;
}

L
Li Zhang 已提交
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
static struct ppc_vendor *
ppcVendorFind(const struct ppc_map *map,
              const char *name)
{
    struct ppc_vendor *vendor;

    vendor = map->vendors;
    while (vendor) {
        if (STREQ(vendor->name, name))
            return vendor;

        vendor = vendor->next;
    }

    return NULL;
}

static void
ppcVendorFree(struct ppc_vendor *vendor)
{
    if (!vendor)
        return;

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

149
static struct ppc_model *
150
ppcModelFromCPU(const virCPUDef *cpu,
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
                const struct ppc_map *map)
{
    struct ppc_model *model = NULL;

    if ((model = ppcModelFind(map, cpu->model)) == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown CPU model %s"), cpu->model);
        goto error;
    }

    if ((model = ppcModelCopy(model)) == NULL)
        goto error;

    return model;

166
 error:
167 168 169 170 171
    ppcModelFree(model);
    return NULL;
}


L
Li Zhang 已提交
172 173 174 175 176 177
static int
ppcVendorLoad(xmlXPathContextPtr ctxt,
              struct ppc_map *map)
{
    struct ppc_vendor *vendor = NULL;

178
    if (VIR_ALLOC(vendor) < 0)
179
        return -1;
L
Li Zhang 已提交
180 181 182 183 184 185 186 187 188 189 190 191 192 193

    vendor->name = virXPathString("string(@name)", ctxt);
    if (!vendor->name) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing CPU vendor name"));
        goto ignore;
    }

    if (ppcVendorFind(map, vendor->name)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU vendor %s already defined"), vendor->name);
        goto ignore;
    }

194
    if (!map->vendors) {
L
Li Zhang 已提交
195
        map->vendors = vendor;
196
    } else {
L
Li Zhang 已提交
197 198 199 200
        vendor->next = map->vendors;
        map->vendors = vendor;
    }

201
 cleanup:
202
    return 0;
L
Li Zhang 已提交
203

204
 ignore:
L
Li Zhang 已提交
205
    ppcVendorFree(vendor);
206
    goto cleanup;
L
Li Zhang 已提交
207 208 209 210 211 212 213 214
}

static int
ppcModelLoad(xmlXPathContextPtr ctxt,
             struct ppc_map *map)
{
    struct ppc_model *model;
    char *vendor = NULL;
215
    unsigned long pvr;
L
Li Zhang 已提交
216

217
    if (VIR_ALLOC(model) < 0)
218
        return -1;
L
Li Zhang 已提交
219 220

    model->name = virXPathString("string(@name)", ctxt);
221
    if (!model->name) {
L
Li Zhang 已提交
222 223 224 225 226
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Missing CPU model name"));
        goto ignore;
    }

227 228 229 230 231
    if (ppcModelFind(map, model->name)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("CPU model %s already defined"), model->name);
        goto ignore;
    }
L
Li Zhang 已提交
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

    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);
            goto ignore;
        }

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

250 251 252 253 254 255 256 257 258 259
    if (!virXPathBoolean("boolean(./pvr)", ctxt) ||
        virXPathULongHex("string(./pvr/@value)", ctxt, &pvr) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Missing or invalid PVR value in CPU model %s"),
                       model->name);
        goto ignore;
    }
    model->data.pvr = pvr;

    if (map->models == NULL) {
L
Li Zhang 已提交
260
        map->models = model;
261
    } else {
L
Li Zhang 已提交
262 263 264 265
        model->next = map->models;
        map->models = model;
    }

266
 cleanup:
L
Li Zhang 已提交
267
    VIR_FREE(vendor);
268
    return 0;
L
Li Zhang 已提交
269

270
 ignore:
L
Li Zhang 已提交
271
    ppcModelFree(model);
272
    goto cleanup;
L
Li Zhang 已提交
273 274 275
}

static int
276
ppcMapLoadCallback(cpuMapElement element,
L
Li Zhang 已提交
277 278 279 280 281 282 283 284 285 286
                   xmlXPathContextPtr ctxt,
                   void *data)
{
    struct ppc_map *map = data;

    switch (element) {
    case CPU_MAP_ELEMENT_VENDOR:
        return ppcVendorLoad(ctxt, map);
    case CPU_MAP_ELEMENT_MODEL:
        return ppcModelLoad(ctxt, map);
287 288
    case CPU_MAP_ELEMENT_FEATURE:
    case CPU_MAP_ELEMENT_LAST:
L
Li Zhang 已提交
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
        break;
    }

    return 0;
}

static void
ppcMapFree(struct ppc_map *map)
{
    if (map == NULL)
        return;

    while (map->models != NULL) {
        struct ppc_model *model = map->models;
        map->models = model->next;
        ppcModelFree(model);
    }

    while (map->vendors != NULL) {
        struct ppc_vendor *vendor = map->vendors;
        map->vendors = vendor->next;
        ppcVendorFree(vendor);
    }

    VIR_FREE(map);
}

static struct ppc_map *
ppcLoadMap(void)
{
    struct ppc_map *map;

321
    if (VIR_ALLOC(map) < 0)
L
Li Zhang 已提交
322 323 324 325 326 327 328
        return NULL;

    if (cpuMapLoad("ppc64", ppcMapLoadCallback, map) < 0)
        goto error;

    return map;

329
 error:
L
Li Zhang 已提交
330 331 332 333
    ppcMapFree(map);
    return NULL;
}

334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
static virCPUDataPtr
ppcMakeCPUData(virArch arch, struct cpuPPCData *data)
{
    virCPUDataPtr cpuData;

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

    cpuData->arch = arch;
    cpuData->data.ppc = *data;
    data = NULL;

    return cpuData;
}

static virCPUCompareResult
ppcCompute(virCPUDefPtr host,
351
           const virCPUDef *cpu,
352 353
           virCPUDataPtr *guestData,
           char **message)
354 355 356 357 358 359

{
    struct ppc_map *map = NULL;
    struct ppc_model *host_model = NULL;
    struct ppc_model *guest_model = NULL;

360
    virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
    virArch arch;
    size_t i;

    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)
381 382 383 384
                goto cleanup;

            ret = VIR_CPU_COMPARE_INCOMPATIBLE;
            goto cleanup;
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
        }
        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)
400 401 402 403
            goto cleanup;

        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
        goto cleanup;
404 405 406 407 408
    }

    if (!(map = ppcLoadMap()) ||
        !(host_model = ppcModelFromCPU(host, map)) ||
        !(guest_model = ppcModelFromCPU(cpu, map)))
409
        goto cleanup;
410 411 412 413 414 415 416 417 418 419 420 421

    if (guestData != NULL) {
        if (cpu->type == VIR_CPU_TYPE_GUEST &&
            cpu->match == VIR_CPU_MATCH_STRICT &&
            STRNEQ(guest_model->name, host_model->name)) {
            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)
422 423 424 425
                goto cleanup;

            ret = VIR_CPU_COMPARE_INCOMPATIBLE;
            goto cleanup;
426 427 428
        }

        if (!(*guestData = ppcMakeCPUData(arch, &guest_model->data)))
429
            goto cleanup;
430 431 432 433
    }

    ret = VIR_CPU_COMPARE_IDENTICAL;

434
 cleanup:
435 436 437 438 439 440
    ppcMapFree(map);
    ppcModelFree(host_model);
    ppcModelFree(guest_model);
    return ret;
}

L
Li Zhang 已提交
441
static virCPUCompareResult
442
ppcCompare(virCPUDefPtr host,
443 444
           virCPUDefPtr cpu,
           bool failIncompatible)
L
Li Zhang 已提交
445
{
446 447 448
    if ((cpu->arch == VIR_ARCH_NONE || host->arch == cpu->arch) &&
        STREQ(host->model, cpu->model))
        return VIR_CPU_COMPARE_IDENTICAL;
L
Li Zhang 已提交
449

450 451 452 453 454 455
    if (failIncompatible) {
        virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL);
        return VIR_CPU_COMPARE_ERROR;
    } else {
        return VIR_CPU_COMPARE_INCOMPATIBLE;
    }
L
Li Zhang 已提交
456 457 458
}

static int
J
Jiri Denemark 已提交
459
ppcDecode(virCPUDefPtr cpu,
460
          const virCPUData *data,
L
Li Zhang 已提交
461 462
          const char **models,
          unsigned int nmodels,
463 464
          const char *preferred ATTRIBUTE_UNUSED,
          unsigned int flags)
L
Li Zhang 已提交
465 466 467
{
    int ret = -1;
    struct ppc_map *map;
468
    const struct ppc_model *model;
L
Li Zhang 已提交
469

470 471
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1);

L
Li Zhang 已提交
472 473 474
    if (data == NULL || (map = ppcLoadMap()) == NULL)
        return -1;

J
Jiri Denemark 已提交
475
    if (!(model = ppcModelFindPVR(map, data->data.ppc.pvr))) {
476 477
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Cannot find CPU model with PVR 0x%08x"),
J
Jiri Denemark 已提交
478
                       data->data.ppc.pvr);
J
Jiri Denemark 已提交
479
        goto cleanup;
480
    }
L
Li Zhang 已提交
481

482
    if (!cpuModelIsAllowed(model->name, models, nmodels)) {
J
Jiri Denemark 已提交
483 484
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("CPU model %s is not supported by hypervisor"),
485
                       model->name);
J
Jiri Denemark 已提交
486
        goto cleanup;
L
Li Zhang 已提交
487 488
    }

489 490
    if (VIR_STRDUP(cpu->model, model->name) < 0 ||
        (model->vendor && VIR_STRDUP(cpu->vendor, model->vendor->name) < 0)) {
491 492
        goto cleanup;
    }
L
Li Zhang 已提交
493 494 495

    ret = 0;

496
 cleanup:
L
Li Zhang 已提交
497 498 499 500 501 502 503
    ppcMapFree(map);

    return ret;
}


static void
504
ppcDataFree(virCPUDataPtr data)
L
Li Zhang 已提交
505 506 507 508 509 510 511
{
    if (data == NULL)
        return;

    VIR_FREE(data);
}

512
static virCPUDataPtr
513
ppcNodeData(virArch arch)
P
Prerna Saxena 已提交
514
{
L
Li Zhang 已提交
515
    virCPUDataPtr cpuData;
P
Prerna Saxena 已提交
516

L
Li Zhang 已提交
517
    if (VIR_ALLOC(cpuData) < 0)
P
Prerna Saxena 已提交
518 519
        return NULL;

520 521 522
    cpuData->arch = arch;

#if defined(__powerpc__) || defined(__powerpc64__)
J
Jiri Denemark 已提交
523
    asm("mfpvr %0"
L
Li Zhang 已提交
524
        : "=r" (cpuData->data.ppc.pvr));
525
#endif
L
Li Zhang 已提交
526

L
Li Zhang 已提交
527
    return cpuData;
P
Prerna Saxena 已提交
528 529
}

530 531 532 533 534 535 536 537 538
static virCPUCompareResult
ppcGuestData(virCPUDefPtr host,
             virCPUDefPtr guest,
             virCPUDataPtr *data,
             char **message)
{
    return ppcCompute(host, guest, data, message);
}

P
Prerna Saxena 已提交
539
static int
540
ppcUpdate(virCPUDefPtr guest,
541
          const virCPUDef *host)
P
Prerna Saxena 已提交
542
{
543
    switch ((virCPUMode) guest->mode) {
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
    case VIR_CPU_MODE_HOST_MODEL:
    case VIR_CPU_MODE_HOST_PASSTHROUGH:
        guest->match = VIR_CPU_MATCH_EXACT;
        virCPUDefFreeModel(guest);
        return virCPUDefCopyModel(guest, host, true);

    case VIR_CPU_MODE_CUSTOM:
        return 0;

    case VIR_CPU_MODE_LAST:
        break;
    }

    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Unexpected CPU mode: %d"), guest->mode);
    return -1;
P
Prerna Saxena 已提交
560
}
561

L
Li Zhang 已提交
562
static virCPUDefPtr
J
Jiri Denemark 已提交
563 564
ppcBaseline(virCPUDefPtr *cpus,
            unsigned int ncpus,
565 566
            const char **models ATTRIBUTE_UNUSED,
            unsigned int nmodels ATTRIBUTE_UNUSED,
567
            unsigned int flags)
P
Prerna Saxena 已提交
568
{
L
Li Zhang 已提交
569
    struct ppc_map *map = NULL;
J
Jiri Denemark 已提交
570 571
    const struct ppc_model *model;
    const struct ppc_vendor *vendor = NULL;
L
Li Zhang 已提交
572
    virCPUDefPtr cpu = NULL;
573
    size_t i;
J
Jiri Denemark 已提交
574

575 576
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);

J
Jiri Denemark 已提交
577 578
    if (!(map = ppcLoadMap()))
        goto error;
L
Li Zhang 已提交
579

J
Jiri Denemark 已提交
580 581 582
    if (!(model = ppcModelFind(map, cpus[0]->model))) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown CPU model %s"), cpus[0]->model);
L
Li Zhang 已提交
583 584 585
        goto error;
    }

J
Jiri Denemark 已提交
586 587
    for (i = 0; i < ncpus; i++) {
        const struct ppc_vendor *vnd;
588

J
Jiri Denemark 已提交
589 590 591 592 593
        if (STRNEQ(cpus[i]->model, model->name)) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("CPUs are incompatible"));
            goto error;
        }
L
Li Zhang 已提交
594

J
Jiri Denemark 已提交
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
        if (!cpus[i]->vendor)
            continue;

        if (!(vnd = ppcVendorFind(map, cpus[i]->vendor))) {
            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 已提交
622 623
    }

J
Jiri Denemark 已提交
624
    if (VIR_ALLOC(cpu) < 0 ||
625
        VIR_STRDUP(cpu->model, model->name) < 0)
626
        goto error;
L
Li Zhang 已提交
627

628 629
    if (vendor && VIR_STRDUP(cpu->vendor, vendor->name) < 0)
        goto error;
J
Jiri Denemark 已提交
630 631 632

    cpu->type = VIR_CPU_TYPE_GUEST;
    cpu->match = VIR_CPU_MATCH_EXACT;
L
Li Zhang 已提交
633

634
 cleanup:
L
Li Zhang 已提交
635
    ppcMapFree(map);
P
Prerna Saxena 已提交
636

L
Li Zhang 已提交
637
    return cpu;
J
Jiri Denemark 已提交
638

639
 error:
L
Li Zhang 已提交
640 641 642
    virCPUDefFree(cpu);
    cpu = NULL;
    goto cleanup;
P
Prerna Saxena 已提交
643 644 645 646 647 648
}

struct cpuArchDriver cpuDriverPowerPC = {
    .name = "ppc64",
    .arch = archs,
    .narch = ARRAY_CARDINALITY(archs),
649
    .compare    = ppcCompare,
J
Jiri Denemark 已提交
650
    .decode     = ppcDecode,
P
Prerna Saxena 已提交
651
    .encode     = NULL,
652
    .free       = ppcDataFree,
J
Jiri Denemark 已提交
653
    .nodeData   = ppcNodeData,
654
    .guestData  = ppcGuestData,
J
Jiri Denemark 已提交
655
    .baseline   = ppcBaseline,
656
    .update     = ppcUpdate,
P
Prerna Saxena 已提交
657 658
    .hasFeature = NULL,
};