[PATCH 5/5] cpu: Introduce getHost supoort for ARM

Zhenyu Zheng zheng.zhenyu at foxmail.com
Fri Mar 27 08:52:25 UTC 2020


Introduce getHost support for ARM, use data from 'lscpu' cmd
result. 'util-linux/lscpu' provided a very good translation of
ARM cpu data start from release v2.32, use it directly to avoid
re-implement the translation.

Signed-of-by: Zhenyu Zheng <zhengzhenyulixi at gmail.com>
---
 src/cpu/cpu_arm.c | 198 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 197 insertions(+), 1 deletion(-)

diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
index 969025b5cf..30d9c0ae2e 100644
--- a/src/cpu/cpu_arm.c
+++ b/src/cpu/cpu_arm.c
@@ -22,8 +22,11 @@
 #include <config.h>
 
 #include "viralloc.h"
+#include "virlog.h"
 #include "cpu.h"
 #include "cpu_map.h"
+#include "vircommand.h"
+#include "virfile.h"
 #include "virstring.h"
 #include "virxml.h"
 #include "cpu_map.h"
@@ -31,6 +34,14 @@
 
 #define VIR_FROM_THIS VIR_FROM_CPU
 
+VIR_LOG_INIT("cpu.cpu_arm");
+
+static const char *lsCpuPath = "/usr/bin/lscpu";
+
+#define LSCPU lsCpuPath
+#define MAX_LSCPU_SIZE = (1024*1024)   /* 1MB limit for lscpu output */
+
+
 static const virArch archs[] = {
     VIR_ARCH_ARMV6L,
     VIR_ARCH_ARMV7B,
@@ -464,13 +475,198 @@ virCPUarmValidateFeatures(virCPUDefPtr cpu)
     return 0;
 }
 
+static int
+armCpuDataFromLsCpu(virCPUarmData *data)
+{
+    int ret = -1;
+    char *outbuf = NULL;
+    char *eol = NULL;
+    const char *cur;
+    virCommandPtr cmd = NULL;
+    g_autofree char *lscpu = NULL;
+
+    if (!data)
+        return ret;
+
+    lscpu = virFindFileInPath("lscpu");
+    cmd = virCommandNew(lscpu);
+    virCommandSetOutputBuffer(cmd, &outbuf);
+
+    if (virCommandRun(cmd, NULL) < 0) 
+        goto cleanup;
+
+    if ((cur = strstr(outbuf, "Vendor ID")) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("there is no \"Vendor ID\" info in %s command result"), LSCPU);
+        goto cleanup;
+    }
+    cur = strchr(cur, ':') + 1;
+    eol = strchr(cur, '\n');
+    virSkipSpaces(&cur);
+    if (!eol)
+        goto cleanup;
+
+    data->vendor_id = g_strndup(cur, eol - cur);
+
+    if ((cur = strstr(outbuf, "Model name")) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("there is no \"Model name\" info in %s command result"), LSCPU);
+        goto cleanup;
+    }
+    cur = strchr(cur, ':') + 1;
+    eol = strchr(cur, '\n');
+    virSkipSpaces(&cur);
+    if (!eol)
+        goto cleanup;
+
+    data->model_name = g_strndup(cur, eol - cur);
+
+    if ((cur = strstr(outbuf, "Flags")) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("there is no \"Flags\" info in %s command result"), LSCPU);
+        goto cleanup;
+    }
+    cur = strchr(cur, ':') + 1;
+    eol = strchr(cur, '\n');
+    virSkipSpaces(&cur);
+    if (!eol)
+        goto cleanup;
+
+    data->features = g_strndup(cur, eol - cur);
+
+    ret = 0;
+
+ cleanup:
+    virCommandFree(cmd);
+    VIR_FREE(outbuf);
+    return ret;
+}
+
+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;
+            cpu->features[i].name = g_strdup(features[i]);
+        }
+    }
+
+    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 = armModelFind(map, cpuData->model_name))) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       _("Cannot find CPU model with name %s"),
+                       cpuData->model_name);
+        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 = armVendorFindByName(map, cpuData->vendor_id))) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       _("Cannot find CPU vendor with vendor id %s"),
+                       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
+armDecodeCPUData(virCPUDefPtr cpu,
+                 const virCPUData *data,
+                 virDomainCapsCPUModelsPtr models)
+{
+    return armDecode(cpu, &data->data.arm, models);
+}
+
+static int
+virCPUarmGetHost(virCPUDefPtr cpu,
+                 virDomainCapsCPUModelsPtr models)
+{
+    virCPUDataPtr cpuData = NULL;
+    int ret = -1;
+
+    if (virCPUarmDriverInitialize() < 0)
+        goto cleanup;
+
+    if (!(cpuData = virCPUDataNew(archs[0])))
+        goto cleanup;
+
+    if (armCpuDataFromLsCpu(&cpuData->data.arm) < 0)
+        goto cleanup;
+
+    ret = armDecodeCPUData(cpu, cpuData, models);
+
+ cleanup:
+    virCPUarmDataFree(cpuData);
+    return ret;
+}
+
 struct cpuArchDriver cpuDriverArm = {
     .name = "arm",
     .arch = archs,
     .narch = G_N_ELEMENTS(archs),
     .compare = virCPUarmCompare,
-    .decode = NULL,
+    .decode = armDecodeCPUData,
     .encode = NULL,
+    .dataFree = virCPUarmDataFree,
+    .getHost = virCPUarmGetHost,
     .baseline = virCPUarmBaseline,
     .update = virCPUarmUpdate,
     .validateFeatures = virCPUarmValidateFeatures,
-- 
2.26.0.windows.1





More information about the libvir-list mailing list