You need to sign in or sign up before continuing.
cpu.c 14.0 KB
Newer Older
J
Jiri Denemark 已提交
1 2 3
/*
 * cpu.c: internal functions for CPU manipulation
 *
4
 * Copyright (C) 2009-2013 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
 *
 * Authors:
 *      Jiri Denemark <jdenemar@redhat.com>
 */

#include <config.h>

26
#include "virlog.h"
27
#include "viralloc.h"
28
#include "virxml.h"
J
Jiri Denemark 已提交
29
#include "cpu.h"
30
#include "cpu_map.h"
J
Jiri Denemark 已提交
31
#include "cpu_x86.h"
P
Prerna Saxena 已提交
32
#include "cpu_powerpc.h"
T
Thang Pham 已提交
33
#include "cpu_s390.h"
C
Chuck Short 已提交
34
#include "cpu_arm.h"
35
#include "cpu_aarch64.h"
J
Jiri Denemark 已提交
36
#include "cpu_generic.h"
37
#include "util/virstring.h"
J
Jiri Denemark 已提交
38 39 40 41 42


#define NR_DRIVERS ARRAY_CARDINALITY(drivers)
#define VIR_FROM_THIS VIR_FROM_CPU

43 44
VIR_LOG_INIT("cpu.cpu");

J
Jiri Denemark 已提交
45 46
static struct cpuArchDriver *drivers[] = {
    &cpuDriverX86,
P
Prerna Saxena 已提交
47
    &cpuDriverPowerPC,
T
Thang Pham 已提交
48
    &cpuDriverS390,
C
Chuck Short 已提交
49
    &cpuDriverArm,
50
    &cpuDriverAARCH64,
J
Jiri Denemark 已提交
51 52 53 54 55 56
    /* generic driver must always be the last one */
    &cpuDriverGeneric
};


static struct cpuArchDriver *
57
cpuGetSubDriver(virArch arch)
J
Jiri Denemark 已提交
58
{
59 60
    size_t i;
    size_t j;
J
Jiri Denemark 已提交
61

62
    if (arch == VIR_ARCH_NONE) {
63 64
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("undefined hardware architecture"));
J
Jiri Denemark 已提交
65 66 67 68 69
        return NULL;
    }

    for (i = 0; i < NR_DRIVERS - 1; i++) {
        for (j = 0; j < drivers[i]->narch; j++) {
70
            if (arch == drivers[i]->arch[j])
J
Jiri Denemark 已提交
71 72 73 74 75 76 77 78 79 80
                return drivers[i];
        }
    }

    /* use generic driver by default */
    return drivers[NR_DRIVERS - 1];
}


virCPUCompareResult
81
cpuCompareXML(virCPUDefPtr host,
J
Jiri Denemark 已提交
82 83 84 85 86 87 88
              const char *xml)
{
    xmlDocPtr doc = NULL;
    xmlXPathContextPtr ctxt = NULL;
    virCPUDefPtr cpu = NULL;
    virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;

89 90
    VIR_DEBUG("host=%p, xml=%s", host, NULLSTR(xml));

91
    if (!(doc = virXMLParseStringCtxt(xml, _("(CPU_definition)"), &ctxt)))
92
        goto cleanup;
J
Jiri Denemark 已提交
93

94
    cpu = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_AUTO);
J
Jiri Denemark 已提交
95 96 97
    if (cpu == NULL)
        goto cleanup;

98
    if (!cpu->model) {
99 100
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("no CPU model specified"));
101 102 103
        goto cleanup;
    }

104
    ret = cpuCompare(host, cpu);
J
Jiri Denemark 已提交
105 106 107 108 109 110 111 112 113 114 115

cleanup:
    virCPUDefFree(cpu);
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(doc);

    return ret;
}


virCPUCompareResult
116
cpuCompare(virCPUDefPtr host,
J
Jiri Denemark 已提交
117 118 119 120
           virCPUDefPtr cpu)
{
    struct cpuArchDriver *driver;

121 122
    VIR_DEBUG("host=%p, cpu=%p", host, cpu);

123
    if ((driver = cpuGetSubDriver(host->arch)) == NULL)
J
Jiri Denemark 已提交
124 125 126
        return VIR_CPU_COMPARE_ERROR;

    if (driver->compare == NULL) {
127 128
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("cannot compare CPUs of %s architecture"),
129
                       virArchToString(host->arch));
J
Jiri Denemark 已提交
130 131 132 133 134 135 136 137
        return VIR_CPU_COMPARE_ERROR;
    }

    return driver->compare(host, cpu);
}


int
138
cpuDecode(virCPUDefPtr cpu,
139
          const virCPUData *data,
140
          const char **models,
141 142
          unsigned int nmodels,
          const char *preferred)
