From a0574d45603010761d3f3034f97457fda94d2266 Mon Sep 17 00:00:00 2001
From: Xu Yandong <xuyandong2@huawei.com>
Date: Fri, 17 Apr 2020 18:13:32 +0800
Subject: cpu/arm: add load cpu map parse function

Signed-off-by: Xu Yandong <xuyandong2@huawei.com>
---
 src/cpu/cpu_arm.c | 223 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 220 insertions(+), 3 deletions(-)

diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
index 230cd27..d85f111 100644
--- a/src/cpu/cpu_arm.c
+++ b/src/cpu/cpu_arm.c
@@ -67,7 +67,7 @@ virCPUarmDataClear(virCPUarmData *data)
     if (!data)
         return;
 
-    VIR_FREE(data->features);
+    g_free(data->features);
 }
 
 static void
@@ -77,12 +77,64 @@ virCPUarmDataFree(virCPUDataPtr cpuData)
         return;
 
     virCPUarmDataClear(&cpuData->data.arm);
-    VIR_FREE(cpuData);
+    g_free(cpuData);
 }
 
+typedef struct _virCPUarmVendor virCPUarmVendor;
+typedef virCPUarmVendor *virCPUarmVendorPtr;
+struct _virCPUarmVendor {
+    char *name;
+    unsigned long value;
+};
+
+static virCPUarmVendorPtr
+virCPUarmVendorNew(void)
+{
+    return g_new0(virCPUarmVendor, 1);
+}
+
+static void
+virCPUarmVendorFree(virCPUarmVendorPtr vendor)
+{
+    if (!vendor)
+        return;
+
+    g_free(vendor->name);
+    VIR_FREE(vendor);
+}
+
+typedef struct _virCPUarmModel virCPUarmModel;
+typedef virCPUarmModel *virCPUarmModelPtr;
+struct _virCPUarmModel {
+    char *name;
+    virCPUarmVendorPtr vendor;
+    virCPUarmData data;
+};
+
+static virCPUarmModelPtr
+virCPUarmModelNew(void)
+{
+    return g_new0(virCPUarmModel, 1);
+}
+
+static void
+virCPUarmModelFree(virCPUarmModelPtr model)
+{
+    if (!model)
+        return;
+
+    virCPUarmDataClear(&model->data);
+    g_free(model->name);
+    g_free(model);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPUarmModel, virCPUarmModelFree);
+
 typedef struct _virCPUarmMap virCPUarmMap;
 typedef virCPUarmMap *virCPUarmMapPtr;
 struct _virCPUarmMap {
+    GPtrArray *vendors;
+    GPtrArray *models;
     GPtrArray *features;
 };
 
@@ -93,6 +145,14 @@ virCPUarmMapNew(void)
 
     map = g_new0(virCPUarmMap, 1);
 
+    map->vendors = g_ptr_array_new();
+    g_ptr_array_set_free_func(map->vendors,
+                              (GDestroyNotify) virCPUarmVendorFree);
+
+    map->models = g_ptr_array_new();
+    g_ptr_array_set_free_func(map->models,
+                              (GDestroyNotify) virCPUarmModelFree);
+
     map->features = g_ptr_array_new();
     g_ptr_array_set_free_func(map->features,
                               (GDestroyNotify) virCPUarmFeatureFree);
@@ -106,6 +166,8 @@ virCPUarmMapFree(virCPUarmMapPtr map)
     if (!map)
         return;
 
+    g_ptr_array_free(map->vendors, TRUE);
+    g_ptr_array_free(map->models, TRUE);
     g_ptr_array_free(map->features, TRUE);
 
     g_free(map);
@@ -151,6 +213,161 @@ virCPUarmMapFeatureParse(xmlXPathContextPtr ctxt G_GNUC_UNUSED,
     return 0;
 }
 
