The driver only supports VIR_ARCH_PPC64 and VIR_ARCH_PPC64LE. Just shuffling files around and updating the build system accordingly. No functional changes. --- po/POTFILES.in | 2 +- src/Makefile.am | 5 +- src/cpu/cpu.c | 2 +- src/cpu/cpu.h | 2 +- src/cpu/cpu_powerpc.c | 711 ----------------------------------------------- src/cpu/cpu_powerpc.h | 32 --- src/cpu/cpu_ppc64.c | 711 +++++++++++++++++++++++++++++++++++++++++++++++ src/cpu/cpu_ppc64.h | 32 +++ src/cpu/cpu_ppc64_data.h | 33 +++ src/cpu/cpu_ppc_data.h | 33 --- 10 files changed, 782 insertions(+), 781 deletions(-) delete mode 100644 src/cpu/cpu_powerpc.c delete mode 100644 src/cpu/cpu_powerpc.h create mode 100644 src/cpu/cpu_ppc64.c create mode 100644 src/cpu/cpu_ppc64.h create mode 100644 src/cpu/cpu_ppc64_data.h delete mode 100644 src/cpu/cpu_ppc_data.h
diff --git a/po/POTFILES.in b/po/POTFILES.in index a75f5ae..c58a7c1 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -39,7 +39,7 @@ src/conf/virchrdev.c src/cpu/cpu.c src/cpu/cpu_generic.c src/cpu/cpu_map.c -src/cpu/cpu_powerpc.c +src/cpu/cpu_ppc64.c src/cpu/cpu_x86.c src/driver.c src/esx/esx_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index 7338ab9..c4d49a5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1008,8 +1008,9 @@ CPU_SOURCES = \ cpu/cpu_s390.h cpu/cpu_s390.c \ cpu/cpu_arm.h cpu/cpu_arm.c \ cpu/cpu_aarch64.h cpu/cpu_aarch64.c \ - cpu/cpu_map.h cpu/cpu_map.c cpu/cpu_powerpc.h \ - cpu/cpu_powerpc.c cpu/cpu_ppc_data.h + cpu/cpu_ppc64.h cpu/cpu_ppc64.c \ + cpu/cpu_ppc64_data.h \ + cpu/cpu_map.h cpu/cpu_map.c VMX_SOURCES = \ vmx/vmx.c vmx/vmx.h diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 9e67ddd..2e34f81 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -29,7 +29,7 @@ #include "cpu.h" #include "cpu_map.h" #include "cpu_x86.h" -#include "cpu_powerpc.h" +#include "cpu_ppc64.h" #include "cpu_s390.h" #include "cpu_arm.h" #include "cpu_aarch64.h" diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 09e9538..c0371cd 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -29,7 +29,7 @@ # include "virarch.h" # include "conf/cpu_conf.h" # include "cpu_x86_data.h" -# include "cpu_ppc_data.h" +# include "cpu_ppc64_data.h" typedef struct _virCPUData virCPUData; diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c deleted file mode 100644 index 733a0cd..0000000 --- a/src/cpu/cpu_powerpc.c +++ /dev/null @@ -1,711 +0,0 @@ -/* - * cpu_powerpc.c: CPU driver for PowerPC CPUs - * - * Copyright (C) 2013 Red Hat, Inc. - * Copyright (C) IBM Corporation, 2010 - * - * 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 - * License along with this library. If not, see - * <http://www.gnu.org/licenses/>. - * - * Authors: - * Anton Blanchard <an...@au.ibm.com> - * Prerna Saxena <pre...@linux.vnet.ibm.com> - * Li Zhang <zhlci...@linux.vnet.ibm.com> - */ - -#include <config.h> -#include <stdint.h> - -#include "virlog.h" -#include "viralloc.h" -#include "cpu.h" -#include "virstring.h" -#include "cpu_map.h" -#include "virbuffer.h" - -#define VIR_FROM_THIS VIR_FROM_CPU - -VIR_LOG_INIT("cpu.cpu_powerpc"); - -static const virArch archs[] = { VIR_ARCH_PPC64, VIR_ARCH_PPC64LE }; - -struct ppc_vendor { - char *name; - struct ppc_vendor *next; -}; - -struct ppc_model { - char *name; - const struct ppc_vendor *vendor; - struct cpuPPCData data; - 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; -} - -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; - } - - /* PowerPC Processor Version Register is interpreted as follows : - * Higher order 16 bits : Power ISA generation. - * Lower order 16 bits : CPU chip version number. - * If the exact CPU isn't found, return the nearest matching CPU generation - */ - if (pvr & 0x0000FFFFul) - return ppcModelFindPVR(map, (pvr & 0xFFFF0000ul)); - - return NULL; -} - -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; -} - -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); -} - -static struct ppc_model * -ppcModelFromCPU(const virCPUDef *cpu, - 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; - - error: - ppcModelFree(model); - return NULL; -} - - -static int -ppcVendorLoad(xmlXPathContextPtr ctxt, - struct ppc_map *map) -{ - struct ppc_vendor *vendor = NULL; - - if (VIR_ALLOC(vendor) < 0) - return -1; - - 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; - } - - if (!map->vendors) { - map->vendors = vendor; - } else { - vendor->next = map->vendors; - map->vendors = vendor; - } - - cleanup: - return 0; - - ignore: - ppcVendorFree(vendor); - goto cleanup; -} - -static int -ppcModelLoad(xmlXPathContextPtr ctxt, - struct ppc_map *map) -{ - struct ppc_model *model; - char *vendor = NULL; - unsigned long pvr; - - if (VIR_ALLOC(model) < 0) - return -1; - - model->name = virXPathString("string(@name)", ctxt); - if (!model->name) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Missing CPU model name")); - goto ignore; - } - - if (ppcModelFind(map, model->name)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("CPU model %s already defined"), model->name); - goto ignore; - } - - 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; - } - } - - 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) { - map->models = model; - } else { - model->next = map->models; - map->models = model; - } - - cleanup: - VIR_FREE(vendor); - return 0; - - ignore: - ppcModelFree(model); - goto cleanup; -} - -static int -ppcMapLoadCallback(cpuMapElement element, - 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); - case CPU_MAP_ELEMENT_FEATURE: - case CPU_MAP_ELEMENT_LAST: - 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; - - if (VIR_ALLOC(map) < 0) - return NULL; - - if (cpuMapLoad("ppc64", ppcMapLoadCallback, map) < 0) - goto error; - - return map; - - error: - ppcMapFree(map); - return NULL; -} - -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, - const virCPUDef *cpu, - virCPUDataPtr *guestData, - char **message) - -{ - struct ppc_map *map = NULL; - struct ppc_model *host_model = NULL; - struct ppc_model *guest_model = NULL; - - virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR; - 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) - goto cleanup; - - ret = VIR_CPU_COMPARE_INCOMPATIBLE; - goto cleanup; - } - 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) - goto cleanup; - - ret = VIR_CPU_COMPARE_INCOMPATIBLE; - goto cleanup; - } - - if (!(map = ppcLoadMap()) || - !(host_model = ppcModelFromCPU(host, map)) || - !(guest_model = ppcModelFromCPU(cpu, map))) - goto cleanup; - - 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) - goto cleanup; - - ret = VIR_CPU_COMPARE_INCOMPATIBLE; - goto cleanup; - } - - if (!(*guestData = ppcMakeCPUData(arch, &guest_model->data))) - goto cleanup; - } - - ret = VIR_CPU_COMPARE_IDENTICAL; - - cleanup: - ppcMapFree(map); - ppcModelFree(host_model); - ppcModelFree(guest_model); - return ret; -} - -static virCPUCompareResult -ppcCompare(virCPUDefPtr host, - virCPUDefPtr cpu, - bool failIncompatible) -{ - if ((cpu->arch == VIR_ARCH_NONE || host->arch == cpu->arch) && - STREQ(host->model, cpu->model)) - return VIR_CPU_COMPARE_IDENTICAL; - - if (failIncompatible) { - virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL); - return VIR_CPU_COMPARE_ERROR; - } else { - return VIR_CPU_COMPARE_INCOMPATIBLE; - } -} - -static int -ppcDecode(virCPUDefPtr cpu, - const virCPUData *data, - const char **models, - unsigned int nmodels, - const char *preferred ATTRIBUTE_UNUSED, - unsigned int flags) -{ - int ret = -1; - struct ppc_map *map; - const struct ppc_model *model; - - virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1); - - if (data == NULL || (map = ppcLoadMap()) == NULL) - return -1; - - if (!(model = ppcModelFindPVR(map, data->data.ppc.pvr))) { - virReportError(VIR_ERR_OPERATION_FAILED, - _("Cannot find CPU model with PVR 0x%08x"), - data->data.ppc.pvr); - goto cleanup; - } - - if (!cpuModelIsAllowed(model->name, models, nmodels)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("CPU model %s is not supported by hypervisor"), - model->name); - goto cleanup; - } - - if (VIR_STRDUP(cpu->model, model->name) < 0 || - (model->vendor && VIR_STRDUP(cpu->vendor, model->vendor->name) < 0)) { - goto cleanup; - } - - ret = 0; - - cleanup: - ppcMapFree(map); - - return ret; -} - - -static void -ppcDataFree(virCPUDataPtr data) -{ - if (data == NULL) - return; - - VIR_FREE(data); -} - -static virCPUDataPtr -ppcNodeData(virArch arch) -{ - virCPUDataPtr cpuData; - - if (VIR_ALLOC(cpuData) < 0) - return NULL; - - cpuData->arch = arch; - -#if defined(__powerpc__) || defined(__powerpc64__) - asm("mfpvr %0" - : "=r" (cpuData->data.ppc.pvr)); -#endif - - return cpuData; -} - -static virCPUCompareResult -ppcGuestData(virCPUDefPtr host, - virCPUDefPtr guest, - virCPUDataPtr *data, - char **message) -{ - return ppcCompute(host, guest, data, message); -} - -static int -ppcUpdate(virCPUDefPtr guest, - const virCPUDef *host) -{ - switch ((virCPUMode) guest->mode) { - 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; -} - -static virCPUDefPtr -ppcBaseline(virCPUDefPtr *cpus, - unsigned int ncpus, - const char **models ATTRIBUTE_UNUSED, - unsigned int nmodels ATTRIBUTE_UNUSED, - unsigned int flags) -{ - struct ppc_map *map = NULL; - const struct ppc_model *model; - const struct ppc_vendor *vendor = NULL; - virCPUDefPtr cpu = NULL; - size_t i; - - virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES | - VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL); - - if (!(map = ppcLoadMap())) - goto error; - - if (!(model = ppcModelFind(map, cpus[0]->model))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown CPU model %s"), cpus[0]->model); - goto error; - } - - for (i = 0; i < ncpus; i++) { - const struct ppc_vendor *vnd; - - if (STRNEQ(cpus[i]->model, model->name)) { - virReportError(VIR_ERR_OPERATION_FAILED, "%s", - _("CPUs are incompatible")); - goto error; - } - - 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; - } - } - - if (VIR_ALLOC(cpu) < 0 || - VIR_STRDUP(cpu->model, model->name) < 0) - goto error; - - if (vendor && VIR_STRDUP(cpu->vendor, vendor->name) < 0) - goto error; - - cpu->type = VIR_CPU_TYPE_GUEST; - cpu->match = VIR_CPU_MATCH_EXACT; - - cleanup: - ppcMapFree(map); - - return cpu; - - error: - virCPUDefFree(cpu); - cpu = NULL; - goto cleanup; -} - -static int -ppcGetModels(char ***models) -{ - struct ppc_map *map; - struct ppc_model *model; - char *name; - size_t nmodels = 0; - - if (!(map = ppcLoadMap())) - goto error; - - if (models && VIR_ALLOC_N(*models, 0) < 0) - goto error; - - model = map->models; - while (model != NULL) { - if (models) { - if (VIR_STRDUP(name, model->name) < 0) - goto error; - - if (VIR_APPEND_ELEMENT(*models, nmodels, name) < 0) - goto error; - } else { - nmodels++; - } - - model = model->next; - } - - cleanup: - ppcMapFree(map); - - return nmodels; - - error: - if (models) { - virStringFreeList(*models); - *models = NULL; - } - nmodels = -1; - goto cleanup; -} - -struct cpuArchDriver cpuDriverPowerPC = { - .name = "ppc64", - .arch = archs, - .narch = ARRAY_CARDINALITY(archs), - .compare = ppcCompare, - .decode = ppcDecode, - .encode = NULL, - .free = ppcDataFree, - .nodeData = ppcNodeData, - .guestData = ppcGuestData, - .baseline = ppcBaseline, - .update = ppcUpdate, - .hasFeature = NULL, - .getModels = ppcGetModels, -}; diff --git a/src/cpu/cpu_powerpc.h b/src/cpu/cpu_powerpc.h deleted file mode 100644 index 312886e..0000000 --- a/src/cpu/cpu_powerpc.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * cpu_powerpc.h: CPU driver for PowerPC CPUs - * - * Copyright (C) Copyright (C) IBM Corporation, 2010 - * - * 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 - * License along with this library. If not, see - * <http://www.gnu.org/licenses/>. - * - * Authors: - * Anton Blanchard <an...@au.ibm.com> - * Prerna Saxena <pre...@linux.vnet.ibm.com> - */ - -#ifndef __VIR_CPU_POWERPC_H__ -# define __VIR_CPU_POWERPC_H__ - -# include "cpu.h" - -extern struct cpuArchDriver cpuDriverPowerPC; - -#endif /* __VIR_CPU_POWERPC_H__ */ diff --git a/src/cpu/cpu_ppc64.c b/src/cpu/cpu_ppc64.c new file mode 100644 index 0000000..7866bdd --- /dev/null +++ b/src/cpu/cpu_ppc64.c @@ -0,0 +1,711 @@ +/* + * cpu_ppc64.c: CPU driver for PowerPC CPUs + * + * Copyright (C) 2013 Red Hat, Inc. + * Copyright (C) IBM Corporation, 2010 + * + * 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 + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Anton Blanchard <an...@au.ibm.com> + * Prerna Saxena <pre...@linux.vnet.ibm.com> + * Li Zhang <zhlci...@linux.vnet.ibm.com> + */ + +#include <config.h> +#include <stdint.h> + +#include "virlog.h" +#include "viralloc.h" +#include "cpu.h" +#include "virstring.h" +#include "cpu_map.h" +#include "virbuffer.h" + +#define VIR_FROM_THIS VIR_FROM_CPU + +VIR_LOG_INIT("cpu.cpu_powerpc"); + +static const virArch archs[] = { VIR_ARCH_PPC64, VIR_ARCH_PPC64LE }; + +struct ppc_vendor { + char *name; + struct ppc_vendor *next; +}; + +struct ppc_model { + char *name; + const struct ppc_vendor *vendor; + struct cpuPPCData data; + 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; +} + +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; + } + + /* PowerPC Processor Version Register is interpreted as follows : + * Higher order 16 bits : Power ISA generation. + * Lower order 16 bits : CPU chip version number. + * If the exact CPU isn't found, return the nearest matching CPU generation + */ + if (pvr & 0x0000FFFFul) + return ppcModelFindPVR(map, (pvr & 0xFFFF0000ul)); + + return NULL; +} + +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; +} + +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); +} + +static struct ppc_model * +ppcModelFromCPU(const virCPUDef *cpu, + 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; + + error: + ppcModelFree(model); + return NULL; +} + + +static int +ppcVendorLoad(xmlXPathContextPtr ctxt, + struct ppc_map *map) +{ + struct ppc_vendor *vendor = NULL; + + if (VIR_ALLOC(vendor) < 0) + return -1; + + 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; + } + + if (!map->vendors) { + map->vendors = vendor; + } else { + vendor->next = map->vendors; + map->vendors = vendor; + } + + cleanup: + return 0; + + ignore: + ppcVendorFree(vendor); + goto cleanup; +} + +static int +ppcModelLoad(xmlXPathContextPtr ctxt, + struct ppc_map *map) +{ + struct ppc_model *model; + char *vendor = NULL; + unsigned long pvr; + + if (VIR_ALLOC(model) < 0) + return -1; + + model->name = virXPathString("string(@name)", ctxt); + if (!model->name) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Missing CPU model name")); + goto ignore; + } + + if (ppcModelFind(map, model->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("CPU model %s already defined"), model->name); + goto ignore; + } + + 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; + } + } + + 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) { + map->models = model; + } else { + model->next = map->models; + map->models = model; + } + + cleanup: + VIR_FREE(vendor); + return 0; + + ignore: + ppcModelFree(model); + goto cleanup; +} + +static int +ppcMapLoadCallback(cpuMapElement element, + 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); + case CPU_MAP_ELEMENT_FEATURE: + case CPU_MAP_ELEMENT_LAST: + 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; + + if (VIR_ALLOC(map) < 0) + return NULL; + + if (cpuMapLoad("ppc64", ppcMapLoadCallback, map) < 0) + goto error; + + return map; + + error: + ppcMapFree(map); + return NULL; +} + +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, + const virCPUDef *cpu, + virCPUDataPtr *guestData, + char **message) + +{ + struct ppc_map *map = NULL; + struct ppc_model *host_model = NULL; + struct ppc_model *guest_model = NULL; + + virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR; + 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) + goto cleanup; + + ret = VIR_CPU_COMPARE_INCOMPATIBLE; + goto cleanup; + } + 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) + goto cleanup; + + ret = VIR_CPU_COMPARE_INCOMPATIBLE; + goto cleanup; + } + + if (!(map = ppcLoadMap()) || + !(host_model = ppcModelFromCPU(host, map)) || + !(guest_model = ppcModelFromCPU(cpu, map))) + goto cleanup; + + 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) + goto cleanup; + + ret = VIR_CPU_COMPARE_INCOMPATIBLE; + goto cleanup; + } + + if (!(*guestData = ppcMakeCPUData(arch, &guest_model->data))) + goto cleanup; + } + + ret = VIR_CPU_COMPARE_IDENTICAL; + + cleanup: + ppcMapFree(map); + ppcModelFree(host_model); + ppcModelFree(guest_model); + return ret; +} + +static virCPUCompareResult +ppcCompare(virCPUDefPtr host, + virCPUDefPtr cpu, + bool failIncompatible) +{ + if ((cpu->arch == VIR_ARCH_NONE || host->arch == cpu->arch) && + STREQ(host->model, cpu->model)) + return VIR_CPU_COMPARE_IDENTICAL; + + if (failIncompatible) { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL); + return VIR_CPU_COMPARE_ERROR; + } else { + return VIR_CPU_COMPARE_INCOMPATIBLE; + } +} + +static int +ppcDecode(virCPUDefPtr cpu, + const virCPUData *data, + const char **models, + unsigned int nmodels, + const char *preferred ATTRIBUTE_UNUSED, + unsigned int flags) +{ + int ret = -1; + struct ppc_map *map; + const struct ppc_model *model; + + virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1); + + if (data == NULL || (map = ppcLoadMap()) == NULL) + return -1; + + if (!(model = ppcModelFindPVR(map, data->data.ppc.pvr))) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Cannot find CPU model with PVR 0x%08x"), + data->data.ppc.pvr); + goto cleanup; + } + + if (!cpuModelIsAllowed(model->name, models, nmodels)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("CPU model %s is not supported by hypervisor"), + model->name); + goto cleanup; + } + + if (VIR_STRDUP(cpu->model, model->name) < 0 || + (model->vendor && VIR_STRDUP(cpu->vendor, model->vendor->name) < 0)) { + goto cleanup; + } + + ret = 0; + + cleanup: + ppcMapFree(map); + + return ret; +} + + +static void +ppcDataFree(virCPUDataPtr data) +{ + if (data == NULL) + return; + + VIR_FREE(data); +} + +static virCPUDataPtr +ppcNodeData(virArch arch) +{ + virCPUDataPtr cpuData; + + if (VIR_ALLOC(cpuData) < 0) + return NULL; + + cpuData->arch = arch; + +#if defined(__powerpc__) || defined(__powerpc64__) + asm("mfpvr %0" + : "=r" (cpuData->data.ppc.pvr)); +#endif + + return cpuData; +} + +static virCPUCompareResult +ppcGuestData(virCPUDefPtr host, + virCPUDefPtr guest, + virCPUDataPtr *data, + char **message) +{ + return ppcCompute(host, guest, data, message); +} + +static int +ppcUpdate(virCPUDefPtr guest, + const virCPUDef *host) +{ + switch ((virCPUMode) guest->mode) { + 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; +} + +static virCPUDefPtr +ppcBaseline(virCPUDefPtr *cpus, + unsigned int ncpus, + const char **models ATTRIBUTE_UNUSED, + unsigned int nmodels ATTRIBUTE_UNUSED, + unsigned int flags) +{ + struct ppc_map *map = NULL; + const struct ppc_model *model; + const struct ppc_vendor *vendor = NULL; + virCPUDefPtr cpu = NULL; + size_t i; + + virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES | + VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL); + + if (!(map = ppcLoadMap())) + goto error; + + if (!(model = ppcModelFind(map, cpus[0]->model))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown CPU model %s"), cpus[0]->model); + goto error; + } + + for (i = 0; i < ncpus; i++) { + const struct ppc_vendor *vnd; + + if (STRNEQ(cpus[i]->model, model->name)) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("CPUs are incompatible")); + goto error; + } + + 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; + } + } + + if (VIR_ALLOC(cpu) < 0 || + VIR_STRDUP(cpu->model, model->name) < 0) + goto error; + + if (vendor && VIR_STRDUP(cpu->vendor, vendor->name) < 0) + goto error; + + cpu->type = VIR_CPU_TYPE_GUEST; + cpu->match = VIR_CPU_MATCH_EXACT; + + cleanup: + ppcMapFree(map); + + return cpu; + + error: + virCPUDefFree(cpu); + cpu = NULL; + goto cleanup; +} + +static int +ppcGetModels(char ***models) +{ + struct ppc_map *map; + struct ppc_model *model; + char *name; + size_t nmodels = 0; + + if (!(map = ppcLoadMap())) + goto error; + + if (models && VIR_ALLOC_N(*models, 0) < 0) + goto error; + + model = map->models; + while (model != NULL) { + if (models) { + if (VIR_STRDUP(name, model->name) < 0) + goto error; + + if (VIR_APPEND_ELEMENT(*models, nmodels, name) < 0) + goto error; + } else { + nmodels++; + } + + model = model->next; + } + + cleanup: + ppcMapFree(map); + + return nmodels; + + error: + if (models) { + virStringFreeList(*models); + *models = NULL; + } + nmodels = -1; + goto cleanup; +} + +struct cpuArchDriver cpuDriverPowerPC = { + .name = "ppc64", + .arch = archs, + .narch = ARRAY_CARDINALITY(archs), + .compare = ppcCompare, + .decode = ppcDecode, + .encode = NULL, + .free = ppcDataFree, + .nodeData = ppcNodeData, + .guestData = ppcGuestData, + .baseline = ppcBaseline, + .update = ppcUpdate, + .hasFeature = NULL, + .getModels = ppcGetModels, +}; diff --git a/src/cpu/cpu_ppc64.h b/src/cpu/cpu_ppc64.h new file mode 100644 index 0000000..e9ef2be --- /dev/null +++ b/src/cpu/cpu_ppc64.h @@ -0,0 +1,32 @@ +/* + * cpu_ppc64.h: CPU driver for PowerPC CPUs + * + * Copyright (C) Copyright (C) IBM Corporation, 2010 + * + * 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 + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Anton Blanchard <an...@au.ibm.com> + * Prerna Saxena <pre...@linux.vnet.ibm.com> + */ + +#ifndef __VIR_CPU_POWERPC_H__ +# define __VIR_CPU_POWERPC_H__ + +# include "cpu.h" + +extern struct cpuArchDriver cpuDriverPowerPC; + +#endif /* __VIR_CPU_POWERPC_H__ */ diff --git a/src/cpu/cpu_ppc64_data.h b/src/cpu/cpu_ppc64_data.h new file mode 100644 index 0000000..a70b099 --- /dev/null +++ b/src/cpu/cpu_ppc64_data.h @@ -0,0 +1,33 @@ +/* + * cpu_ppc64_data.h: PowerPC specific CPU data + * + * Copyright (C) 2012 IBM Corporation. + * + * 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 + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Li Zhang <zhlci...@linux.vnet.ibm.com> + */ + +#ifndef __VIR_CPU_PPC_DATA_H__ +# define __VIR_CPU_PPC_DATA_H__ + +# include <stdint.h> + +struct cpuPPCData { + uint32_t pvr; +}; + +#endif /* __VIR_CPU_PPC_DATA_H__ */ diff --git a/src/cpu/cpu_ppc_data.h b/src/cpu/cpu_ppc_data.h deleted file mode 100644 index 685332a..0000000 --- a/src/cpu/cpu_ppc_data.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * cpu_ppc_data.h: PowerPC specific CPU data - * - * Copyright (C) 2012 IBM Corporation. - * - * 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 - * License along with this library; If not, see - * <http://www.gnu.org/licenses/>. - * - * Authors: - * Li Zhang <zhlci...@linux.vnet.ibm.com> - */ - -#ifndef __VIR_CPU_PPC_DATA_H__ -# define __VIR_CPU_PPC_DATA_H__ - -# include <stdint.h> - -struct cpuPPCData { - uint32_t pvr; -}; - -#endif /* __VIR_CPU_PPC_DATA_H__ */ -- 2.4.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list