From c69a629367b0e9bfa1a034301a4c3f88ad080586 Mon Sep 17 00:00:00 2001
From: Xu Yandong <xuyandong2@huawei.com>
Date: Sat, 18 Apr 2020 11:16:13 +0800
Subject: cpu/arm: add decode function

Signed-off-by: Xu Yandong <xuyandong2@huawei.com>
---
 src/cpu/cpu_arm.c     | 150 ++++++++++++++++++++++++++++++++++--------
 src/cpu_map/index.xml |   3 -
 2 files changed, 122 insertions(+), 31 deletions(-)

diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
index d85f111..eb9b1c9 100644
--- a/src/cpu/cpu_arm.c
+++ b/src/cpu/cpu_arm.c
@@ -55,7 +55,6 @@ virCPUarmFeatureFree(virCPUarmFeaturePtr feature)
         return;
 
     g_free(feature->name);
-
     g_free(feature);
 }
 
@@ -80,6 +79,8 @@ virCPUarmDataFree(virCPUDataPtr cpuData)
     g_free(cpuData);
 }
 
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPUData, virCPUarmDataFree);
+
 typedef struct _virCPUarmVendor virCPUarmVendor;
 typedef virCPUarmVendor *virCPUarmVendorPtr;
 struct _virCPUarmVendor {
@@ -103,6 +104,8 @@ virCPUarmVendorFree(virCPUarmVendorPtr vendor)
     VIR_FREE(vendor);
 }
 
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPUarmVendor, virCPUarmVendorFree);
+
 typedef struct _virCPUarmModel virCPUarmModel;
 typedef virCPUarmModel *virCPUarmModelPtr;
 struct _virCPUarmModel {
@@ -175,6 +178,38 @@ virCPUarmMapFree(virCPUarmMapPtr map)
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCPUarmMap, virCPUarmMapFree);
 
+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 virCPUarmFeaturePtr
 virCPUarmMapFeatureFind(virCPUarmMapPtr map,
                         const char *name)
@@ -213,36 +248,43 @@ virCPUarmMapFeatureParse(xmlXPathContextPtr ctxt G_GNUC_UNUSED,
     return 0;
 }
 
-static virCPUarmVendorPtr
-virCPUarmVendorFindByID(virCPUarmMapPtr map,
-                        unsigned long vendor_id)
+static int
+armCpuDataParseFeatures(virCPUDefPtr cpu,
+                        const virCPUarmData *cpuData)
 {
+    int ret = -1;
     size_t i;
+    char **features;
 
-    for (i = 0; i < map->vendors->len; i++) {
-        virCPUarmVendorPtr vendor = g_ptr_array_index(map->vendors, i);
+    if (!cpu || !cpuData)
+        return ret;
 
-        if (vendor->value == vendor_id)
-            return vendor;
-    }
+    if (!(features = virStringSplitCount(cpuData->features, " ",
+                                         0, &cpu->nfeatures)))
+        return ret;
 
-    return NULL;
-}
+    if (cpu->nfeatures) {
+        if (VIR_ALLOC_N(cpu->features, cpu->nfeatures) < 0)
+            goto error;
 
-static virCPUarmVendorPtr
-virCPUarmVendorFindByName(virCPUarmMapPtr map,
-                          const char *name)
-{
-    size_t i;
+        for (i = 0; i < cpu->nfeatures; i++) {
+            cpu->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
+            cpu->features[i].name = g_strdup(features[i]);
+        }
+    }
 
-    for (i = 0; i < map->vendors->len; i++) {
-        virCPUarmVendorPtr vendor = g_ptr_array_index(map->vendors, i);
+    ret = 0;
 
-        if (STREQ(vendor->name, name))
-            return vendor;
-    }
+cleanup:
+    virStringListFree(features);
+    return ret;
 
-    return NULL;
+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
@@ -252,7 +294,6 @@ virCPUarmVendorParse(xmlXPathContextPtr ctxt,
 {
     virCPUarmMapPtr map = (virCPUarmMapPtr)data;
     g_autoptr(virCPUarmVendor) vendor = NULL;
-    int ret = -1;
 
     if (virCPUarmVendorFindByName(map, name)) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -289,7 +330,7 @@ virCPUarmModelFindByPVR(virCPUarmMapPtr map,
     for (i = 0; i < map->models->len; i++) {
         virCPUarmModelPtr model = g_ptr_array_index(map->models, i);
 
-        if (STREQ(model->pvr, pvr))
+        if (model->data.pvr == pvr)
             return model;
     }
 
@@ -299,7 +340,7 @@ virCPUarmModelFindByPVR(virCPUarmMapPtr map,
 
 static virCPUarmModelPtr
 virCPUarmModelFindByName(virCPUarmMapPtr map,
-                   const char *name)
+                         const char *name)
 {
     size_t i;
 
@@ -321,7 +362,6 @@ virCPUarmModelParse(xmlXPathContextPtr ctxt,
     virCPUarmMapPtr map = (virCPUarmMapPtr)data;
     g_autoptr(virCPUarmModel) model = NULL;
     char *vendor = NULL;
-    int ret = -1;
 
     if (virCPUarmModelFindByName(map, name)) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -404,6 +444,60 @@ virCPUarmGetMap(void)
     return cpuMap;
 }
 
+static int
+virCPUarmDecode(virCPUDefPtr cpu,
+                const virCPUarmData *cpuData,
+                virDomainCapsCPUModelsPtr models)
+{
+    virCPUarmMapPtr map;
+    virCPUarmModelPtr model;
+    virCPUarmVendorPtr vendor = NULL;
+
+    if (!cpuData || !(map = virCPUarmGetMap()))
+        return -1;
+
+    if (!(model = virCPUarmModelFindByPVR(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;
+    }
+
+    cpu->model = g_strdup(model->name);
+
+    if (cpuData->vendor_id &&
+        !(vendor = virCPUarmVendorFindByID(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)
+        cpu->vendor = g_strdup(vendor->name);
+
+    if (cpuData->features &&
+        armCpuDataParseFeatures(cpu, cpuData) < 0)
+        return -1;
+
+    return 0;
+}
+
+static int
+virCPUarmDecodeCPUData(virCPUDefPtr cpu,
+                       const virCPUData *data,
+                       virDomainCapsCPUModelsPtr models)
+{
+    return virCPUarmDecode(cpu, &data->data.arm, models);
+}
+
 static int
 virCPUarmUpdate(virCPUDefPtr guest,
                 const virCPUDef *host)
@@ -432,7 +526,7 @@ virCPUarmUpdate(virCPUDefPtr guest,
     guest->match = VIR_CPU_MATCH_EXACT;
     ret = 0;
 
- cleanup:
+cleanup:
     virCPUDefFree(updated);
     return ret;
 }
@@ -493,7 +587,7 @@ struct cpuArchDriver cpuDriverArm = {
     .arch = archs,
     .narch = G_N_ELEMENTS(archs),
     .compare = virCPUarmCompare,
-    .decode = NULL,
+    .decode = virCPUarmDecodeCPUData,
     .encode = NULL,
     .dataFree = virCPUarmDataFree,
     .baseline = virCPUarmBaseline,
diff --git a/src/cpu_map/index.xml b/src/cpu_map/index.xml
index 2e78834..985af86 100644
--- a/src/cpu_map/index.xml
+++ b/src/cpu_map/index.xml
@@ -86,9 +86,6 @@
 
   <arch name='arm'>
     <include filename='arm_features.xml'/>
-  </arch>
-
-  <arch name='arm'>
     <include filename="arm_vendors.xml"/>
 
     <!-- ARM-based CPU models -->
-- 
2.23.0