For now we only perform very basic validation, such as making sure
that the user is not trying to enable/disable unknown CPU features
and the like.
Signed-off-by: Andrea Bolognani <abologna(a)redhat.com>
Tested-by: Andrew Jones <drjones(a)redhat.com>
---
src/cpu/cpu_arm.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 157 insertions(+)
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
index a102c6fda4..70dba6021c 100644
--- a/src/cpu/cpu_arm.c
+++ b/src/cpu/cpu_arm.c
@@ -23,7 +23,9 @@
#include "viralloc.h"
#include "cpu.h"
+#include "cpu_map.h"
#include "virstring.h"
+#include "virxml.h"
#define VIR_FROM_THIS VIR_FROM_CPU
@@ -34,6 +36,137 @@ static const virArch archs[] = {
VIR_ARCH_AARCH64,
};
+typedef struct _virCPUarmFeature virCPUarmFeature;
+typedef virCPUarmFeature *virCPUarmFeaturePtr;
+struct _virCPUarmFeature {
+ char *name;
+};
+
+static virCPUarmFeaturePtr
+virCPUarmFeatureNew(void)
+{
+ return g_new0(virCPUarmFeature, 1);
+}
+
+static void
+virCPUarmFeatureFree(virCPUarmFeaturePtr feature)
+{
+ if (!feature)
+ return;
+
+ g_free(feature->name);
+
+ g_free(feature);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPUarmFeature, virCPUarmFeatureFree);
+
+typedef struct _virCPUarmMap virCPUarmMap;
+typedef virCPUarmMap *virCPUarmMapPtr;
+struct _virCPUarmMap {
+ GPtrArray *features;
+};
+
+static virCPUarmMapPtr
+virCPUarmMapNew(void)
+{
+ virCPUarmMapPtr map;
+
+ map = g_new0(virCPUarmMap, 1);
+
+ map->features = g_ptr_array_new();
+ g_ptr_array_set_free_func(map->features,
+ (GDestroyNotify) virCPUarmFeatureFree);
+
+ return map;
+}
+
+static void
+virCPUarmMapFree(virCPUarmMapPtr map)
+{
+ if (!map)
+ return;
+
+ g_ptr_array_free(map->features, TRUE);
+
+ g_free(map);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPUarmMap, virCPUarmMapFree);
+
+static virCPUarmFeaturePtr
+virCPUarmMapFeatureFind(virCPUarmMapPtr map,
+ const char *name)
+{
+ size_t i;
+
+ for (i = 0; i < map->features->len; i++) {
+ virCPUarmFeaturePtr feature = g_ptr_array_index(map->features, i);
+
+ if (STREQ(feature->name, name))
+ return feature;
+ }
+
+ return NULL;
+}
+
+static int
+virCPUarmMapFeatureParse(xmlXPathContextPtr ctxt G_GNUC_UNUSED,
+ const char *name,
+ void *data)
+{
+ g_autoptr(virCPUarmFeature) feature = NULL;
+ virCPUarmMapPtr map = data;
+
+ if (virCPUarmMapFeatureFind(map, name)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("CPU feature %s already defined"), name);
+ return -1;
+ }
+
+ feature = virCPUarmFeatureNew();
+ feature->name = g_strdup(name);
+
+ g_ptr_array_add(map->features, g_steal_pointer(&feature));
+
+ return 0;
+}
+
+static virCPUarmMapPtr
+virCPUarmLoadMap(void)
+{
+ g_autoptr(virCPUarmMap) map = NULL;
+
+ map = virCPUarmMapNew();
+
+ if (cpuMapLoad("arm", NULL, virCPUarmMapFeatureParse, NULL, map) < 0)
+ return NULL;
+
+ return g_steal_pointer(&map);
+}
+
+static virCPUarmMapPtr cpuMap;
+
+int virCPUarmDriverOnceInit(void);
+VIR_ONCE_GLOBAL_INIT(virCPUarmDriver);
+
+int
+virCPUarmDriverOnceInit(void)
+{
+ if (!(cpuMap = virCPUarmLoadMap()))
+ return -1;
+
+ return 0;
+}
+
+static virCPUarmMapPtr
+virCPUarmGetMap(void)
+{
+ if (virCPUarmDriverInitialize() < 0)
+ return NULL;
+
+ return cpuMap;
+}
static int
virCPUarmUpdate(virCPUDefPtr guest,
@@ -99,6 +232,29 @@ virCPUarmCompare(virCPUDefPtr host G_GNUC_UNUSED,
return VIR_CPU_COMPARE_IDENTICAL;
}
+static int
+virCPUarmValidateFeatures(virCPUDefPtr cpu)
+{
+ virCPUarmMapPtr map;
+ size_t i;
+
+ if (!(map = virCPUarmGetMap()))
+ return -1;
+
+ for (i = 0; i < cpu->nfeatures; i++) {
+ virCPUFeatureDefPtr feature = &cpu->features[i];
+
+ if (!virCPUarmMapFeatureFind(map, feature->name)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown CPU feature: %s"),
+ feature->name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
struct cpuArchDriver cpuDriverArm = {
.name = "arm",
.arch = archs,
@@ -108,4 +264,5 @@ struct cpuArchDriver cpuDriverArm = {
.encode = NULL,
.baseline = virCPUarmBaseline,
.update = virCPUarmUpdate,
+ .validateFeatures = virCPUarmValidateFeatures,
};
--
2.21.0