libvirt/libvirt-cpu-introduce-cpu-baseline-for-ARM-CPU.patch
2019-09-30 10:58:53 -04:00

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(&copy->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