J
Jiri Denemark 已提交
143 144 145
{
    struct cpuArchDriver *driver;

146 147
    VIR_DEBUG("cpu=%p, data=%p, nmodels=%u, preferred=%s",
              cpu, data, nmodels, NULLSTR(preferred));
148
    if (models) {
149
        size_t i;
150
        for (i = 0; i < nmodels; i++)
151
            VIR_DEBUG("models[%zu]=%s", i, NULLSTR(models[i]));
152 153
    }

154
    if (models == NULL && nmodels != 0) {
155 156
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("nonzero nmodels doesn't match with NULL models"));
157 158 159
        return -1;
    }

J
Jiri Denemark 已提交
160
    if (cpu == NULL) {
161 162
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("invalid CPU definition"));
J
Jiri Denemark 已提交
163 164 165
        return -1;
    }

166
    if ((driver = cpuGetSubDriver(cpu->arch)) == NULL)
J
Jiri Denemark 已提交
167 168 169
        return -1;

    if (driver->decode == NULL) {
170 171
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("cannot decode CPU data for %s architecture"),
172
                       virArchToString(cpu->arch));
J
Jiri Denemark 已提交
173 174 175
        return -1;
    }

176
    return driver->decode(cpu, data, models, nmodels, preferred, 0);
J
Jiri Denemark 已提交
177 178 179 180
}


int
181
cpuEncode(virArch arch,
182
          const virCPUDef *cpu,
183 184 185 186 187 188
          virCPUDataPtr *forced,
          virCPUDataPtr *required,
          virCPUDataPtr *optional,
          virCPUDataPtr *disabled,
          virCPUDataPtr *forbidden,
          virCPUDataPtr *vendor)
J
Jiri Denemark 已提交
189 190 191
{
    struct cpuArchDriver *driver;

192
    VIR_DEBUG("arch=%s, cpu=%p, forced=%p, required=%p, "
J
Jiri Denemark 已提交
193
              "optional=%p, disabled=%p, forbidden=%p, vendor=%p",
194
              virArchToString(arch), cpu, forced, required,
J
Jiri Denemark 已提交
195
              optional, disabled, forbidden, vendor);
196

197
    if ((driver = cpuGetSubDriver(arch)) == NULL)
J
Jiri Denemark 已提交
198 199 200
        return -1;

    if (driver->encode == NULL) {
201 202
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("cannot encode CPU data for %s architecture"),
203
                       virArchToString(arch));
J
Jiri Denemark 已提交
204 205 206
        return -1;
    }

J
Jiri Denemark 已提交
207
    return driver->encode(arch, cpu, forced, required,
J
Jiri Denemark 已提交
208
                          optional, disabled, forbidden, vendor);
J
Jiri Denemark 已提交
209 210 211 212
}


void
J
Jiri Denemark 已提交
213
cpuDataFree(virCPUDataPtr data)
J
Jiri Denemark 已提交
214 215 216
{
    struct cpuArchDriver *driver;

J
Jiri Denemark 已提交
217
    VIR_DEBUG("data=%p", data);
218

J
Jiri Denemark 已提交
219 220 221
    if (data == NULL)
        return;

J
Jiri Denemark 已提交
222
    if ((driver = cpuGetSubDriver(data->arch)) == NULL)
J
Jiri Denemark 已提交
223 224 225
        return;

    if (driver->free == NULL) {
226 227
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("cannot free CPU data for %s architecture"),
J
Jiri Denemark 已提交
228
                       virArchToString(data->arch));
J
Jiri Denemark 已提交
229 230 231
        return;
    }

E
Eric Blake 已提交
232
    (driver->free)(data);
J
Jiri Denemark 已提交
233 234 235
}


236
virCPUDataPtr
237
cpuNodeData(virArch arch)
J
Jiri Denemark 已提交
238 239 240
{
    struct cpuArchDriver *driver;

241
    VIR_DEBUG("arch=%s", virArchToString(arch));
242

243
    if ((driver = cpuGetSubDriver(arch)) == NULL)
J
Jiri Denemark 已提交
244 245 246
        return NULL;

    if (driver->nodeData == NULL) {
247 248
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("cannot get node CPU data for %s architecture"),
249
                       virArchToString(arch));
J
Jiri Denemark 已提交
250 251 252
        return NULL;
    }

253
    return driver->nodeData(arch);
J
Jiri Denemark 已提交
254 255 256 257
}


virCPUCompareResult
258
cpuGuestData(virCPUDefPtr host,
J
Jiri Denemark 已提交
259
             virCPUDefPtr guest,
260
             virCPUDataPtr *data,
261
             char **msg)