+static virCPUarmVendorPtr
+virCPUarmVendorFindByID(virCPUarmMapPtr map,
+                        unsigned long vendor_id)
+{
+    size_t i;
+
+    for (i = 0; i < map->vendors->len; i++) {
+        virCPUarmVendorPtr vendor = g_ptr_array_index(map->vendors, i);
+
+        if (vendor->value == vendor_id)
+            return vendor;
+    }
+
+    return NULL;
+}
+
+static virCPUarmVendorPtr
+virCPUarmVendorFindByName(virCPUarmMapPtr map,
+                          const char *name)
+{
+    size_t i;
+
+    for (i = 0; i < map->vendors->len; i++) {
+        virCPUarmVendorPtr vendor = g_ptr_array_index(map->vendors, i);
+
+        if (STREQ(vendor->name, name))
+            return vendor;
+    }
+
+    return NULL;
+}
+
+static int
+virCPUarmVendorParse(xmlXPathContextPtr ctxt,
+                     const char *name,
+                     void *data)
+{
+    virCPUarmMapPtr map = (virCPUarmMapPtr)data;
+    g_autoptr(virCPUarmVendor) vendor = NULL;
+    int ret = -1;
+
+    if (virCPUarmVendorFindByName(map, name)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("CPU vendor %s already defined"), name);
+        return -1;
+    }
+
+    vendor = virCPUarmVendorNew();
+    vendor->name = g_strdup(name);
+
+    if (virXPathULongHex("string(@value)", ctxt, &vendor->value) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("Missing CPU vendor value"));
+        return -1;
+    }
+
+    if (virCPUarmVendorFindByID(map, vendor->value)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("CPU vendor value 0x%2lx already defined"), vendor->value);
+        return -1;
+    }
+
+    g_ptr_array_add(map->vendors, g_steal_pointer(&vendor));
+
+    return 0;
+}
+
+static virCPUarmModelPtr
+virCPUarmModelFindByPVR(virCPUarmMapPtr map,
+                        unsigned long pvr)
+{
+    size_t i;
+
+    for (i = 0; i < map->models->len; i++) {
+        virCPUarmModelPtr model = g_ptr_array_index(map->models, i);
+
+        if (STREQ(model->pvr, pvr))
+            return model;
+    }
+
+    return NULL;
+
+}
+
+static virCPUarmModelPtr
+virCPUarmModelFindByName(virCPUarmMapPtr map,
+                   const char *name)
+{
+    size_t i;
+
+    for (i = 0; i < map->models->len; i++) {
+        virCPUarmModelPtr model = g_ptr_array_index(map->models, i);
+
+        if (STREQ(model->name, name))
+            return model;
+    }
+
+    return NULL;
+}
+
+static int
+virCPUarmModelParse(xmlXPathContextPtr ctxt,
+                    const char *name,
+                    void *data)
+{
+    virCPUarmMapPtr map = (virCPUarmMapPtr)data;
+    g_autoptr(virCPUarmModel) model = NULL;
+    char *vendor = NULL;
+    int ret = -1;
+
+    if (virCPUarmModelFindByName(map, name)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("CPU model %s already defined"), name);
+        return -1;
+    }
+
+    model = virCPUarmModelNew();
+    model->name = g_strdup(name);
+
+    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"),
+                           name);
+            return -1;
+        }
+
+        if (!(model->vendor = virCPUarmVendorFindByName(map, vendor))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Unknown vendor %s referenced by CPU model %s"),
+                           vendor, model->name);
+            return -1;
+        }
+    }
+
+    if (!virXPathBoolean("boolean(./pvr)", ctxt)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Missing PVR information for CPU model %s"),
+                       model->name);
+        return -1;
+    }
+
+    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);
+        return -1;
+    }
+
+    g_ptr_array_add(map->models, g_steal_pointer(&model));
+
+    return 0;
+}
+
 static virCPUarmMapPtr
 virCPUarmLoadMap(void)
 {
@@ -158,7 +375,7 @@ virCPUarmLoadMap(void)
 
     map = virCPUarmMapNew();
 
-    if (cpuMapLoad("arm", NULL, virCPUarmMapFeatureParse, NULL, map) < 0)
+    if (cpuMapLoad("arm", virCPUarmVendorParse, virCPUarmMapFeatureParse, virCPUarmModelParse, map) < 0)
         return NULL;
 
     return g_steal_pointer(&map);
-- 
2.23.0