[libvirt] [PATCH 04/23] cpu: Add support for loading and storing CPU data

Peter Krempa pkrempa at redhat.com
Mon Oct 14 12:57:27 UTC 2013


From: Jiri Denemark <jdenemar at redhat.com>

This patch adds cpuDataFormat and cpuDataParse APIs to be used in unit
tests for testing APIs that deal with virCPUData. In the x86 world, this
means we can now store/load arbitrary CPUID data in the test suite to
check correctness of CPU related APIs that could not be tested before.

Signed-off-by: Peter Krempa <pkrempa at redhat.com>
---
 src/cpu/cpu.c            |  41 ++++++++++++++
 src/cpu/cpu.h            |  14 +++++
 src/cpu/cpu_x86.c        | 135 +++++++++++++++++++++++++++++++++++++++--------
 src/libvirt_private.syms |   2 +
 4 files changed, 171 insertions(+), 21 deletions(-)

diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index 31de857..8b293c8 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -442,6 +442,47 @@ cpuHasFeature(const virCPUDataPtr data,
     return driver->hasFeature(data, feature);
 }

+char *
+cpuDataFormat(const virCPUDataPtr data)
+{
+    struct cpuArchDriver *driver;
+
+    VIR_DEBUG("data=%p", data);
+
+    if (!(driver = cpuGetSubDriver(data->arch)))
+        return NULL;
+
+    if (!driver->dataFormat) {
+        virReportError(VIR_ERR_NO_SUPPORT,
+                       _("cannot format %s CPU data"),
+                       virArchToString(data->arch));
+        return NULL;
+    }
+
+    return driver->dataFormat(data);
+}
+
+virCPUDataPtr
+cpuDataParse(virArch arch,
+             const char *xmlStr)
+{
+    struct cpuArchDriver *driver;
+
+    VIR_DEBUG("arch=%s, xmlStr=%s", virArchToString(arch), xmlStr);
+
+    if (!(driver = cpuGetSubDriver(arch)))
+        return NULL;
+
+    if (!driver->dataParse) {
+        virReportError(VIR_ERR_NO_SUPPORT,
+                       _("cannot parse %s CPU data"),
+                       virArchToString(arch));
+        return NULL;
+    }
+
+    return driver->dataParse(xmlStr);
+}
+
 bool
 cpuModelIsAllowed(const char *model,
                   const char **models,
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
index 2f0c8c7..5e343a3 100644
--- a/src/cpu/cpu.h
+++ b/src/cpu/cpu.h
@@ -93,6 +93,11 @@ typedef int
 (*cpuArchHasFeature) (const virCPUDataPtr data,
                       const char *feature);

+typedef char *
+(*cpuArchDataFormat)(const virCPUDataPtr data);
+
+typedef virCPUDataPtr
+(*cpuArchDataParse) (const char *xmlStr);

 struct cpuArchDriver {
     const char *name;
@@ -107,6 +112,8 @@ struct cpuArchDriver {
     cpuArchBaseline     baseline;
     cpuArchUpdate       update;
     cpuArchHasFeature    hasFeature;
+    cpuArchDataFormat   dataFormat;
+    cpuArchDataParse    dataParse;
 };


@@ -178,4 +185,11 @@ cpuModelIsAllowed(const char *model,
 extern int
 cpuGetModels(const char *arch, char ***models);

+/* cpuDataFormat and cpuDataParse are implemented for unit tests only and
+ * have no real-life usage
+ */
+char *cpuDataFormat(const virCPUDataPtr data);
+virCPUDataPtr cpuDataParse(virArch arch,
+                           const char *xmlStr);
+
 #endif /* __VIR_CPU_H__ */
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index 3d5e16f..3ab03fc 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -666,12 +666,42 @@ x86FeatureNames(const struct x86_map *map,


 static int
+x86ParseCPUID(xmlXPathContextPtr ctxt,
+              struct cpuX86cpuid *cpuid)
+{
+    unsigned long fun, eax, ebx, ecx, edx;
+    int ret_fun, ret_eax, ret_ebx, ret_ecx, ret_edx;
+
+    memset(cpuid, 0, sizeof(*cpuid));
+
+    fun = eax = ebx = ecx = edx = 0;
+    ret_fun = virXPathULongHex("string(@function)", ctxt, &fun);
+    ret_eax = virXPathULongHex("string(@eax)", ctxt, &eax);
+    ret_ebx = virXPathULongHex("string(@ebx)", ctxt, &ebx);
+    ret_ecx = virXPathULongHex("string(@ecx)", ctxt, &ecx);
+    ret_edx = virXPathULongHex("string(@edx)", ctxt, &edx);
+
+    if (ret_fun < 0 || ret_eax == -2 || ret_ebx == -2
+        || ret_ecx == -2 || ret_edx == -2)
+        return -1;
+
+    cpuid->function = fun;
+    cpuid->eax = eax;
+    cpuid->ebx = ebx;
+    cpuid->ecx = ecx;
+    cpuid->edx = edx;
+    return 0;
+}
+
+
+static int
 x86FeatureLoad(xmlXPathContextPtr ctxt,
                struct x86_map *map)
 {
     xmlNodePtr *nodes = NULL;
     xmlNodePtr ctxt_node = ctxt->node;
     struct x86_feature *feature;
+    struct cpuX86cpuid cpuid;
     int ret = 0;
     size_t i;
     int n;
@@ -697,31 +727,13 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
         goto ignore;

     for (i = 0; i < n; i++) {
-        struct cpuX86cpuid cpuid;
-        unsigned long fun, eax, ebx, ecx, edx;
-        int ret_fun, ret_eax, ret_ebx, ret_ecx, ret_edx;
-
         ctxt->node = nodes[i];
-        fun = eax = ebx = ecx = edx = 0;
-        ret_fun = virXPathULongHex("string(@function)", ctxt, &fun);
-        ret_eax = virXPathULongHex("string(@eax)", ctxt, &eax);
-        ret_ebx = virXPathULongHex("string(@ebx)", ctxt, &ebx);
-        ret_ecx = virXPathULongHex("string(@ecx)", ctxt, &ecx);
-        ret_edx = virXPathULongHex("string(@edx)", ctxt, &edx);
-
-        if (ret_fun < 0 || ret_eax == -2 || ret_ebx == -2
-            || ret_ecx == -2 || ret_edx == -2) {
+        if (x86ParseCPUID(ctxt, &cpuid) < 0) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Invalid cpuid[%zu] in %s feature"), i, feature->name);
+                           _("Invalid cpuid[%zu] in %s feature"),
+                           i, feature->name);
             goto ignore;
         }
-
-        cpuid.function = fun;
-        cpuid.eax = eax;
-        cpuid.ebx = ebx;
-        cpuid.ecx = ecx;
-        cpuid.edx = edx;
-
         if (x86DataAddCpuid(feature->data, &cpuid))
             goto error;
     }
@@ -1124,6 +1136,85 @@ error:
 }


+static char *
+x86CPUDataFormat(const virCPUDataPtr data)
+{
+    struct data_iterator iter = DATA_ITERATOR_INIT(data->data.x86);
+    struct cpuX86cpuid *cpuid;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferAddLit(&buf, "<cpudata arch='x86'>\n");
+    while ((cpuid = x86DataCpuidNext(&iter))) {
+        virBufferAsprintf(&buf,
+                          "  <cpuid function='0x%08x'"
+                          " eax='0x%08x' ebx='0x%08x'"
+                          " ecx='0x%08x' edx='0x%08x'/>\n",
+                          cpuid->function,
+                          cpuid->eax, cpuid->ebx, cpuid->ecx, cpuid->edx);
+    }
+    virBufferAddLit(&buf, "</cpudata>\n");
+
+    if (virBufferError(&buf)) {
+        virBufferFreeAndReset(&buf);
+        virReportOOMError();
+        return NULL;
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
+
+static virCPUDataPtr
+x86CPUDataParse(const char *xmlStr)
+{
+    xmlDocPtr xml = NULL;
+    xmlXPathContextPtr ctxt = NULL;
+    xmlNodePtr *nodes = NULL;
+    virCPUDataPtr cpuData = NULL;
+    struct cpuX86Data *data = NULL;
+    struct cpuX86cpuid cpuid;
+    size_t i;
+    int n;
+
+    if (VIR_ALLOC(data) < 0)
+        goto cleanup;
+
+    if (!(xml = virXMLParseStringCtxt(xmlStr, _("CPU data"), &ctxt))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("cannot parse CPU data"));
+        goto cleanup;
+    }
+    ctxt->node = xmlDocGetRootElement(xml);
+
+    n = virXPathNodeSet("/cpudata[@arch='x86']/data", ctxt, &nodes);
+    if (n < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("no x86 CPU data found"));
+        goto cleanup;
+    }
+
+    for (i = 0; i < n; i++) {
+        ctxt->node = nodes[i];
+        if (x86ParseCPUID(ctxt, &cpuid) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("failed to parse cpuid[%zu]"), i);
+            goto cleanup;
+        }
+        if (x86DataAddCpuid(data, &cpuid) < 0)
+            goto cleanup;
+    }
+
+    cpuData = x86MakeCPUData(VIR_ARCH_X86_64, &data);
+
+cleanup:
+    VIR_FREE(nodes);
+    xmlXPathFreeContext(ctxt);
+    xmlFreeDoc(xml);
+    x86DataFree(data);
+    return cpuData;
+}
+
+
 /* A helper macro to exit the cpu computation function without writing
  * redundant code:
  * MSG: error message
@@ -1956,4 +2047,6 @@ struct cpuArchDriver cpuDriverX86 = {
     .baseline   = x86Baseline,
     .update     = x86Update,
     .hasFeature = x86HasFeature,
+    .dataFormat = x86CPUDataFormat,
+    .dataParse  = x86CPUDataParse,
 };
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 844ca29..7d90b85 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -720,7 +720,9 @@ cpuBaseline;
 cpuBaselineXML;
 cpuCompare;
 cpuCompareXML;
+cpuDataFormat;
 cpuDataFree;
+cpuDataParse;
 cpuDecode;
 cpuEncode;
 cpuGetModels;
-- 
1.8.3.2




More information about the libvir-list mailing list