J
Jiri Denemark 已提交
262 263 264
{
    struct cpuArchDriver *driver;

265
    VIR_DEBUG("host=%p, guest=%p, data=%p, msg=%p", host, guest, data, msg);
266

267
    if ((driver = cpuGetSubDriver(host->arch)) == NULL)
J
Jiri Denemark 已提交
268 269 270
        return VIR_CPU_COMPARE_ERROR;

    if (driver->guestData == NULL) {
271 272
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("cannot compute guest CPU data for %s architecture"),
273
                       virArchToString(host->arch));
J
Jiri Denemark 已提交
274 275 276
        return VIR_CPU_COMPARE_ERROR;
    }

277
    return driver->guestData(host, guest, data, msg);
J
Jiri Denemark 已提交
278
}
279 280 281 282 283 284


char *
cpuBaselineXML(const char **xmlCPUs,
               unsigned int ncpus,
               const char **models,
285 286
               unsigned int nmodels,
               unsigned int flags)
287 288 289 290 291 292
{
    xmlDocPtr doc = NULL;
    xmlXPathContextPtr ctxt = NULL;
    virCPUDefPtr *cpus = NULL;
    virCPUDefPtr cpu = NULL;
    char *cpustr;
293
    size_t i;
294

295 296 297
    VIR_DEBUG("ncpus=%u, nmodels=%u", ncpus, nmodels);
    if (xmlCPUs) {
        for (i = 0; i < ncpus; i++)
298
            VIR_DEBUG("xmlCPUs[%zu]=%s", i, NULLSTR(xmlCPUs[i]));
299 300 301
    }
    if (models) {
        for (i = 0; i < nmodels; i++)
302
            VIR_DEBUG("models[%zu]=%s", i, NULLSTR(models[i]));
303 304
    }

305
    if (xmlCPUs == NULL && ncpus != 0) {
306 307
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("nonzero ncpus doesn't match with NULL xmlCPUs"));
308 309 310 311
        return NULL;
    }

    if (ncpus < 1) {
312
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("No CPUs given"));
313 314 315 316
        return NULL;
    }

    if (VIR_ALLOC_N(cpus, ncpus))
317
        goto error;
318 319

    for (i = 0; i < ncpus; i++) {
320
        if (!(doc = virXMLParseStringCtxt(xmlCPUs[i], _("(CPU_definition)"), &ctxt)))
321 322
            goto error;

323 324 325 326 327 328 329 330 331 332
        cpus[i] = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_HOST);
        if (cpus[i] == NULL)
            goto error;

        xmlXPathFreeContext(ctxt);
        xmlFreeDoc(doc);
        ctxt = NULL;
        doc = NULL;
    }

333
    if (!(cpu = cpuBaseline(cpus, ncpus, models, nmodels, flags)))
334 335
        goto error;

336
    cpustr = virCPUDefFormat(cpu, 0);
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359

cleanup:
    if (cpus) {
        for (i = 0; i < ncpus; i++)
            virCPUDefFree(cpus[i]);
        VIR_FREE(cpus);
    }
    virCPUDefFree(cpu);
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(doc);

    return cpustr;

error:
    cpustr = NULL;
    goto cleanup;
}


virCPUDefPtr
cpuBaseline(virCPUDefPtr *cpus,
            unsigned int ncpus,
            const char **models,
360 361
            unsigned int nmodels,
            unsigned int flags)
362 363
{
    struct cpuArchDriver *driver;
364
    size_t i;
365 366 367 368

    VIR_DEBUG("ncpus=%u, nmodels=%u", ncpus, nmodels);
    if (cpus) {
        for (i = 0; i < ncpus; i++)
369
            VIR_DEBUG("cpus[%zu]=%p", i, cpus[i]);
370 371 372
    }
    if (models) {
        for (i = 0; i < nmodels; i++)
373
            VIR_DEBUG("models[%zu]=%s", i, NULLSTR(models[i]));
374
    }
375 376

    if (cpus == NULL && ncpus != 0) {
377 378
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("nonzero ncpus doesn't match with NULL cpus"));
379 380 381 382
        return NULL;
    }

    if (ncpus < 1) {
383
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("No CPUs given"));
384 385 386 387
        return NULL;
    }

    if (models == NULL && nmodels != 0) {
388 389
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("nonzero nmodels doesn't match with NULL models"));
390 391 392 393 394 395 396
        return NULL;
    }

    if ((driver = cpuGetSubDriver(cpus[0]->arch)) == NULL)
        return NULL;

    if (driver->baseline == NULL) {
397 398
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("cannot compute baseline CPU of %s architecture"),
399
                       virArchToString(cpus[0]->arch));
400 401 402
        return NULL;
    }

