cpu.c 13.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"
J
Jiri Denemark 已提交
35
#include "cpu_generic.h"
36
#include "util/virstring.h"
J
Jiri Denemark 已提交
37 38 39 40 41 42 43


#define NR_DRIVERS ARRAY_CARDINALITY(drivers)
#define VIR_FROM_THIS VIR_FROM_CPU

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


static struct cpuArchDriver *
53
cpuGetSubDriver(virArch arch)
J
Jiri Denemark 已提交
54
{
55 56
    size_t i;
    size_t j;
J
Jiri Denemark 已提交
57

58
    if (arch == VIR_ARCH_NONE) {
59 60
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("undefined hardware architecture"));
J
Jiri Denemark 已提交
61 62 63 64 65
        return NULL;
    }

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

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


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

85 86
    VIR_DEBUG("host=%p, xml=%s", host, NULLSTR(xml));

87
    if (!(doc = virXMLParseStringCtxt(xml, _("(CPU_definition)"), &ctxt)))
88
        goto cleanup;
J
Jiri Denemark 已提交
89

90
    cpu = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_AUTO);
J
Jiri Denemark 已提交
91 92 93
    if (cpu == NULL)
        goto cleanup;

94
    if (!cpu->model) {
95 96
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("no CPU model specified"));
97 98 99
        goto cleanup;
    }

100
    ret = cpuCompare(host, cpu);
J
Jiri Denemark 已提交
101 102 103 104 105 106 107 108 109 110 111

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

    return ret;
}


virCPUCompareResult
112
cpuCompare(virCPUDefPtr host,
J
Jiri Denemark 已提交
113 114 115 116
           virCPUDefPtr cpu)
{
    struct cpuArchDriver *driver;

117 118
    VIR_DEBUG("host=%p, cpu=%p", host, cpu);

119
    if ((driver = cpuGetSubDriver(host->arch)) == NULL)
J
Jiri Denemark 已提交
120 121 122
        return VIR_CPU_COMPARE_ERROR;

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

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


int
134
cpuDecode(virCPUDefPtr cpu,
135
          const virCPUDataPtr data,
136
          const char **models,
137 138
          unsigned int nmodels,
          const char *preferred)
J
Jiri Denemark 已提交
139 140 141
{
    struct cpuArchDriver *driver;

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

150
    if (models == NULL && nmodels != 0) {
151 152
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("nonzero nmodels doesn't match with NULL models"));
153 154 155
        return -1;
    }

J
Jiri Denemark 已提交
156
    if (cpu == NULL) {
157 158
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("invalid CPU definition"));
J
Jiri Denemark 已提交
159 160 161
        return -1;
    }

162
    if ((driver = cpuGetSubDriver(cpu->arch)) == NULL)
J
Jiri Denemark 已提交
163 164 165
        return -1;

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

172
    return driver->decode(cpu, data, models, nmodels, preferred, 0);
J
Jiri Denemark 已提交
173 174 175 176
}


int
177
cpuEncode(virArch arch,
J
Jiri Denemark 已提交
178
          const virCPUDefPtr cpu,
179 180 181 182 183 184
          virCPUDataPtr *forced,
          virCPUDataPtr *required,
          virCPUDataPtr *optional,
          virCPUDataPtr *disabled,
          virCPUDataPtr *forbidden,
          virCPUDataPtr *vendor)
J
Jiri Denemark 已提交
185 186 187
{
    struct cpuArchDriver *driver;

188
    VIR_DEBUG("arch=%s, cpu=%p, forced=%p, required=%p, "
J
Jiri Denemark 已提交
189
              "optional=%p, disabled=%p, forbidden=%p, vendor=%p",
190
              virArchToString(arch), cpu, forced, required,
J
Jiri Denemark 已提交
191
              optional, disabled, forbidden, vendor);
192

193
    if ((driver = cpuGetSubDriver(arch)) == NULL)
J
Jiri Denemark 已提交
194 195 196
        return -1;

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

J
Jiri Denemark 已提交
203
    return driver->encode(arch, cpu, forced, required,
J
Jiri Denemark 已提交
204
                          optional, disabled, forbidden, vendor);
J
Jiri Denemark 已提交
205 206 207 208
}


