650 lines
15 KiB
Diff
650 lines
15 KiB
Diff
|
|
From 2dc7c9bc3dc24d991834f7657cd65cf4b5774ff8 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Xu Yandong <xuyandong2@huawei.com>
|
||
|
|
Date: Wed, 14 Aug 2019 21:33:37 +0800
|
||
|
|
Subject: [PATCH] cpu: introduce cpu baseline for ARM CPU
|
||
|
|
|
||
|
|
support vendor and model for ARM CPU
|
||
|
|
|
||
|
|
Signed-off-by: Xu Yandong <xuyandong2.huawei.com>
|
||
|
|
---
|
||
|
|
src/cpu/cpu_arm.c | 610 ++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
|
1 file changed, 610 insertions(+)
|
||
|
|
|
||
|
|
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
|
||
|
|
index 65d69c0..0c8cd50 100644
|
||
|
|
--- a/src/cpu/cpu_arm.c
|
||
|
|
+++ b/src/cpu/cpu_arm.c
|
||
|
|
@@ -21,12 +21,23 @@
|
||
|
|
|
||
|
|
#include <config.h>
|
||
|
|
|
||
|
|
+#include "virlog.h"
|
||
|
|
#include "viralloc.h"
|
||
|
|
#include "cpu.h"
|
||
|
|
#include "virstring.h"
|
||
|
|
+#include "cpu_map.h"
|
||
|
|
+#include "cpu_arm.h"
|
||
|
|
+#include "virfile.h"
|
||
|
|
|
||
|
|
#define VIR_FROM_THIS VIR_FROM_CPU
|
||
|
|
|
||
|
|
+VIR_LOG_INIT("cpu.cpu_arm");
|
||
|
|
+
|
||
|
|
+static const char *sysinfoCpuinfo = "/proc/cpuinfo";
|
||
|
|
+
|
||
|
|
+#define CPUINFO sysinfoCpuinfo
|
||
|
|
+#define CPUINFO_FILE_LEN (1024*1024) /* 1MB limit for /proc/cpuinfo file */
|
||
|
|
+
|
||
|
|
static const virArch archs[] = {
|
||
|
|
VIR_ARCH_ARMV6L,
|
||
|
|
VIR_ARCH_ARMV7B,
|
||
|
|
@@ -34,6 +45,605 @@ static const virArch archs[] = {
|
||
|
|
VIR_ARCH_AARCH64,
|
||
|
|
};
|
||
|
|
|
||
|
|
+typedef struct _virCPUarmVendor virCPUarmVendor;
|
||
|
|
+typedef virCPUarmVendor *virCPUarmVendorPtr;
|
||
|
|
+struct _virCPUarmVendor {
|
||
|
|
+ char *name;
|
||
|
|
+ unsigned long value;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+typedef struct _virCPUarmModel virCPUarmModel;
|
||
|
|
+typedef virCPUarmModel *virCPUarmModelPtr;
|
||
|
|
+struct _virCPUarmModel {
|
||
|
|
+ char *name;
|
||
|
|
+ virCPUarmVendorPtr vendor;
|
||
|
|
+ virCPUarmData data;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+typedef struct _virCPUarmMap virCPUarmMap;
|
||
|
|
+typedef virCPUarmMap *virCPUarmMapPtr;
|
||
|
|
+struct _virCPUarmMap {
|
||
|
|
+ size_t nvendors;
|
||
|
|
+ virCPUarmVendorPtr *vendors;
|
||
|
|
+ size_t nmodels;
|
||
|
|
+ virCPUarmModelPtr *models;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+static virCPUarmMapPtr cpuMap;
|
||
|
|
+
|
||
|
|
+int virCPUarmDriverOnceInit(void);
|
||
|
|
+VIR_ONCE_GLOBAL_INIT(virCPUarmDriver);
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+virCPUarmDataClear(virCPUarmData *data)
|
||
|
|
+{
|
||
|
|
+ if (!data)
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ VIR_FREE(data->features);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static int
|
||
|
|
+armDataCopy(virCPUarmData *dst, const virCPUarmData *src)
|
||
|
|
+{
|
||
|
|
+ if (VIR_STRDUP(dst->features, src->features) < 0)
|
||
|
|
+ return -1;
|
||
|
|
+
|
||
|
|
+ dst->vendor_id = src->vendor_id;
|
||
|
|
+ dst->pvr = src->pvr;
|
||
|
|
+
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+armDataIntersect(virCPUarmData *data1,
|
||
|
|
+ const virCPUarmData *data2)
|
||
|
|
+{
|
||
|
|
+ char **features = NULL;
|
||
|
|
+ char **features1 = NULL;
|
||
|
|
+ char **features2 = NULL;
|
||
|
|
+ size_t count = 0;
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ if (!data1 || !data2)
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ data1->pvr = MIN(data1->pvr, data2->pvr);
|
||
|
|
+
|
||
|
|
+ if (virStringIsEmpty(data1->features) ||
|
||
|
|
+ virStringIsEmpty(data2->features)) {
|
||
|
|
+ VIR_FREE(data1->features);
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (STREQ_NULLABLE(data1->features, data2->features))
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ if (!(features = virStringSplitCount(data1->features, " ", 0, &count)) ||
|
||
|
|
+ !(features1 = virStringSplitCount(data1->features, " ", 0, &count)) ||
|
||
|
|
+ !(features2 = virStringSplit(data2->features, " ", 0)))
|
||
|
|
+ goto cleanup;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < count; i++) {
|
||
|
|
+ if (!virStringListHasString((const char**)features2, features1[i]))
|
||
|
|
+ virStringListRemove(&features, features1[i]);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ VIR_FREE(data1->features);
|
||
|
|
+ if (features)
|
||
|
|
+ data1->features = virStringListJoin((const char**)features, " ");
|
||
|
|
+
|
||
|
|
+ cleanup:
|
||
|
|
+ virStringListFree(features);
|
||
|
|
+ virStringListFree(features1);
|
||
|
|
+ virStringListFree(features2);
|
||
|
|
+ return;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+virCPUarmDataFree(virCPUDataPtr cpuData)
|
||
|
|
+{
|
||
|
|
+ if (!cpuData)
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ virCPUarmDataClear(&cpuData->data.arm);
|
||
|
|
+ VIR_FREE(cpuData);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static bool
|
||
|
|
+armFeaturesIsSub(char *subFeatures,
|
||
|
|
+ char *fullFeatures)
|
||
|
|
+{
|
||
|
|
+ bool ret = false;
|
||
|
|
+ char **sub = NULL;
|
||
|
|
+ char **full = NULL;
|
||
|
|
+ size_t subCount = 0;
|
||
|
|
+ size_t fullCount = 0;
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ if (virStringIsEmpty(subFeatures))
|
||
|
|
+ return true;
|
||
|
|
+
|
||
|
|
+ if (virStringIsEmpty(fullFeatures))
|
||
|
|
+ return ret;
|
||
|
|
+
|
||
|
|
+ if (STREQ(subFeatures, fullFeatures))
|
||
|
|
+ return true;
|
||
|
|
+
|
||
|
|
+ if (!(sub = virStringSplitCount(subFeatures, " ", 0, &subCount)) ||
|
||
|
|
+ !(full = virStringSplitCount(fullFeatures, " ", 0, &fullCount)) ||
|
||
|
|
+ subCount > fullCount)
|
||
|
|
+ goto cleanup;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < subCount; i++) {
|
||
|
|
+ if (!virStringListHasString((const char**)full, sub[i]))
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ret = true;
|
||
|
|
+
|
||
|
|
+ cleanup:
|
||
|
|
+ virStringListFree(sub);
|
||
|
|
+ virStringListFree(full);
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+armVendorFree(virCPUarmVendorPtr vendor)
|
||
|
|
+{
|
||
|
|
+ if (!vendor)
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ VIR_FREE(vendor->name);
|
||
|
|
+ VIR_FREE(vendor);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static virCPUarmVendorPtr
|
||
|
|
+armVendorFindByID(virCPUarmMapPtr map,
|
||
|
|
+ unsigned long vendor_id)
|
||
|
|
+{
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < map->nvendors; i++) {
|
||
|
|
+ if (map->vendors[i]->value == vendor_id)
|
||
|
|
+ return map->vendors[i];
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return NULL;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static virCPUarmVendorPtr
|
||
|
|
+armVendorFindByName(virCPUarmMapPtr map,
|
||
|
|
+ const char *name)
|
||
|
|
+{
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < map->nvendors; i++) {
|
||
|
|
+ if (STREQ(map->vendors[i]->name, name))
|
||
|
|
+ return map->vendors[i];
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return NULL;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static int
|
||
|
|
+armVendorParse(xmlXPathContextPtr ctxt,
|
||
|
|
+ const char *name,
|
||
|
|
+ void *data)
|
||
|
|
+{
|
||
|
|
+ virCPUarmMapPtr map = (virCPUarmMapPtr)data;
|
||
|
|
+ virCPUarmVendorPtr vendor = NULL;
|
||
|
|
+ int ret = -1;
|
||
|
|
+
|
||
|
|
+ if (VIR_ALLOC(vendor) < 0)
|
||
|
|
+ return ret;
|
||
|
|
+
|
||
|
|
+ if (VIR_STRDUP(vendor->name, name) < 0)
|
||
|
|
+ goto cleanup;
|
||
|
|
+
|
||
|
|
+ if (armVendorFindByName(map, vendor->name)) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
||
|
|
+ _("CPU vendor %s already defined"), vendor->name);
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (virXPathULongHex("string(@value)", ctxt, &vendor->value) < 0) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
||
|
|
+ "%s", _("Missing CPU vendor value"));
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (armVendorFindByID(map, vendor->value)) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
||
|
|
+ _("CPU vendor value 0x%2lx already defined"), vendor->value);
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (VIR_APPEND_ELEMENT(map->vendors, map->nvendors, vendor) < 0)
|
||
|
|
+ goto cleanup;
|
||
|
|
+
|
||
|
|
+ ret = 0;
|
||
|
|
+
|
||
|
|
+ cleanup:
|
||
|
|
+ armVendorFree(vendor);
|
||
|
|
+ return ret;
|
||
|
|
+
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+armModelFree(virCPUarmModelPtr model)
|
||
|
|
+{
|
||
|
|
+ if (!model)
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ virCPUarmDataClear(&model->data);
|
||
|
|
+ VIR_FREE(model->name);
|
||
|
|
+ VIR_FREE(model);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static virCPUarmModelPtr
|
||
|
|
+armModelCopy(virCPUarmModelPtr model)
|
||
|
|
+{
|
||
|
|
+ virCPUarmModelPtr copy;
|
||
|
|
+
|
||
|
|
+ if (VIR_ALLOC(copy) < 0)
|
||
|
|
+ goto cleanup;
|
||
|
|
+
|
||
|
|
+ if (VIR_STRDUP(copy->name, model->name) < 0)
|
||
|
|
+ goto cleanup;
|
||
|
|
+
|
||
|
|
+ if (armDataCopy(©->data, &model->data) < 0)
|
||
|
|
+ goto cleanup;
|
||
|
|
+
|
||
|
|
+ copy->vendor = model->vendor;
|
||
|
|
+
|
||
|
|
+ return copy;
|
||
|
|
+
|
||
|
|
+ cleanup:
|
||
|
|
+ armModelFree(copy);
|
||
|
|
+ return NULL;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static virCPUarmModelPtr
|
||
|
|
+armModelFind(virCPUarmMapPtr map,
|
||
|
|
+ const char *name)
|
||
|
|
+{
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < map->nmodels; i++) {
|
||
|
|
+ if (STREQ(map->models[i]->name, name))
|
||
|
|
+ return map->models[i];
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return NULL;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static virCPUarmModelPtr
|
||
|
|
+armModelFindByPVR(virCPUarmMapPtr map,
|
||
|
|
+ unsigned long pvr)
|
||
|
|
+{
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < map->nmodels; i++) {
|
||
|
|
+ if (map->models[i]->data.pvr == pvr)
|
||
|
|
+ return map->models[i];
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return NULL;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static virCPUarmModelPtr
|
||
|
|
+armModelFromCPU(const virCPUDef *cpu,
|
||
|
|
+ virCPUarmMapPtr map)
|
||
|
|
+{
|
||
|
|
+ virCPUarmModelPtr model = NULL;
|
||
|
|
+ virCPUarmVendorPtr vendor = NULL;
|
||
|
|
+ char **features = NULL;
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ if (!cpu->model) {
|
||
|
|
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
|
||
|
|
+ _("no CPU model specified"));
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!(model = armModelFind(map, cpu->model))) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
||
|
|
+ _("Unknown CPU model %s"), cpu->model);
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!(model = armModelCopy(model)))
|
||
|
|
+ goto cleanup;
|
||
|
|
+
|
||
|
|
+ if (cpu->vendor) {
|
||
|
|
+ if (!(vendor = armVendorFindByName(map, cpu->vendor))) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
||
|
|
+ _("Unknown CPU vendor %s"), cpu->vendor);
|
||
|
|
+ goto error;
|
||
|
|
+ }
|
||
|
|
+ model->data.vendor_id = vendor->value;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (cpu->nfeatures) {
|
||
|
|
+ if (VIR_REALLOC_N(features, cpu->nfeatures + 1) < 0)
|
||
|
|
+ goto cleanup;
|
||
|
|
+
|
||
|
|
+ features[cpu->nfeatures] = NULL;
|
||
|
|
+ for (i = 0; i < cpu->nfeatures; i++) {
|
||
|
|
+ if (VIR_STRDUP(features[i], cpu->features[i].name) < 0)
|
||
|
|
+ goto error;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ VIR_FREE(model->data.features);
|
||
|
|
+ model->data.features = virStringListJoin((const char **)features, " ");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ cleanup:
|
||
|
|
+ virStringListFree(features);
|
||
|
|
+ return model;
|
||
|
|
+
|
||
|
|
+ error:
|
||
|
|
+ armModelFree(model);
|
||
|
|
+ model = NULL;
|
||
|
|
+ goto cleanup;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static int
|
||
|
|
+armModelParse(xmlXPathContextPtr ctxt,
|
||
|
|
+ const char *name,
|
||
|
|
+ void *data)
|
||
|
|
+{
|
||
|
|
+ virCPUarmMapPtr map = (virCPUarmMapPtr)data;
|
||
|
|
+ virCPUarmModel *model;
|
||
|
|
+ xmlNodePtr *nodes = NULL;
|
||
|
|
+ char *vendor = NULL;
|
||
|
|
+ int ret = -1;
|
||
|
|
+
|
||
|
|
+ if (VIR_ALLOC(model) < 0)
|
||
|
|
+ goto error;
|
||
|
|
+
|
||
|
|
+ if (VIR_STRDUP(model->name, name) < 0)
|
||
|
|
+ goto error;
|
||
|
|
+
|
||
|
|
+ if (armModelFind(map, model->name)) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
||
|
|
+ _("CPU model %s already defined"), model->name);
|
||
|
|
+ goto error;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ 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 error;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!(model->vendor = armVendorFindByName(map, vendor))) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
||
|
|
+ _("Unknown vendor %s referenced by CPU model %s"),
|
||
|
|
+ vendor, model->name);
|
||
|
|
+ goto error;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!virXPathBoolean("boolean(./pvr)", ctxt)) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
||
|
|
+ _("Missing PVR information for CPU model %s"),
|
||
|
|
+ model->name);
|
||
|
|
+ goto error;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (virXPathULongHex("string(./pvr/@value)", ctxt, &model->data.pvr) < 0) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
||
|
|
+ _("Missing or invalid PVR value in CPU model %s"),
|
||
|
|
+ model->name);
|
||
|
|
+ goto error;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (VIR_APPEND_ELEMENT(map->models, map->nmodels, model) < 0)
|
||
|
|
+ goto error;
|
||
|
|
+
|
||
|
|
+ ret = 0;
|
||
|
|
+
|
||
|
|
+ cleanup:
|
||
|
|
+ VIR_FREE(vendor);
|
||
|
|
+ VIR_FREE(nodes);
|
||
|
|
+ return ret;
|
||
|
|
+
|
||
|
|
+ error:
|
||
|
|
+ armModelFree(model);
|
||
|
|
+ goto cleanup;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+armMapFree(virCPUarmMapPtr map)
|
||
|
|
+{
|
||
|
|
+ size_t i;
|
||
|
|
+
|
||
|
|
+ if (!map)
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < map->nmodels; i++)
|
||
|
|
+ armModelFree(map->models[i]);
|
||
|
|
+ VIR_FREE(map->models);
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < map->nvendors; i++)
|
||
|
|
+ armVendorFree(map->vendors[i]);
|
||
|
|
+ VIR_FREE(map->vendors);
|
||
|
|
+
|
||
|
|
+ VIR_FREE(map);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static virCPUarmMapPtr
|
||
|
|
+virCPUarmLoadMap(void)
|
||
|
|
+{
|
||
|
|
+ virCPUarmMapPtr map;
|
||
|
|
+
|
||
|
|
+ if (VIR_ALLOC(map) < 0)
|
||
|
|
+ goto error;
|
||
|
|
+
|
||
|
|
+ if (cpuMapLoad("arm", armVendorParse, NULL, armModelParse, map) < 0)
|
||
|
|
+ goto error;
|
||
|
|
+
|
||
|
|
+ return map;
|
||
|
|
+
|
||
|
|
+ error:
|
||
|
|
+ armMapFree(map);
|
||
|
|
+ return NULL;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int
|
||
|
|
+virCPUarmDriverOnceInit(void)
|
||
|
|
+{
|
||
|
|
+ if (!(cpuMap = virCPUarmLoadMap()))
|
||
|
|
+ return -1;
|
||
|
|
+
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static virCPUarmMapPtr
|
||
|
|
+virCPUarmGetMap(void)
|
||
|
|
+{
|
||
|
|
+ if (virCPUarmDriverInitialize() < 0)
|
||
|
|
+ return NULL;
|
||
|
|
+
|
||
|
|
+ return cpuMap;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static virCPUDataPtr
|
||
|
|
+armMakeCPUData(virArch arch,
|
||
|
|
+ virCPUarmData *data)
|
||
|
|
+{
|
||
|
|
+ virCPUDataPtr cpuData;
|
||
|
|
+
|
||
|
|
+ if (VIR_ALLOC(cpuData) < 0)
|
||
|
|
+ return NULL;
|
||
|
|
+
|
||
|
|
+ cpuData->arch = arch;
|
||
|
|
+
|
||
|
|
+ if (armDataCopy(&cpuData->data.arm, data) < 0)
|
||
|
|
+ VIR_FREE(cpuData);
|
||
|
|
+
|
||
|
|
+ return cpuData;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static int
|
||
|
|
+armCpuDataParseFeatures(virCPUDefPtr cpu,
|
||
|
|
+ const virCPUarmData *cpuData)
|
||
|
|
+{
|
||
|
|
+ int ret = -1;
|
||
|
|
+ size_t i;
|
||
|
|
+ char **features;
|
||
|
|
+
|
||
|
|
+ if (!cpu || !cpuData)
|
||
|
|
+ return ret;
|
||
|
|
+
|
||
|
|
+ if (!(features = virStringSplitCount(cpuData->features, " ",
|
||
|
|
+ 0, &cpu->nfeatures)))
|
||
|
|
+ return ret;
|
||
|
|
+ if (cpu->nfeatures) {
|
||
|
|
+ if (VIR_ALLOC_N(cpu->features, cpu->nfeatures) < 0)
|
||
|
|
+ goto error;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < cpu->nfeatures; i++) {
|
||
|
|
+ cpu->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
|
||
|
|
+ if (VIR_STRDUP(cpu->features[i].name, features[i]) < 0)
|
||
|
|
+ goto error;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ret = 0;
|
||
|
|
+
|
||
|
|
+ cleanup:
|
||
|
|
+ virStringListFree(features);
|
||
|
|
+ return ret;
|
||
|
|
+
|
||
|
|
+ error:
|
||
|
|
+ for (i = 0; i < cpu->nfeatures; i++)
|
||
|
|
+ VIR_FREE(cpu->features[i].name);
|
||
|
|
+ VIR_FREE(cpu->features);
|
||
|
|
+ cpu->nfeatures = 0;
|
||
|
|
+ goto cleanup;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static int
|
||
|
|
+armDecode(virCPUDefPtr cpu,
|
||
|
|
+ const virCPUarmData *cpuData,
|
||
|
|
+ virDomainCapsCPUModelsPtr models)
|
||
|
|
+{
|
||
|
|
+ virCPUarmMapPtr map;
|
||
|
|
+ virCPUarmModelPtr model;
|
||
|
|
+ virCPUarmVendorPtr vendor = NULL;
|
||
|
|
+
|
||
|
|
+ if (!cpuData || !(map = virCPUarmGetMap()))
|
||
|
|
+ return -1;
|
||
|
|
+
|
||
|
|
+ if (!(model = armModelFindByPVR(map, cpuData->pvr))) {
|
||
|
|
+ virReportError(VIR_ERR_OPERATION_FAILED,
|
||
|
|
+ _("Cannot find CPU model with PVR 0x%03lx"),
|
||
|
|
+ cpuData->pvr);
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!virCPUModelIsAllowed(model->name, models)) {
|
||
|
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||
|
|
+ _("CPU model %s is not supported by hypervisor"),
|
||
|
|
+ model->name);
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (VIR_STRDUP(cpu->model, model->name) < 0)
|
||
|
|
+ return -1;
|
||
|
|
+
|
||
|
|
+ if (cpuData->vendor_id &&
|
||
|
|
+ !(vendor = armVendorFindByID(map, cpuData->vendor_id))) {
|
||
|
|
+ virReportError(VIR_ERR_OPERATION_FAILED,
|
||
|
|
+ _("Cannot find CPU vendor with vendor id 0x%02lx"),
|
||
|
|
+ cpuData->vendor_id);
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (vendor && VIR_STRDUP(cpu->vendor, vendor->name) < 0)
|
||
|
|
+ return -1;
|
||
|
|
+
|
||
|
|
+ if (cpuData->features &&
|
||
|
|
+ armCpuDataParseFeatures(cpu, cpuData) < 0)
|
||
|
|
+ return -1;
|
||
|
|
+
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static int
|
||
|
|
+armDecodeCPUData(virCPUDefPtr cpu,
|
||
|
|
+ const virCPUData *data,
|
||
|
|
+ virDomainCapsCPUModelsPtr models)
|
||
|
|
+{
|
||
|
|
+ return armDecode(cpu, &data->data.arm, models);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
|
||
|
|
static int
|
||
|
|
virCPUarmUpdate(virCPUDefPtr guest,
|
||
|
|
--
|
||
|
|
2.19.1
|
||
|
|
|