diff --git a/po/POTFILES.in b/po/POTFILES.in
index 66779dd87e..97685287f1 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -26,6 +26,7 @@ src/conf/virconsole.c
src/cpu/cpu.c
src/cpu/cpu_generic.c
src/cpu/cpu_map.c
+src/cpu/cpu_powerpc.c
src/cpu/cpu_x86.c
src/datatypes.c
src/driver.c
diff --git a/src/cpu/cpu_map.xml b/src/cpu/cpu_map.xml
index 9a89e2efd1..affcce35ef 100644
--- a/src/cpu/cpu_map.xml
+++ b/src/cpu/cpu_map.xml
@@ -495,4 +495,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c
index 1b77caff32..911957217d 100644
--- a/src/cpu/cpu_powerpc.c
+++ b/src/cpu/cpu_powerpc.c
@@ -20,18 +20,531 @@
* Authors:
* Anton Blanchard
* Prerna Saxena
+ * Li Zhang
*/
#include
+#include
+#include "logging.h"
#include "memory.h"
+#include "util.h"
#include "cpu.h"
+#include "cpu_map.h"
+#include "buf.h"
#define VIR_FROM_THIS VIR_FROM_CPU
static const char *archs[] = { "ppc64" };
+struct cpuPowerPC {
+ const char *name;
+ const char *vendor;
+ uint32_t pvr;
+};
+
+static const struct cpuPowerPC cpu_defs[] = {
+ {"POWER7", "IBM", 0x003f0200},
+ {"POWER7_v2.1", "IBM", 0x003f0201},
+ {"POWER7_v2.3", "IBM", 0x003f0203},
+ {NULL, NULL, 0xffffffff}
+};
+
+
+struct ppc_vendor {
+ char *name;
+ struct ppc_vendor *next;
+};
+
+struct ppc_model {
+ char *name;
+ const struct ppc_vendor *vendor;
+ union cpuData *data;
+ struct ppc_model *next;
+};
+
+struct ppc_map {
+ struct ppc_vendor *vendors;
+ struct ppc_model *models;
+};
+
+static int
+ConvertModelVendorFromPVR(char ***model,
+ char ***vendor,
+ uint32_t pvr)
+{
+ int i;
+
+ for (i = 0; cpu_defs[i].name; i++) {
+ if (cpu_defs[i].pvr == pvr) {
+ **model = strdup(cpu_defs[i].name);
+ **vendor = strdup(cpu_defs[i].vendor);
+ return 0;
+ }
+ }
+
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing the definition of this model"));
+ return -1;
+}
+
+static int
+ConvertPVRFromModel(const char *model,
+ uint32_t *pvr)
+{
+ int i;
+
+ for (i = 0; cpu_defs[i].name; i++) {
+ if (STREQ(cpu_defs[i].name, model)) {
+ *pvr = cpu_defs[i].pvr;
+ return 0;
+ }
+ }
+
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing the definition of this model"));
+ return -1;
+}
+
+static int
+cpuMatch(const union cpuData *data,
+ char **cpu_model,
+ char **cpu_vendor,
+ const struct ppc_model *model)
+{
+ int ret = 0;
+
+ ret = ConvertModelVendorFromPVR(&cpu_model, &cpu_vendor, data->ppc.pvr);
+
+ if (STREQ(model->name, *cpu_model) &&
+ STREQ(model->vendor->name, *cpu_vendor))
+ ret = 1;
+
+ return ret;
+}
+
+
+static struct ppc_model *
+ppcModelNew(void)
+{
+ struct ppc_model *model;
+
+ if (VIR_ALLOC(model) < 0)
+ return NULL;
+
+ if (VIR_ALLOC(model->data) < 0) {
+ VIR_FREE(model);
+ return NULL;
+ }
+
+ return model;
+}
+
+static void
+ppcModelFree(struct ppc_model *model)
+{
+ if (model == NULL)
+ return;
+
+ VIR_FREE(model->name);
+
+ VIR_FREE(model->data);
+
+ 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_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 int
+ppcVendorLoad(xmlXPathContextPtr ctxt,
+ struct ppc_map *map)
+{
+ struct ppc_vendor *vendor = NULL;
+ char *string = NULL;
+ int ret = -1;
+
+ if (VIR_ALLOC(vendor) < 0)
+ goto no_memory;
+
+ 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;
+ }
+
+ string = virXPathString("string(@string)", ctxt);
+ if (!string) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Missing vendor string for CPU vendor %s"), vendor->name);
+ goto ignore;
+ }
+ if (!map->vendors)
+ map->vendors = vendor;
+ else {
+ vendor->next = map->vendors;
+ map->vendors = vendor;
+ }
+
+ ret = 0;
+
+out:
+ VIR_FREE(string);
+ return ret;
+
+no_memory:
+ virReportOOMError();
+
+ignore:
+ ppcVendorFree(vendor);
+ goto out;
+}
+
+static int
+ppcModelLoad(xmlXPathContextPtr ctxt,
+ struct ppc_map *map)
+{
+ xmlNodePtr *nodes = NULL;
+ struct ppc_model *model;
+ char *vendor = NULL;
+ int ret = -1;
+
+ if (!(model = ppcModelNew()))
+ goto no_memory;
+
+ model->name = virXPathString("string(@name)", ctxt);
+ if (model->name == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing CPU model name"));
+ goto ignore;
+ }
+
+ ret = ConvertPVRFromModel(model->name, &model->data->ppc.pvr);
+ if (ret < 0)
+ 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 (map->models == NULL)
+ map->models = model;
+ else {
+ model->next = map->models;
+ map->models = model;
+ }
+
+ ret = 0;
+
+out:
+ VIR_FREE(vendor);
+ VIR_FREE(nodes);
+ return ret;
+
+no_memory:
+ virReportOOMError();
+
+ignore:
+ ppcModelFree(model);
+ goto out;
+}
+
+static int
+ppcMapLoadCallback(enum 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);
+ default:
+ 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) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ if (cpuMapLoad("ppc64", ppcMapLoadCallback, map) < 0)
+ goto error;
+
+ return map;
+
+error:
+ ppcMapFree(map);
+ return NULL;
+}
+
+static struct ppc_model *
+ppcModelCopy(const struct ppc_model *model)
+{
+ struct ppc_model *copy;
+
+ if (VIR_ALLOC(copy) < 0
+ || VIR_ALLOC(copy->data) < 0
+ || !(copy->name = strdup(model->name))){
+ ppcModelFree(copy);
+ return NULL;
+ }
+
+ copy->data->ppc.pvr = model->data->ppc.pvr;
+ copy->vendor = model->vendor;
+
+ return copy;
+}
+
+static struct ppc_model *
+ppcModelFromCPU(const virCPUDefPtr cpu,
+ const struct ppc_map *map)
+{
+ struct ppc_model *model = NULL;
+
+ if ((model = ppcModelFind(map, cpu->model))) {
+ if ((model = ppcModelCopy(model)) == NULL) {
+ goto no_memory;
+ }
+ } else if (!(model = ppcModelNew())) {
+ goto no_memory;
+ }
+
+ return model;
+
+no_memory:
+ virReportOOMError();
+ ppcModelFree(model);
+
+ return NULL;
+}
+
+static virCPUCompareResult
+PowerPCCompare(virCPUDefPtr host,
+ virCPUDefPtr cpu)
+{
+ if ((cpu->arch && STRNEQ(host->arch, cpu->arch)) ||
+ STRNEQ(host->model, cpu->model))
+ return VIR_CPU_COMPARE_INCOMPATIBLE;
+
+ return VIR_CPU_COMPARE_IDENTICAL;
+}
+
+static int
+PowerPCDecode(virCPUDefPtr cpu,
+ const union cpuData *data,
+ const char **models,
+ unsigned int nmodels,
+ const char *preferred)
+{
+ int ret = -1;
+ struct ppc_map *map;
+ const struct ppc_model *candidate;
+ virCPUDefPtr cpuCandidate;
+ virCPUDefPtr cpuModel = NULL;
+ char *cpu_vendor = NULL;
+ char *cpu_model = NULL;
+ unsigned int i;
+
+ if (data == NULL || (map = ppcLoadMap()) == NULL)
+ return -1;
+
+ candidate = map->models;
+
+ while (candidate != NULL) {
+ bool allowed = (models == NULL);
+
+ for (i = 0; i < nmodels; i++) {
+ if (models && models[i] && STREQ(models[i], candidate->name)) {
+ allowed = true;
+ break;
+ }
+ }
+
+ if (!allowed) {
+ if (preferred && STREQ(candidate->name, preferred)) {
+ if (cpu->fallback != VIR_CPU_FALLBACK_ALLOW) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("CPU model %s is not supported by hypervisor"),
+ preferred);
+ goto out;
+ } else {
+ VIR_WARN("Preferred CPU model %s not allowed by"
+ " hypervisor; closest supported model will be"
+ " used", preferred);
+ }
+ } else {
+ VIR_DEBUG("CPU model %s not allowed by hypervisor; ignoring",
+ candidate->name);
+ }
+ goto next;
+ }
+
+ if (VIR_ALLOC(cpuCandidate) < 0) {
+ virReportOOMError();
+ goto out;
+ }
+
+ cpuCandidate->model = strdup(candidate->name);
+ cpuCandidate->vendor = strdup(candidate->vendor->name);
+
+ if (preferred && STREQ(cpuCandidate->model, preferred)) {
+ virCPUDefFree(cpuModel);
+ cpuModel = cpuCandidate;
+ break;
+ }
+
+ ret = cpuMatch(data, &cpu_model, &cpu_vendor, candidate);
+ if (ret < 0) {
+ VIR_FREE(cpuCandidate);
+ goto out;
+ }else if(ret == 1) {
+ cpuCandidate->model = cpu_model;
+ cpuCandidate->vendor = cpu_vendor;
+ virCPUDefFree(cpuModel);
+ cpuModel = cpuCandidate;
+ break;
+ }
+
+ virCPUDefFree(cpuCandidate);
+
+ next:
+ candidate = candidate->next;
+ }
+
+ if (cpuModel == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Cannot find suitable CPU model for given data"));
+ goto out;
+ }
+
+ cpu->model = cpuModel->model;
+ cpu->vendor = cpuModel->vendor;
+ VIR_FREE(cpuModel);
+
+ ret = 0;
+
+out:
+ ppcMapFree(map);
+ virCPUDefFree(cpuModel);
+
+ return ret;
+}
+
+#if defined(__powerpc__) || \
+ defined(__powerpc64__)
+static uint32_t ppc_mfpvr(void)
+{
+ uint32_t pvr;
+ asm ("mfpvr %0"
+ : "=r"(pvr));
+ return pvr;
+}
+#endif
+
+static void
+PowerPCDataFree(union cpuData *data)
+{
+ if (data == NULL)
+ return;
+
+ VIR_FREE(data);
+}
+
static union cpuData *
PowerPCNodeData(void)
{
@@ -42,40 +555,88 @@ PowerPCNodeData(void)
return NULL;
}
+#if defined(__powerpc__) || \
+ defined(__powerpc64__)
+ data->ppc.pvr = ppc_mfpvr();
+#endif
+
return data;
}
-
static int
-PowerPCDecode(virCPUDefPtr cpu ATTRIBUTE_UNUSED,
- const union cpuData *data ATTRIBUTE_UNUSED,
- const char **models ATTRIBUTE_UNUSED,
- unsigned int nmodels ATTRIBUTE_UNUSED,
- const char *preferred ATTRIBUTE_UNUSED)
+PowerPCUpdate(virCPUDefPtr guest ATTRIBUTE_UNUSED,
+ const virCPUDefPtr host ATTRIBUTE_UNUSED)
{
- return 0;
+ return 0;
}
-
-static void
-PowerPCDataFree(union cpuData *data)
+static virCPUDefPtr
+PowerPCBaseline(virCPUDefPtr *cpus,
+ unsigned int ncpus ATTRIBUTE_UNUSED,
+ const char **models ATTRIBUTE_UNUSED,
+ unsigned int nmodels ATTRIBUTE_UNUSED)
{
- if (data == NULL)
- return;
+ struct ppc_map *map = NULL;
+ struct ppc_model *base_model = NULL;
+ virCPUDefPtr cpu = NULL;
+ struct ppc_model *model = NULL;
+ bool outputModel = true;
- VIR_FREE(data);
+ if (!(map = ppcLoadMap())) {
+ goto error;
+ }
+
+ if (!(base_model = ppcModelFromCPU(cpus[0], map))) {
+ goto error;
+ }
+
+ if (VIR_ALLOC(cpu) < 0 ||
+ !(cpu->arch = strdup(cpus[0]->arch)))
+ goto no_memory;
+ cpu->type = VIR_CPU_TYPE_GUEST;
+ cpu->match = VIR_CPU_MATCH_EXACT;
+
+ if (!cpus[0]->model) {
+ outputModel = false;
+ } else if (!(model = ppcModelFind(map, cpus[0]->model))) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("Unknown CPU vendor %s"), cpus[0]->model);
+ goto error;
+ }
+
+ base_model->data->ppc.pvr = model->data->ppc.pvr;
+ if (PowerPCDecode(cpu, base_model->data, models, nmodels, NULL) < 0)
+ goto error;
+
+ if (!outputModel)
+ VIR_FREE(cpu->model);
+
+ VIR_FREE(cpu->arch);
+
+cleanup:
+ ppcModelFree(base_model);
+ ppcMapFree(map);
+
+ return cpu;
+no_memory:
+ virReportOOMError();
+error:
+ ppcModelFree(model);
+ virCPUDefFree(cpu);
+ cpu = NULL;
+ goto cleanup;
}
struct cpuArchDriver cpuDriverPowerPC = {
.name = "ppc64",
.arch = archs,
.narch = ARRAY_CARDINALITY(archs),
- .compare = NULL,
+ .compare = PowerPCCompare,
.decode = PowerPCDecode,
.encode = NULL,
.free = PowerPCDataFree,
.nodeData = PowerPCNodeData,
.guestData = NULL,
- .baseline = NULL,
- .update = NULL,
+ .baseline = PowerPCBaseline,
+ .update = PowerPCUpdate,
.hasFeature = NULL,
};