void
J
Jiri Denemark 已提交
209
cpuDataFree(virCPUDataPtr data)
J
Jiri Denemark 已提交
210 211 212
{
    struct cpuArchDriver *driver;

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

J
Jiri Denemark 已提交
215 216 217
    if (data == NULL)
        return;

J
Jiri Denemark 已提交
218
    if ((driver = cpuGetSubDriver(data->arch)) == NULL)
J
Jiri Denemark 已提交
219 220 221
        return;

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

E
Eric Blake 已提交
228
    (driver->free)(data);
J
Jiri Denemark 已提交
229 230 231
}


232
virCPUDataPtr
233
cpuNodeData(virArch arch)
J
Jiri Denemark 已提交
234 235 236
{
    struct cpuArchDriver *driver;

237
    VIR_DEBUG("arch=%s", virArchToString(arch));
238

239
    if ((driver = cpuGetSubDriver(arch)) == NULL)
J
Jiri Denemark 已提交
240 241 242
        return NULL;

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

249
    return driver->nodeData(arch);
J
Jiri Denemark 已提交
250 251 252 253
}


virCPUCompareResult
254
cpuGuestData(virCPUDefPtr host,
J
Jiri Denemark 已提交
255
             virCPUDefPtr guest,
256
             virCPUDataPtr *data,
257
             char **msg)
J
Jiri Denemark 已提交
258 259 260
{
    struct cpuArchDriver *driver;

261
    VIR_DEBUG("host=%p, guest=%p, data=%p, msg=%p", host, guest, data, msg);
262

263
    if ((driver = cpuGetSubDriver(host->arch)) == NULL)
J
Jiri Denemark 已提交
264 265 266
        return VIR_CPU_COMPARE_ERROR;

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

273
    return driver->guestData(host, guest, data, msg);
J
Jiri Denemark 已提交
274
}
275 276 277 278 279 280


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

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

301
    if (xmlCPUs == NULL && ncpus != 0) {
302 303
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("nonzero ncpus doesn't match with NULL xmlCPUs"));
304 305 306 307
        return NULL;
    }

    if (ncpus < 1) {
308
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("No CPUs given"));
309 310 311 312
        return NULL;
    }

    if (VIR_ALLOC_N(cpus, ncpus))
313
        goto error;
314 315

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

319 320 321 322 323 324 325 326 327 328
        cpus[i] = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_HOST);
        if (cpus[i] == NULL)
            goto error;

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

329
    if (!(cpu = cpuBaseline(cpus, ncpus, models, nmodels, flags)))
330 331
        goto error;

332
    cpustr = virCPUDefFormat(cpu, 0);
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355

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,
356 357
            unsigned int nmodels,
            unsigned int flags)
358 359
{
    struct cpuArchDriver *driver;
360
    size_t i;
361 362 363 364

    VIR_DEBUG("ncpus=%u, nmodels=%u", ncpus, nmodels);
    if (cpus) {
        for (i = 0; i < ncpus; i++)
365
            VIR_DEBUG("cpus[%zu]=%p", i, cpus[i]);
366 367 368
    }
    if (models) {
        for (i = 0; i < nmodels; i++)
369
            VIR_DEBUG("models[%zu]=%s", i, NULLSTR(models[i]));
370
    }
371 372

    if (cpus == NULL && ncpus != 0) {
373 374
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("nonzero ncpus doesn't match with NULL cpus"));
375 376 377 378
        return NULL;
    }

    if (ncpus < 1) {
379
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("No CPUs given"));
380 381 382 383
        return NULL;
    }

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

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

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

399
    return driver->baseline(cpus, ncpus, models, nmodels, flags);
400
}
401 402 403 404 405 406 407 408 409 410 411 412 413 414


int
cpuUpdate(virCPUDefPtr guest,
          const virCPUDefPtr host)
{
    struct cpuArchDriver *driver;

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

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

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

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

int
J
Jiri Denemark 已提交
425
cpuHasFeature(const virCPUDataPtr data,
D
Daniel P. Berrange 已提交
426 427 428 429
              const char *feature)
{
    struct cpuArchDriver *driver;

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

J
Jiri Denemark 已提交
432
    if ((driver = cpuGetSubDriver(data->arch)) == NULL)
D
Daniel P. Berrange 已提交
433 434 435
        return -1;

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

    return driver->hasFeature(data, feature);
}
444 445 446 447 448 449

bool
cpuModelIsAllowed(const char *model,
                  const char **models,
                  unsigned int nmodels)
{
450
    size_t i;
451 452 453 454 455 456 457 458 459 460

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

    for (i = 0; i < nmodels; i++) {
        if (models[i] && STREQ(models[i], model))
            return true;
    }
    return false;
}
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 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 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

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;
}