403
    return driver->baseline(cpus, ncpus, models, nmodels, flags);
404
}
405 406 407 408


int
cpuUpdate(virCPUDefPtr guest,
409
          const virCPUDef *host)
410 411 412 413 414 415 416 417 418
{
    struct cpuArchDriver *driver;

    VIR_DEBUG("guest=%p, host=%p", guest, host);

    if ((driver = cpuGetSubDriver(host->arch)) == NULL)
        return -1;

    if (driver->update == NULL) {
419 420
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("cannot update guest CPU data for %s architecture"),
421
                       virArchToString(host->arch));
422 423 424 425 426
        return -1;
    }

    return driver->update(guest, host);
}
D
Daniel P. Berrange 已提交
427 428

int
429
cpuHasFeature(const virCPUData *data,
D
Daniel P. Berrange 已提交
430 431 432 433
              const char *feature)
{
    struct cpuArchDriver *driver;

J
Jiri Denemark 已提交
434
    VIR_DEBUG("data=%p, feature=%s", data, feature);
D
Daniel P. Berrange 已提交
435

J
Jiri Denemark 已提交
436
    if ((driver = cpuGetSubDriver(data->arch)) == NULL)
D
Daniel P. Berrange 已提交
437 438 439
        return -1;

    if (driver->hasFeature == NULL) {
440 441
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("cannot check guest CPU data for %s architecture"),
J
Jiri Denemark 已提交
442
                       virArchToString(data->arch));
D
Daniel P. Berrange 已提交
443 444 445 446 447
        return -1;
    }

    return driver->hasFeature(data, feature);
}
448

449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
char *
cpuDataFormat(const virCPUData *data)
{
    struct cpuArchDriver *driver;

    VIR_DEBUG("data=%p", data);

    if (!(driver = cpuGetSubDriver(data->arch)))
        return NULL;

    if (!driver->dataFormat) {
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("cannot format %s CPU data"),
                       virArchToString(data->arch));
        return NULL;
    }

    return driver->dataFormat(data);
}

virCPUDataPtr
cpuDataParse(virArch arch,
             const char *xmlStr)
{
    struct cpuArchDriver *driver;

    VIR_DEBUG("arch=%s, xmlStr=%s", virArchToString(arch), xmlStr);

    if (!(driver = cpuGetSubDriver(arch)))
        return NULL;

    if (!driver->dataParse) {
        virReportError(VIR_ERR_NO_SUPPORT,
                       _("cannot parse %s CPU data"),
                       virArchToString(arch));
        return NULL;
    }

    return driver->dataParse(xmlStr);
}

490 491 492 493 494
bool
cpuModelIsAllowed(const char *model,
                  const char **models,
                  unsigned int nmodels)
{
495
    size_t i;
496 497 498 499 500 501 502 503 504 505

    if (!models || !nmodels)
        return true;

    for (i = 0; i < nmodels; i++) {
        if (models[i] && STREQ(models[i], model))
            return true;
    }
    return false;
}
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583

struct cpuGetModelsData
{
    char **data;
    size_t len;  /* It includes the last element of DATA, which is NULL. */
};

static int
cpuGetArchModelsCb(enum cpuMapElement element,
                   xmlXPathContextPtr ctxt,
                   void *cbdata)
{
    char *name;
    struct cpuGetModelsData *data = cbdata;
    if (element != CPU_MAP_ELEMENT_MODEL)
        return 0;

    name = virXPathString("string(@name)", ctxt);
    if (name == NULL)
        return -1;

    if (!data->data) {
        VIR_FREE(name);
        data->len++;
        return 0;
    }

    return VIR_INSERT_ELEMENT(data->data, data->len - 1, data->len, name);
}


static int
cpuGetArchModels(const char *arch, struct cpuGetModelsData *data)
{
    return cpuMapLoad(arch, cpuGetArchModelsCb, data);
}


int
cpuGetModels(const char *archName, char ***models)
{
    struct cpuGetModelsData data;
    virArch arch;
    struct cpuArchDriver *driver;
    data.data = NULL;
    data.len = 1;

    arch = virArchFromString(archName);
    if (arch == VIR_ARCH_NONE) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("cannot find architecture %s"),
                       archName);
        goto error;
    }

    driver = cpuGetSubDriver(arch);
    if (driver == NULL) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("cannot find a driver for the architecture %s"),
                       archName);
        goto error;
    }

    if (models && VIR_ALLOC_N(data.data, data.len) < 0)
        goto error;

    if (cpuGetArchModels(driver->name, &data) < 0)
        goto error;

    if (models)
        *models = data.data;

    return data.len - 1;

error:
    virStringFreeList(data.data);
    return -1;
}