2011-10-03 12:56:20 +00:00
|
|
|
/*
|
2015-07-20 12:35:22 +00:00
|
|
|
* cpu_ppc64.c: CPU driver for 64-bit PowerPC CPUs
|
2011-10-03 12:56:20 +00:00
|
|
|
*
|
maint: avoid 'const fooPtr' in cpu files
'const fooPtr' is the same as 'foo * const' (the pointer won't
change, but it's contents can). But in general, if an interface
is trying to be const-correct, it should be using 'const foo *'
(the pointer is to data that can't be changed).
Fix up offenders in src/cpu.
* src/cpu/cpu.h (cpuArchDecode, cpuArchEncode, cpuArchUpdate)
(cpuArchHasFeature, cpuDecode, cpuEncode, cpuUpdate)
(cpuHasFeature): Use intended type.
* src/conf/cpu_conf.h (virCPUDefCopyModel, virCPUDefCopy):
Likewise.
(virCPUDefParseXML): Drop const.
* src/cpu/cpu.c (cpuDecode, cpuEncode, cpuUpdate, cpuHasFeature):
Fix fallout.
* src/cpu/cpu_x86.c (x86ModelFromCPU, x86ModelSubtractCPU)
(x86DecodeCPUData, x86EncodePolicy, x86Encode, x86UpdateCustom)
(x86UpdateHostModel, x86Update, x86HasFeature): Likewise.
* src/cpu/cpu_s390.c (s390Decode): Likewise.
* src/cpu/cpu_arm.c (ArmDecode): Likewise.
* src/cpu/cpu_powerpc.c (ppcModelFromCPU, ppcCompute, ppcDecode)
(ppcUpdate): Likewise.
* src/conf/cpu_conf.c (virCPUDefCopyModel, virCPUDefCopy)
(virCPUDefParseXML): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-05 20:01:02 +00:00
|
|
|
* Copyright (C) 2013 Red Hat, Inc.
|
2012-10-15 09:07:51 +00:00
|
|
|
* Copyright (C) IBM Corporation, 2010
|
2011-10-03 12:56:20 +00:00
|
|
|
*
|
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2011-10-03 12:56:20 +00:00
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Anton Blanchard <anton@au.ibm.com>
|
|
|
|
* Prerna Saxena <prerna@linux.vnet.ibm.com>
|
2012-10-15 09:07:50 +00:00
|
|
|
* Li Zhang <zhlcindy@linux.vnet.ibm.com>
|
2011-10-03 12:56:20 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
2012-10-15 09:07:50 +00:00
|
|
|
#include <stdint.h>
|
2011-10-03 12:56:20 +00:00
|
|
|
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2011-10-03 12:56:20 +00:00
|
|
|
#include "cpu.h"
|
2013-05-03 12:41:23 +00:00
|
|
|
#include "virstring.h"
|
2012-10-15 09:07:50 +00:00
|
|
|
#include "cpu_map.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2011-10-03 12:56:20 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_CPU
|
|
|
|
|
2015-07-20 12:35:22 +00:00
|
|
|
VIR_LOG_INIT("cpu.cpu_ppc64");
|
2014-02-28 12:16:17 +00:00
|
|
|
|
2014-11-04 17:21:26 +00:00
|
|
|
static const virArch archs[] = { VIR_ARCH_PPC64, VIR_ARCH_PPC64LE };
|
2011-10-03 12:56:20 +00:00
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
struct ppc64_vendor {
|
2012-10-15 09:07:50 +00:00
|
|
|
char *name;
|
|
|
|
};
|
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
struct ppc64_model {
|
2012-10-15 09:07:50 +00:00
|
|
|
char *name;
|
2015-07-20 13:13:02 +00:00
|
|
|
const struct ppc64_vendor *vendor;
|
2015-08-07 15:39:13 +00:00
|
|
|
virCPUppc64Data *data;
|
2012-10-15 09:07:50 +00:00
|
|
|
};
|
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
struct ppc64_map {
|
2016-05-17 13:56:53 +00:00
|
|
|
size_t nvendors;
|
|
|
|
struct ppc64_vendor **vendors;
|
2016-05-18 13:23:54 +00:00
|
|
|
size_t nmodels;
|
|
|
|
struct ppc64_model **models;
|
2012-10-15 09:07:50 +00:00
|
|
|
};
|
|
|
|
|
2015-08-07 15:39:18 +00:00
|
|
|
/* 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;
|
|
|
|
|
2015-08-14 14:04:18 +00:00
|
|
|
if (!cpu->model ||
|
|
|
|
!(STREQ(cpu->model, "POWER7_v2.1") ||
|
2015-08-07 15:39:18 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-08-13 15:50:37 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2015-08-07 15:39:13 +00:00
|
|
|
static void
|
|
|
|
ppc64DataFree(virCPUppc64Data *data)
|
|
|
|
{
|
2015-08-07 15:39:14 +00:00
|
|
|
if (!data)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_FREE(data->pvr);
|
2015-08-07 15:39:13 +00:00
|
|
|
VIR_FREE(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static virCPUppc64Data *
|
|
|
|
ppc64DataCopy(const virCPUppc64Data *data)
|
|
|
|
{
|
|
|
|
virCPUppc64Data *copy;
|
2015-08-07 15:39:14 +00:00
|
|
|
size_t i;
|
2015-08-07 15:39:13 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC(copy) < 0)
|
2015-08-07 15:39:14 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(copy->pvr, data->len) < 0)
|
|
|
|
goto error;
|
2015-08-07 15:39:13 +00:00
|
|
|
|
2015-08-07 15:39:14 +00:00
|
|
|
copy->len = data->len;
|
|
|
|
|
2015-08-07 15:39:16 +00:00
|
|
|
for (i = 0; i < data->len; i++) {
|
2015-08-07 15:39:14 +00:00
|
|
|
copy->pvr[i].value = data->pvr[i].value;
|
2015-08-07 15:39:16 +00:00
|
|
|
copy->pvr[i].mask = data->pvr[i].mask;
|
|
|
|
}
|
2015-08-07 15:39:13 +00:00
|
|
|
|
|
|
|
return copy;
|
2015-08-07 15:39:14 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
ppc64DataFree(copy);
|
|
|
|
return NULL;
|
2015-08-07 15:39:13 +00:00
|
|
|
}
|
|
|
|
|
2015-08-07 15:39:05 +00:00
|
|
|
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)
|
|
|
|
{
|
2016-05-17 13:56:53 +00:00
|
|
|
size_t i;
|
2015-08-07 15:39:05 +00:00
|
|
|
|
2016-05-17 13:56:53 +00:00
|
|
|
for (i = 0; i < map->nvendors; i++) {
|
|
|
|
if (STREQ(map->vendors[i]->name, name))
|
|
|
|
return map->vendors[i];
|
2015-08-07 15:39:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-10-15 09:07:50 +00:00
|
|
|
|
|
|
|
static void
|
2015-07-20 13:13:02 +00:00
|
|
|
ppc64ModelFree(struct ppc64_model *model)
|
2012-10-15 09:07:50 +00:00
|
|
|
{
|
2015-08-07 15:39:03 +00:00
|
|
|
if (!model)
|
2012-10-15 09:07:50 +00:00
|
|
|
return;
|
|
|
|
|
2015-08-07 15:39:13 +00:00
|
|
|
ppc64DataFree(model->data);
|
2012-10-15 09:07:50 +00:00
|
|
|
VIR_FREE(model->name);
|
|
|
|
VIR_FREE(model);
|
|
|
|
}
|
|
|
|
|
2015-08-07 15:39:05 +00:00
|
|
|
static struct ppc64_model *
|
|
|
|
ppc64ModelCopy(const struct ppc64_model *model)
|
|
|
|
{
|
|
|
|
struct ppc64_model *copy;
|
|
|
|
|
2015-08-07 15:39:13 +00:00
|
|
|
if (VIR_ALLOC(copy) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (VIR_STRDUP(copy->name, model->name) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(copy->data = ppc64DataCopy(model->data)))
|
|
|
|
goto error;
|
2015-08-07 15:39:05 +00:00
|
|
|
|
|
|
|
copy->vendor = model->vendor;
|
|
|
|
|
|
|
|
return copy;
|
2015-08-07 15:39:13 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
ppc64ModelFree(copy);
|
|
|
|
return NULL;
|
2015-08-07 15:39:05 +00:00
|
|
|
}
|
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
static struct ppc64_model *
|
|
|
|
ppc64ModelFind(const struct ppc64_map *map,
|
|
|
|
const char *name)
|
2012-10-15 09:07:50 +00:00
|
|
|
{
|
2016-05-18 13:23:54 +00:00
|
|
|
size_t i;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2016-05-18 13:23:54 +00:00
|
|
|
for (i = 0; i < map->nmodels; i++) {
|
|
|
|
if (STREQ(map->models[i]->name, name))
|
|
|
|
return map->models[i];
|
2012-10-15 09:07:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
static struct ppc64_model *
|
|
|
|
ppc64ModelFindPVR(const struct ppc64_map *map,
|
|
|
|
uint32_t pvr)
|
2012-12-19 00:35:51 +00:00
|
|
|
{
|
2015-08-07 15:39:14 +00:00
|
|
|
size_t i;
|
2016-05-18 13:23:54 +00:00
|
|
|
size_t j;
|
2012-12-19 00:35:51 +00:00
|
|
|
|
2016-05-18 13:23:54 +00:00
|
|
|
for (i = 0; i < map->nmodels; i++) {
|
|
|
|
struct ppc64_model *model = map->models[i];
|
|
|
|
for (j = 0; j < model->data->len; j++) {
|
|
|
|
if ((pvr & model->data->pvr[j].mask) == model->data->pvr[j].value)
|
2015-08-07 15:39:14 +00:00
|
|
|
return model;
|
|
|
|
}
|
2012-12-19 00:35:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
static struct ppc64_model *
|
2015-08-07 15:39:05 +00:00
|
|
|
ppc64ModelFromCPU(const virCPUDef *cpu,
|
|
|
|
const struct ppc64_map *map)
|
2013-09-03 06:28:24 +00:00
|
|
|
{
|
2015-08-07 15:39:05 +00:00
|
|
|
struct ppc64_model *model;
|
2013-09-03 06:28:24 +00:00
|
|
|
|
2015-08-07 15:39:05 +00:00
|
|
|
if (!(model = ppc64ModelFind(map, cpu->model))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unknown CPU model %s"), cpu->model);
|
2013-09-03 06:28:24 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-08-07 15:39:05 +00:00
|
|
|
return ppc64ModelCopy(model);
|
2012-10-15 09:07:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-08-07 15:39:05 +00:00
|
|
|
ppc64MapFree(struct ppc64_map *map)
|
2012-10-15 09:07:50 +00:00
|
|
|
{
|
2016-05-17 13:56:53 +00:00
|
|
|
size_t i;
|
|
|
|
|
2015-08-07 15:39:05 +00:00
|
|
|
if (!map)
|
2012-10-15 09:07:50 +00:00
|
|
|
return;
|
|
|
|
|
2016-05-18 13:23:54 +00:00
|
|
|
for (i = 0; i < map->nmodels; i++)
|
|
|
|
ppc64ModelFree(map->models[i]);
|
|
|
|
VIR_FREE(map->models);
|
2013-09-03 06:28:24 +00:00
|
|
|
|
2016-05-17 13:56:53 +00:00
|
|
|
for (i = 0; i < map->nvendors; i++)
|
|
|
|
ppc64VendorFree(map->vendors[i]);
|
|
|
|
VIR_FREE(map->vendors);
|
2013-09-03 06:28:24 +00:00
|
|
|
|
2015-08-07 15:39:05 +00:00
|
|
|
VIR_FREE(map);
|
2013-09-03 06:28:24 +00:00
|
|
|
}
|
|
|
|
|
2016-05-17 08:59:28 +00:00
|
|
|
static struct ppc64_vendor *
|
|
|
|
ppc64VendorParse(xmlXPathContextPtr ctxt,
|
|
|
|
struct ppc64_map *map)
|
2012-10-15 09:07:50 +00:00
|
|
|
{
|
2015-08-07 15:39:03 +00:00
|
|
|
struct ppc64_vendor *vendor;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2013-07-04 10:03:29 +00:00
|
|
|
if (VIR_ALLOC(vendor) < 0)
|
2016-05-17 08:59:28 +00:00
|
|
|
return NULL;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
|
|
|
vendor->name = virXPathString("string(@name)", ctxt);
|
|
|
|
if (!vendor->name) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Missing CPU vendor name"));
|
2016-05-17 08:59:28 +00:00
|
|
|
goto error;
|
2012-10-15 09:07:50 +00:00
|
|
|
}
|
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
if (ppc64VendorFind(map, vendor->name)) {
|
2012-10-15 09:07:50 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("CPU vendor %s already defined"), vendor->name);
|
2016-05-17 08:59:28 +00:00
|
|
|
goto error;
|
2012-10-15 09:07:50 +00:00
|
|
|
}
|
|
|
|
|
2016-05-17 08:59:28 +00:00
|
|
|
return vendor;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2016-05-17 08:59:28 +00:00
|
|
|
error:
|
2015-07-20 13:13:02 +00:00
|
|
|
ppc64VendorFree(vendor);
|
2016-05-17 08:59:28 +00:00
|
|
|
return NULL;
|
2012-10-15 09:07:50 +00:00
|
|
|
}
|
|
|
|
|
2016-05-17 08:59:28 +00:00
|
|
|
|
2012-10-15 09:07:50 +00:00
|
|
|
static int
|
2016-05-17 08:59:28 +00:00
|
|
|
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)
|
2012-10-15 09:07:50 +00:00
|
|
|
{
|
2015-07-20 13:13:02 +00:00
|
|
|
struct ppc64_model *model;
|
2015-08-07 15:39:14 +00:00
|
|
|
xmlNodePtr *nodes = NULL;
|
2012-10-15 09:07:50 +00:00
|
|
|
char *vendor = NULL;
|
2012-12-19 00:35:51 +00:00
|
|
|
unsigned long pvr;
|
2015-08-07 15:39:14 +00:00
|
|
|
size_t i;
|
|
|
|
int n;
|
|
|
|
|
2013-07-04 10:03:29 +00:00
|
|
|
if (VIR_ALLOC(model) < 0)
|
2016-05-17 08:59:28 +00:00
|
|
|
goto error;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2016-05-17 08:59:28 +00:00
|
|
|
if (VIR_ALLOC(model->data) < 0)
|
|
|
|
goto error;
|
2015-08-07 15:39:13 +00:00
|
|
|
|
2012-10-15 09:07:50 +00:00
|
|
|
model->name = virXPathString("string(@name)", ctxt);
|
2012-12-19 00:35:51 +00:00
|
|
|
if (!model->name) {
|
2012-10-15 09:07:50 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Missing CPU model name"));
|
2016-05-17 08:59:28 +00:00
|
|
|
goto error;
|
2012-10-15 09:07:50 +00:00
|
|
|
}
|
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
if (ppc64ModelFind(map, model->name)) {
|
2012-12-19 00:35:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("CPU model %s already defined"), model->name);
|
2016-05-17 08:59:28 +00:00
|
|
|
goto error;
|
2012-12-19 00:35:51 +00:00
|
|
|
}
|
2012-10-15 09:07:50 +00:00
|
|
|
|
|
|
|
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);
|
2016-05-17 08:59:28 +00:00
|
|
|
goto error;
|
2012-10-15 09:07:50 +00:00
|
|
|
}
|
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
if (!(model->vendor = ppc64VendorFind(map, vendor))) {
|
2012-10-15 09:07:50 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unknown vendor %s referenced by CPU model %s"),
|
|
|
|
vendor, model->name);
|
2016-05-17 08:59:28 +00:00
|
|
|
goto error;
|
2012-10-15 09:07:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-07 15:39:14 +00:00
|
|
|
if ((n = virXPathNodeSet("./pvr", ctxt, &nodes)) <= 0) {
|
2012-12-19 00:35:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2015-08-07 15:39:14 +00:00
|
|
|
_("Missing PVR information for CPU model %s"),
|
2012-12-19 00:35:51 +00:00
|
|
|
model->name);
|
2016-05-17 08:59:28 +00:00
|
|
|
goto error;
|
2012-12-19 00:35:51 +00:00
|
|
|
}
|
2015-08-07 15:39:14 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC_N(model->data->pvr, n) < 0)
|
2016-05-17 08:59:28 +00:00
|
|
|
goto error;
|
2015-08-07 15:39:14 +00:00
|
|
|
|
|
|
|
model->data->len = n;
|
|
|
|
|
|
|
|
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);
|
2016-05-17 08:59:28 +00:00
|
|
|
goto error;
|
2015-08-07 15:39:14 +00:00
|
|
|
}
|
|
|
|
model->data->pvr[i].value = pvr;
|
2015-08-07 15:39:16 +00:00
|
|
|
|
|
|
|
if (virXPathULongHex("string(./@mask)", ctxt, &pvr) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Missing or invalid PVR mask in CPU model %s"),
|
|
|
|
model->name);
|
2016-05-17 08:59:28 +00:00
|
|
|
goto error;
|
2015-08-07 15:39:16 +00:00
|
|
|
}
|
|
|
|
model->data->pvr[i].mask = pvr;
|
2015-08-07 15:39:14 +00:00
|
|
|
}
|
2012-12-19 00:35:51 +00:00
|
|
|
|
2014-03-25 06:50:40 +00:00
|
|
|
cleanup:
|
2012-10-15 09:07:50 +00:00
|
|
|
VIR_FREE(vendor);
|
2015-08-07 15:39:14 +00:00
|
|
|
VIR_FREE(nodes);
|
2016-05-17 08:59:28 +00:00
|
|
|
return model;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2016-05-17 08:59:28 +00:00
|
|
|
error:
|
2015-07-20 13:13:02 +00:00
|
|
|
ppc64ModelFree(model);
|
2016-05-17 08:59:28 +00:00
|
|
|
model = NULL;
|
2012-12-19 00:35:51 +00:00
|
|
|
goto cleanup;
|
2012-10-15 09:07:50 +00:00
|
|
|
}
|
|
|
|
|
2016-05-17 08:59:28 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-15 09:07:50 +00:00
|
|
|
static int
|
2015-07-20 13:13:02 +00:00
|
|
|
ppc64MapLoadCallback(cpuMapElement element,
|
|
|
|
xmlXPathContextPtr ctxt,
|
2016-05-17 08:59:28 +00:00
|
|
|
xmlNodePtr *nodes,
|
|
|
|
int n,
|
2015-07-20 13:13:02 +00:00
|
|
|
void *data)
|
2012-10-15 09:07:50 +00:00
|
|
|
{
|
2015-07-20 13:13:02 +00:00
|
|
|
struct ppc64_map *map = data;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
|
|
|
switch (element) {
|
|
|
|
case CPU_MAP_ELEMENT_VENDOR:
|
2016-05-17 08:59:28 +00:00
|
|
|
return ppc64VendorsLoad(map, ctxt, nodes, n);
|
2012-10-15 09:07:50 +00:00
|
|
|
case CPU_MAP_ELEMENT_MODEL:
|
2016-05-17 08:59:28 +00:00
|
|
|
return ppc64ModelsLoad(map, ctxt, nodes, n);
|
2012-12-19 00:35:51 +00:00
|
|
|
case CPU_MAP_ELEMENT_FEATURE:
|
|
|
|
case CPU_MAP_ELEMENT_LAST:
|
2012-10-15 09:07:50 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
static struct ppc64_map *
|
|
|
|
ppc64LoadMap(void)
|
2012-10-15 09:07:50 +00:00
|
|
|
{
|
2015-07-20 13:13:02 +00:00
|
|
|
struct ppc64_map *map;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2013-07-04 10:03:29 +00:00
|
|
|
if (VIR_ALLOC(map) < 0)
|
2015-08-07 15:39:13 +00:00
|
|
|
goto error;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
if (cpuMapLoad("ppc64", ppc64MapLoadCallback, map) < 0)
|
2012-10-15 09:07:50 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return map;
|
|
|
|
|
2014-03-25 06:50:40 +00:00
|
|
|
error:
|
2015-07-20 13:13:02 +00:00
|
|
|
ppc64MapFree(map);
|
2012-10-15 09:07:50 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-09-03 06:28:24 +00:00
|
|
|
static virCPUDataPtr
|
2015-07-20 13:20:20 +00:00
|
|
|
ppc64MakeCPUData(virArch arch,
|
2015-08-07 15:39:13 +00:00
|
|
|
virCPUppc64Data *data)
|
2013-09-03 06:28:24 +00:00
|
|
|
{
|
|
|
|
virCPUDataPtr cpuData;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(cpuData) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
cpuData->arch = arch;
|
2015-08-07 15:39:13 +00:00
|
|
|
|
|
|
|
if (!(cpuData->data.ppc64 = ppc64DataCopy(data)))
|
|
|
|
VIR_FREE(cpuData);
|
2013-09-03 06:28:24 +00:00
|
|
|
|
|
|
|
return cpuData;
|
|
|
|
}
|
|
|
|
|
|
|
|
static virCPUCompareResult
|
2015-07-20 13:13:02 +00:00
|
|
|
ppc64Compute(virCPUDefPtr host,
|
2015-08-07 15:39:18 +00:00
|
|
|
const virCPUDef *other,
|
2015-07-20 13:13:02 +00:00
|
|
|
virCPUDataPtr *guestData,
|
|
|
|
char **message)
|
2013-09-03 06:28:24 +00:00
|
|
|
{
|
2015-07-20 13:13:02 +00:00
|
|
|
struct ppc64_map *map = NULL;
|
|
|
|
struct ppc64_model *host_model = NULL;
|
|
|
|
struct ppc64_model *guest_model = NULL;
|
2015-08-07 15:39:18 +00:00
|
|
|
virCPUDefPtr cpu = NULL;
|
2013-09-09 05:56:33 +00:00
|
|
|
virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR;
|
2013-09-03 06:28:24 +00:00
|
|
|
virArch arch;
|
|
|
|
size_t i;
|
|
|
|
|
2015-08-07 15:39:18 +00:00
|
|
|
/* Ensure existing configurations are handled correctly */
|
|
|
|
if (!(cpu = ppc64ConvertLegacyCPUDef(other)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-09-03 06:28:24 +00:00
|
|
|
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)
|
2013-09-09 05:56:33 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = VIR_CPU_COMPARE_INCOMPATIBLE;
|
|
|
|
goto cleanup;
|
2013-09-03 06:28:24 +00:00
|
|
|
}
|
|
|
|
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)
|
2013-09-09 05:56:33 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = VIR_CPU_COMPARE_INCOMPATIBLE;
|
|
|
|
goto cleanup;
|
2013-09-03 06:28:24 +00:00
|
|
|
}
|
|
|
|
|
2015-08-13 15:50:37 +00:00
|
|
|
if (!(map = ppc64LoadMap()))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* Host CPU information */
|
|
|
|
if (!(host_model = ppc64ModelFromCPU(host, map)))
|
2013-09-09 05:56:33 +00:00
|
|
|
goto cleanup;
|
2013-09-03 06:28:24 +00:00
|
|
|
|
2015-08-13 15:50:37 +00:00
|
|
|
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 */
|
|
|
|
if (!(guest_model = ppc64ModelCopy(host_model)))
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_CPU_MODE_CUSTOM:
|
|
|
|
/* custom:
|
|
|
|
* look up guest CPU information */
|
|
|
|
if (!(guest_model = ppc64ModelFromCPU(cpu, map)))
|
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Other host CPU information */
|
|
|
|
if (!(guest_model = ppc64ModelFromCPU(cpu, map)))
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-08-07 15:39:10 +00:00
|
|
|
if (STRNEQ(guest_model->name, host_model->name)) {
|
2015-08-07 15:39:09 +00:00
|
|
|
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)
|
2013-09-09 05:56:33 +00:00
|
|
|
goto cleanup;
|
2013-09-03 06:28:24 +00:00
|
|
|
|
2015-08-07 15:39:09 +00:00
|
|
|
ret = VIR_CPU_COMPARE_INCOMPATIBLE;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (guestData)
|
2015-08-07 15:39:13 +00:00
|
|
|
if (!(*guestData = ppc64MakeCPUData(arch, guest_model->data)))
|
2013-09-09 05:56:33 +00:00
|
|
|
goto cleanup;
|
2013-09-03 06:28:24 +00:00
|
|
|
|
|
|
|
ret = VIR_CPU_COMPARE_IDENTICAL;
|
|
|
|
|
2014-03-25 06:50:40 +00:00
|
|
|
cleanup:
|
2015-08-07 15:39:18 +00:00
|
|
|
virCPUDefFree(cpu);
|
2015-07-20 13:13:02 +00:00
|
|
|
ppc64MapFree(map);
|
|
|
|
ppc64ModelFree(host_model);
|
|
|
|
ppc64ModelFree(guest_model);
|
2013-09-03 06:28:24 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-10-15 09:07:50 +00:00
|
|
|
static virCPUCompareResult
|
2015-08-07 15:39:02 +00:00
|
|
|
ppc64DriverCompare(virCPUDefPtr host,
|
|
|
|
virCPUDefPtr cpu,
|
|
|
|
bool failIncompatible)
|
2012-10-15 09:07:50 +00:00
|
|
|
{
|
2015-08-07 15:39:11 +00:00
|
|
|
virCPUCompareResult ret;
|
|
|
|
char *message = NULL;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2015-08-07 15:39:11 +00:00
|
|
|
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);
|
|
|
|
}
|
2014-05-28 13:11:57 +00:00
|
|
|
}
|
2015-08-07 15:39:11 +00:00
|
|
|
VIR_FREE(message);
|
|
|
|
|
|
|
|
return ret;
|
2012-10-15 09:07:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2015-08-07 15:39:02 +00:00
|
|
|
ppc64DriverDecode(virCPUDefPtr cpu,
|
|
|
|
const virCPUData *data,
|
|
|
|
const char **models,
|
|
|
|
unsigned int nmodels,
|
|
|
|
const char *preferred ATTRIBUTE_UNUSED,
|
|
|
|
unsigned int flags)
|
2012-10-15 09:07:50 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
2015-07-20 13:13:02 +00:00
|
|
|
struct ppc64_map *map;
|
|
|
|
const struct ppc64_model *model;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2013-08-02 19:08:19 +00:00
|
|
|
virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1);
|
|
|
|
|
2015-08-07 15:39:03 +00:00
|
|
|
if (!data || !(map = ppc64LoadMap()))
|
2012-10-15 09:07:50 +00:00
|
|
|
return -1;
|
|
|
|
|
2015-08-07 15:39:14 +00:00
|
|
|
if (!(model = ppc64ModelFindPVR(map, data->data.ppc64->pvr[0].value))) {
|
2012-12-19 00:35:51 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("Cannot find CPU model with PVR 0x%08x"),
|
2015-08-07 15:39:14 +00:00
|
|
|
data->data.ppc64->pvr[0].value);
|
2012-12-19 00:53:25 +00:00
|
|
|
goto cleanup;
|
2012-12-19 00:35:51 +00:00
|
|
|
}
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2012-12-19 00:35:51 +00:00
|
|
|
if (!cpuModelIsAllowed(model->name, models, nmodels)) {
|
2012-12-19 00:53:25 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("CPU model %s is not supported by hypervisor"),
|
2012-12-19 00:35:51 +00:00
|
|
|
model->name);
|
2012-12-19 00:53:25 +00:00
|
|
|
goto cleanup;
|
2012-10-15 09:07:50 +00:00
|
|
|
}
|
|
|
|
|
2013-05-03 12:41:23 +00:00
|
|
|
if (VIR_STRDUP(cpu->model, model->name) < 0 ||
|
|
|
|
(model->vendor && VIR_STRDUP(cpu->vendor, model->vendor->name) < 0)) {
|
2012-12-19 00:35:51 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-10-15 09:07:50 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:50:40 +00:00
|
|
|
cleanup:
|
2015-07-20 13:13:02 +00:00
|
|
|
ppc64MapFree(map);
|
2012-10-15 09:07:50 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-08-07 15:39:02 +00:00
|
|
|
ppc64DriverFree(virCPUDataPtr data)
|
2012-10-15 09:07:50 +00:00
|
|
|
{
|
2015-08-07 15:39:03 +00:00
|
|
|
if (!data)
|
2012-10-15 09:07:50 +00:00
|
|
|
return;
|
|
|
|
|
2015-08-07 15:39:13 +00:00
|
|
|
ppc64DataFree(data->data.ppc64);
|
2012-10-15 09:07:50 +00:00
|
|
|
VIR_FREE(data);
|
|
|
|
}
|
|
|
|
|
2012-12-18 18:44:23 +00:00
|
|
|
static virCPUDataPtr
|
2015-08-07 15:39:02 +00:00
|
|
|
ppc64DriverNodeData(virArch arch)
|
2011-10-03 12:56:20 +00:00
|
|
|
{
|
2015-08-07 15:39:13 +00:00
|
|
|
virCPUDataPtr nodeData;
|
|
|
|
virCPUppc64Data *data;
|
2011-10-03 12:56:20 +00:00
|
|
|
|
2015-08-07 15:39:13 +00:00
|
|
|
if (VIR_ALLOC(nodeData) < 0)
|
|
|
|
goto error;
|
2011-10-03 12:56:20 +00:00
|
|
|
|
2015-08-11 15:51:28 +00:00
|
|
|
if (VIR_ALLOC(nodeData->data.ppc64) < 0)
|
2015-08-07 15:39:13 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
data = nodeData->data.ppc64;
|
Ensure 'arch' is always set in cpuArchNodeData
The s390, ppc and arm CPU drivers never set the 'arch' field
in their impl of cpuArchNodeData. This leads to error messages
being reported from cpuDataFree later, due to trying to use
VIR_ARCH_NONE.
#0 virRaiseErrorFull (filename=filename@entry=0x76f94434 "cpu/cpu.c", funcname=funcname@entry=0x76f942dc <__FUNCTION__.18096> "cpuGetSubDriver", linenr=linenr@entry=58,
domain=domain@entry=31, code=code@entry=1, level=level@entry=VIR_ERR_ERROR, str1=0x76f70e18 "internal error: %s",
str2=str2@entry=0x7155f2ec "undefined hardware architecture", str3=str3@entry=0x0, int1=int1@entry=-1, int2=int2@entry=-1, fmt=0x76f70e18 "internal error: %s")
at util/virerror.c:646
#1 0x76e682ea in virReportErrorHelper (domcode=domcode@entry=31, errorcode=errorcode@entry=1, filename=0x76f94434 "cpu/cpu.c",
funcname=0x76f942dc <__FUNCTION__.18096> "cpuGetSubDriver", linenr=linenr@entry=58, fmt=0x76f7e7e4 "%s") at util/virerror.c:1292
#2 0x76ed82d4 in cpuGetSubDriver (arch=<optimized out>) at cpu/cpu.c:57
#3 cpuGetSubDriver (arch=VIR_ARCH_NONE) at cpu/cpu.c:51
#4 0x76ed8818 in cpuDataFree (data=data@entry=0x70c22d78) at cpu/cpu.c:216
#5 0x716aaec0 in virQEMUCapsInitCPU (arch=VIR_ARCH_ARMV7L, caps=0x70c29a08) at qemu/qemu_capabilities.c:867
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-09-04 16:41:55 +00:00
|
|
|
|
2015-08-07 15:39:14 +00:00
|
|
|
if (VIR_ALLOC_N(data->pvr, 1) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
data->len = 1;
|
|
|
|
|
Ensure 'arch' is always set in cpuArchNodeData
The s390, ppc and arm CPU drivers never set the 'arch' field
in their impl of cpuArchNodeData. This leads to error messages
being reported from cpuDataFree later, due to trying to use
VIR_ARCH_NONE.
#0 virRaiseErrorFull (filename=filename@entry=0x76f94434 "cpu/cpu.c", funcname=funcname@entry=0x76f942dc <__FUNCTION__.18096> "cpuGetSubDriver", linenr=linenr@entry=58,
domain=domain@entry=31, code=code@entry=1, level=level@entry=VIR_ERR_ERROR, str1=0x76f70e18 "internal error: %s",
str2=str2@entry=0x7155f2ec "undefined hardware architecture", str3=str3@entry=0x0, int1=int1@entry=-1, int2=int2@entry=-1, fmt=0x76f70e18 "internal error: %s")
at util/virerror.c:646
#1 0x76e682ea in virReportErrorHelper (domcode=domcode@entry=31, errorcode=errorcode@entry=1, filename=0x76f94434 "cpu/cpu.c",
funcname=0x76f942dc <__FUNCTION__.18096> "cpuGetSubDriver", linenr=linenr@entry=58, fmt=0x76f7e7e4 "%s") at util/virerror.c:1292
#2 0x76ed82d4 in cpuGetSubDriver (arch=<optimized out>) at cpu/cpu.c:57
#3 cpuGetSubDriver (arch=VIR_ARCH_NONE) at cpu/cpu.c:51
#4 0x76ed8818 in cpuDataFree (data=data@entry=0x70c22d78) at cpu/cpu.c:216
#5 0x716aaec0 in virQEMUCapsInitCPU (arch=VIR_ARCH_ARMV7L, caps=0x70c29a08) at qemu/qemu_capabilities.c:867
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-09-04 16:41:55 +00:00
|
|
|
#if defined(__powerpc__) || defined(__powerpc64__)
|
2012-12-18 22:42:34 +00:00
|
|
|
asm("mfpvr %0"
|
2015-08-07 15:39:14 +00:00
|
|
|
: "=r" (data->pvr[0].value));
|
Ensure 'arch' is always set in cpuArchNodeData
The s390, ppc and arm CPU drivers never set the 'arch' field
in their impl of cpuArchNodeData. This leads to error messages
being reported from cpuDataFree later, due to trying to use
VIR_ARCH_NONE.
#0 virRaiseErrorFull (filename=filename@entry=0x76f94434 "cpu/cpu.c", funcname=funcname@entry=0x76f942dc <__FUNCTION__.18096> "cpuGetSubDriver", linenr=linenr@entry=58,
domain=domain@entry=31, code=code@entry=1, level=level@entry=VIR_ERR_ERROR, str1=0x76f70e18 "internal error: %s",
str2=str2@entry=0x7155f2ec "undefined hardware architecture", str3=str3@entry=0x0, int1=int1@entry=-1, int2=int2@entry=-1, fmt=0x76f70e18 "internal error: %s")
at util/virerror.c:646
#1 0x76e682ea in virReportErrorHelper (domcode=domcode@entry=31, errorcode=errorcode@entry=1, filename=0x76f94434 "cpu/cpu.c",
funcname=0x76f942dc <__FUNCTION__.18096> "cpuGetSubDriver", linenr=linenr@entry=58, fmt=0x76f7e7e4 "%s") at util/virerror.c:1292
#2 0x76ed82d4 in cpuGetSubDriver (arch=<optimized out>) at cpu/cpu.c:57
#3 cpuGetSubDriver (arch=VIR_ARCH_NONE) at cpu/cpu.c:51
#4 0x76ed8818 in cpuDataFree (data=data@entry=0x70c22d78) at cpu/cpu.c:216
#5 0x716aaec0 in virQEMUCapsInitCPU (arch=VIR_ARCH_ARMV7L, caps=0x70c29a08) at qemu/qemu_capabilities.c:867
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-09-04 16:41:55 +00:00
|
|
|
#endif
|
2015-08-07 15:39:16 +00:00
|
|
|
data->pvr[0].mask = 0xfffffffful;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2015-08-07 15:39:13 +00:00
|
|
|
nodeData->arch = arch;
|
|
|
|
|
|
|
|
return nodeData;
|
|
|
|
|
|
|
|
error:
|
|
|
|
ppc64DriverFree(nodeData);
|
|
|
|
return NULL;
|
2011-10-03 12:56:20 +00:00
|
|
|
}
|
|
|
|
|
2013-09-03 06:28:24 +00:00
|
|
|
static virCPUCompareResult
|
2015-08-07 15:39:02 +00:00
|
|
|
ppc64DriverGuestData(virCPUDefPtr host,
|
|
|
|
virCPUDefPtr guest,
|
|
|
|
virCPUDataPtr *data,
|
|
|
|
char **message)
|
2013-09-03 06:28:24 +00:00
|
|
|
{
|
2015-07-20 13:13:02 +00:00
|
|
|
return ppc64Compute(host, guest, data, message);
|
2013-09-03 06:28:24 +00:00
|
|
|
}
|
|
|
|
|
2011-10-03 12:56:20 +00:00
|
|
|
static int
|
2015-08-07 15:39:02 +00:00
|
|
|
ppc64DriverUpdate(virCPUDefPtr guest,
|
|
|
|
const virCPUDef *host)
|
2011-10-03 12:56:20 +00:00
|
|
|
{
|
2014-04-28 00:15:21 +00:00
|
|
|
switch ((virCPUMode) guest->mode) {
|
2013-09-03 06:28:24 +00:00
|
|
|
case VIR_CPU_MODE_HOST_PASSTHROUGH:
|
|
|
|
guest->match = VIR_CPU_MATCH_EXACT;
|
2015-08-07 15:39:19 +00:00
|
|
|
guest->fallback = VIR_CPU_FALLBACK_FORBID;
|
2013-09-03 06:28:24 +00:00
|
|
|
virCPUDefFreeModel(guest);
|
|
|
|
return virCPUDefCopyModel(guest, host, true);
|
|
|
|
|
2015-08-13 11:40:12 +00:00
|
|
|
case VIR_CPU_MODE_HOST_MODEL:
|
2013-09-03 06:28:24 +00:00
|
|
|
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;
|
2011-10-03 12:56:20 +00:00
|
|
|
}
|
2012-12-20 11:38:25 +00:00
|
|
|
|
2012-10-15 09:07:50 +00:00
|
|
|
static virCPUDefPtr
|
2015-08-07 15:39:02 +00:00
|
|
|
ppc64DriverBaseline(virCPUDefPtr *cpus,
|
|
|
|
unsigned int ncpus,
|
|
|
|
const char **models ATTRIBUTE_UNUSED,
|
|
|
|
unsigned int nmodels ATTRIBUTE_UNUSED,
|
|
|
|
unsigned int flags)
|
2011-10-03 12:56:20 +00:00
|
|
|
{
|
2015-08-07 15:39:03 +00:00
|
|
|
struct ppc64_map *map;
|
2015-07-20 13:13:02 +00:00
|
|
|
const struct ppc64_model *model;
|
|
|
|
const struct ppc64_vendor *vendor = NULL;
|
2012-10-15 09:07:50 +00:00
|
|
|
virCPUDefPtr cpu = NULL;
|
Convert 'int i' to 'size_t i' in src/cpu/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-12-19 00:33:01 +00:00
|
|
|
|
2015-02-05 14:29:52 +00:00
|
|
|
virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
|
|
|
|
VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL);
|
2013-08-02 19:08:19 +00:00
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
if (!(map = ppc64LoadMap()))
|
2012-12-19 00:33:01 +00:00
|
|
|
goto error;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
if (!(model = ppc64ModelFind(map, cpus[0]->model))) {
|
2012-12-19 00:33:01 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unknown CPU model %s"), cpus[0]->model);
|
2012-10-15 09:07:50 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-12-19 00:33:01 +00:00
|
|
|
for (i = 0; i < ncpus; i++) {
|
2015-07-20 13:13:02 +00:00
|
|
|
const struct ppc64_vendor *vnd;
|
2012-12-11 12:58:54 +00:00
|
|
|
|
2015-08-07 15:39:18 +00:00
|
|
|
/* 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 */
|
2012-12-19 00:33:01 +00:00
|
|
|
if (STRNEQ(cpus[i]->model, model->name)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("CPUs are incompatible"));
|
|
|
|
goto error;
|
|
|
|
}
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2012-12-19 00:33:01 +00:00
|
|
|
if (!cpus[i]->vendor)
|
|
|
|
continue;
|
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
if (!(vnd = ppc64VendorFind(map, cpus[i]->vendor))) {
|
2012-12-19 00:33:01 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-10-15 09:07:50 +00:00
|
|
|
}
|
|
|
|
|
2012-12-19 00:33:01 +00:00
|
|
|
if (VIR_ALLOC(cpu) < 0 ||
|
2013-05-03 12:41:23 +00:00
|
|
|
VIR_STRDUP(cpu->model, model->name) < 0)
|
2013-07-04 10:03:29 +00:00
|
|
|
goto error;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2013-05-03 12:41:23 +00:00
|
|
|
if (vendor && VIR_STRDUP(cpu->vendor, vendor->name) < 0)
|
|
|
|
goto error;
|
2012-12-19 00:33:01 +00:00
|
|
|
|
|
|
|
cpu->type = VIR_CPU_TYPE_GUEST;
|
|
|
|
cpu->match = VIR_CPU_MATCH_EXACT;
|
2015-08-07 15:39:19 +00:00
|
|
|
cpu->fallback = VIR_CPU_FALLBACK_FORBID;
|
2012-10-15 09:07:50 +00:00
|
|
|
|
2014-03-25 06:50:40 +00:00
|
|
|
cleanup:
|
2015-07-20 13:13:02 +00:00
|
|
|
ppc64MapFree(map);
|
2011-10-03 12:56:20 +00:00
|
|
|
|
2012-10-15 09:07:50 +00:00
|
|
|
return cpu;
|
2012-12-19 00:33:01 +00:00
|
|
|
|
2014-03-25 06:50:40 +00:00
|
|
|
error:
|
2012-10-15 09:07:50 +00:00
|
|
|
virCPUDefFree(cpu);
|
|
|
|
cpu = NULL;
|
|
|
|
goto cleanup;
|
2011-10-03 12:56:20 +00:00
|
|
|
}
|
|
|
|
|
2014-11-20 10:08:21 +00:00
|
|
|
static int
|
2015-08-07 15:39:02 +00:00
|
|
|
ppc64DriverGetModels(char ***models)
|
2014-11-20 10:08:21 +00:00
|
|
|
{
|
2015-07-20 13:13:02 +00:00
|
|
|
struct ppc64_map *map;
|
2016-05-18 13:23:54 +00:00
|
|
|
size_t i;
|
|
|
|
int ret = -1;
|
2014-11-20 10:08:21 +00:00
|
|
|
|
2015-07-20 13:13:02 +00:00
|
|
|
if (!(map = ppc64LoadMap()))
|
2014-11-20 10:08:21 +00:00
|
|
|
goto error;
|
|
|
|
|
2016-05-18 13:23:54 +00:00
|
|
|
if (models) {
|
|
|
|
if (VIR_ALLOC_N(*models, map->nmodels + 1) < 0)
|
|
|
|
goto error;
|
2014-11-20 10:08:21 +00:00
|
|
|
|
2016-05-18 13:23:54 +00:00
|
|
|
for (i = 0; i < map->nmodels; i++) {
|
|
|
|
if (VIR_STRDUP((*models)[i], map->models[i]->name) < 0)
|
2014-12-03 17:50:16 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2014-11-20 10:08:21 +00:00
|
|
|
}
|
|
|
|
|
2016-05-18 13:23:54 +00:00
|
|
|
ret = map->nmodels;
|
|
|
|
|
2014-11-20 10:08:21 +00:00
|
|
|
cleanup:
|
2015-07-20 13:13:02 +00:00
|
|
|
ppc64MapFree(map);
|
2016-05-18 13:23:54 +00:00
|
|
|
return ret;
|
2014-11-20 10:08:21 +00:00
|
|
|
|
|
|
|
error:
|
2014-12-03 17:50:16 +00:00
|
|
|
if (models) {
|
|
|
|
virStringFreeList(*models);
|
|
|
|
*models = NULL;
|
|
|
|
}
|
2014-11-20 10:08:21 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-07-20 12:35:22 +00:00
|
|
|
struct cpuArchDriver cpuDriverPPC64 = {
|
2015-07-20 13:20:20 +00:00
|
|
|
.name = "ppc64",
|
|
|
|
.arch = archs,
|
|
|
|
.narch = ARRAY_CARDINALITY(archs),
|
2015-08-07 15:39:02 +00:00
|
|
|
.compare = ppc64DriverCompare,
|
|
|
|
.decode = ppc64DriverDecode,
|
2011-10-03 12:56:20 +00:00
|
|
|
.encode = NULL,
|
2015-08-07 15:39:02 +00:00
|
|
|
.free = ppc64DriverFree,
|
|
|
|
.nodeData = ppc64DriverNodeData,
|
|
|
|
.guestData = ppc64DriverGuestData,
|
|
|
|
.baseline = ppc64DriverBaseline,
|
|
|
|
.update = ppc64DriverUpdate,
|
2011-10-03 12:56:20 +00:00
|
|
|
.hasFeature = NULL,
|
2015-08-07 15:39:02 +00:00
|
|
|
.getModels = ppc64DriverGetModels,
|
2011-10-03 12:56:20 +00:00
|
|
|
};
|