43fe83
From ba31d47b940dc748a291e9b68efcf84178ea6800 Mon Sep 17 00:00:00 2001
43fe83
Message-Id: <ba31d47b940dc748a291e9b68efcf84178ea6800.1383922566.git.jdenemar@redhat.com>
43fe83
From: Jiri Denemark <jdenemar@redhat.com>
43fe83
Date: Fri, 8 Nov 2013 12:33:17 +0100
43fe83
Subject: [PATCH] cpu: Add support for loading and storing CPU data
43fe83
43fe83
https://bugzilla.redhat.com/show_bug.cgi?id=1008989
43fe83
43fe83
This patch adds cpuDataFormat and cpuDataParse APIs to be used in unit
43fe83
tests for testing APIs that deal with virCPUData. In the x86 world, this
43fe83
means we can now store/load arbitrary CPUID data in the test suite to
43fe83
check correctness of CPU related APIs that could not be tested before.
43fe83
43fe83
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
43fe83
(cherry picked from commit 376261d164b0872bf011e525b4f0f050e942ace5)
43fe83
43fe83
Conflicts:
43fe83
	src/cpu/cpu.h - virCPUGetModel was not backported (context)
43fe83
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
43fe83
---
43fe83
 src/cpu/cpu.c            |  41 ++++++++++++++
43fe83
 src/cpu/cpu.h            |  14 +++++
43fe83
 src/cpu/cpu_x86.c        | 135 +++++++++++++++++++++++++++++++++++++++--------
43fe83
 src/libvirt_private.syms |   2 +
43fe83
 4 files changed, 171 insertions(+), 21 deletions(-)
43fe83
43fe83
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
43fe83
index 4124354..7989b45 100644
43fe83
--- a/src/cpu/cpu.c
43fe83
+++ b/src/cpu/cpu.c
43fe83
@@ -438,6 +438,47 @@ cpuHasFeature(const virCPUDataPtr data,
43fe83
     return driver->hasFeature(data, feature);
43fe83
 }
43fe83
 
43fe83
+char *
43fe83
+cpuDataFormat(const virCPUData *data)
43fe83
+{
43fe83
+    struct cpuArchDriver *driver;
43fe83
+
43fe83
+    VIR_DEBUG("data=%p", data);
43fe83
+
43fe83
+    if (!(driver = cpuGetSubDriver(data->arch)))
43fe83
+        return NULL;
43fe83
+
43fe83
+    if (!driver->dataFormat) {
43fe83
+        virReportError(VIR_ERR_NO_SUPPORT,
43fe83
+                       _("cannot format %s CPU data"),
43fe83
+                       virArchToString(data->arch));
43fe83
+        return NULL;
43fe83
+    }
43fe83
+
43fe83
+    return driver->dataFormat(data);
43fe83
+}
43fe83
+
43fe83
+virCPUDataPtr
43fe83
+cpuDataParse(virArch arch,
43fe83
+             const char *xmlStr)
43fe83
+{
43fe83
+    struct cpuArchDriver *driver;
43fe83
+
43fe83
+    VIR_DEBUG("arch=%s, xmlStr=%s", virArchToString(arch), xmlStr);
43fe83
+
43fe83
+    if (!(driver = cpuGetSubDriver(arch)))
43fe83
+        return NULL;
43fe83
+
43fe83
+    if (!driver->dataParse) {
43fe83
+        virReportError(VIR_ERR_NO_SUPPORT,
43fe83
+                       _("cannot parse %s CPU data"),
43fe83
+                       virArchToString(arch));
43fe83
+        return NULL;
43fe83
+    }
43fe83
+
43fe83
+    return driver->dataParse(xmlStr);
43fe83
+}
43fe83
+
43fe83
 bool
43fe83
 cpuModelIsAllowed(const char *model,
43fe83
                   const char **models,
43fe83
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
43fe83
index 4003435..7417f92 100644
43fe83
--- a/src/cpu/cpu.h
43fe83
+++ b/src/cpu/cpu.h
43fe83
@@ -91,6 +91,11 @@ typedef int
43fe83
 (*cpuArchHasFeature) (const virCPUDataPtr data,
43fe83
                       const char *feature);
43fe83
 
43fe83
+typedef char *
43fe83
+(*cpuArchDataFormat)(const virCPUData *data);
43fe83
+
43fe83
+typedef virCPUDataPtr
43fe83
+(*cpuArchDataParse) (const char *xmlStr);
43fe83
 
43fe83
 struct cpuArchDriver {
43fe83
     const char *name;
43fe83
@@ -105,6 +110,8 @@ struct cpuArchDriver {
43fe83
     cpuArchBaseline     baseline;
43fe83
     cpuArchUpdate       update;
43fe83
     cpuArchHasFeature    hasFeature;
43fe83
+    cpuArchDataFormat   dataFormat;
43fe83
+    cpuArchDataParse    dataParse;
43fe83
 };
43fe83
 
43fe83
 
43fe83
@@ -171,4 +178,11 @@ cpuModelIsAllowed(const char *model,
43fe83
                   const char **models,
43fe83
                   unsigned int nmodels);
43fe83
 
43fe83
+/* cpuDataFormat and cpuDataParse are implemented for unit tests only and
43fe83
+ * have no real-life usage
43fe83
+ */
43fe83
+char *cpuDataFormat(const virCPUData *data);
43fe83
+virCPUDataPtr cpuDataParse(virArch arch,
43fe83
+                           const char *xmlStr);
43fe83
+
43fe83
 #endif /* __VIR_CPU_H__ */
43fe83
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
43fe83
index a388f0f..0bc031b 100644
43fe83
--- a/src/cpu/cpu_x86.c
43fe83
+++ b/src/cpu/cpu_x86.c
43fe83
@@ -666,12 +666,42 @@ x86FeatureNames(const struct x86_map *map,
43fe83
 
43fe83
 
43fe83
 static int
43fe83
+x86ParseCPUID(xmlXPathContextPtr ctxt,
43fe83
+              struct cpuX86cpuid *cpuid)
43fe83
+{
43fe83
+    unsigned long fun, eax, ebx, ecx, edx;
43fe83
+    int ret_fun, ret_eax, ret_ebx, ret_ecx, ret_edx;
43fe83
+
43fe83
+    memset(cpuid, 0, sizeof(*cpuid));
43fe83
+
43fe83
+    fun = eax = ebx = ecx = edx = 0;
43fe83
+    ret_fun = virXPathULongHex("string(@function)", ctxt, &fun);
43fe83
+    ret_eax = virXPathULongHex("string(@eax)", ctxt, &eax;;
43fe83
+    ret_ebx = virXPathULongHex("string(@ebx)", ctxt, &ebx);
43fe83
+    ret_ecx = virXPathULongHex("string(@ecx)", ctxt, &ecx;;
43fe83
+    ret_edx = virXPathULongHex("string(@edx)", ctxt, &edx;;
43fe83
+
43fe83
+    if (ret_fun < 0 || ret_eax == -2 || ret_ebx == -2
43fe83
+        || ret_ecx == -2 || ret_edx == -2)
43fe83
+        return -1;
43fe83
+
43fe83
+    cpuid->function = fun;
43fe83
+    cpuid->eax = eax;
43fe83
+    cpuid->ebx = ebx;
43fe83
+    cpuid->ecx = ecx;
43fe83
+    cpuid->edx = edx;
43fe83
+    return 0;
43fe83
+}
43fe83
+
43fe83
+
43fe83
+static int
43fe83
 x86FeatureLoad(xmlXPathContextPtr ctxt,
43fe83
                struct x86_map *map)
43fe83
 {
43fe83
     xmlNodePtr *nodes = NULL;
43fe83
     xmlNodePtr ctxt_node = ctxt->node;
43fe83
     struct x86_feature *feature;
43fe83
+    struct cpuX86cpuid cpuid;
43fe83
     int ret = 0;
43fe83
     size_t i;
43fe83
     int n;
43fe83
@@ -697,31 +727,13 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
43fe83
         goto ignore;
43fe83
 
43fe83
     for (i = 0; i < n; i++) {
43fe83
-        struct cpuX86cpuid cpuid;
43fe83
-        unsigned long fun, eax, ebx, ecx, edx;
43fe83
-        int ret_fun, ret_eax, ret_ebx, ret_ecx, ret_edx;
43fe83
-
43fe83
         ctxt->node = nodes[i];
43fe83
-        fun = eax = ebx = ecx = edx = 0;
43fe83
-        ret_fun = virXPathULongHex("string(@function)", ctxt, &fun);
43fe83
-        ret_eax = virXPathULongHex("string(@eax)", ctxt, &eax;;
43fe83
-        ret_ebx = virXPathULongHex("string(@ebx)", ctxt, &ebx);
43fe83
-        ret_ecx = virXPathULongHex("string(@ecx)", ctxt, &ecx;;
43fe83
-        ret_edx = virXPathULongHex("string(@edx)", ctxt, &edx;;
43fe83
-
43fe83
-        if (ret_fun < 0 || ret_eax == -2 || ret_ebx == -2
43fe83
-            || ret_ecx == -2 || ret_edx == -2) {
43fe83
+        if (x86ParseCPUID(ctxt, &cpuid) < 0) {
43fe83
             virReportError(VIR_ERR_INTERNAL_ERROR,
43fe83
-                           _("Invalid cpuid[%zu] in %s feature"), i, feature->name);
43fe83
+                           _("Invalid cpuid[%zu] in %s feature"),
43fe83
+                           i, feature->name);
43fe83
             goto ignore;
43fe83
         }
43fe83
-
43fe83
-        cpuid.function = fun;
43fe83
-        cpuid.eax = eax;
43fe83
-        cpuid.ebx = ebx;
43fe83
-        cpuid.ecx = ecx;
43fe83
-        cpuid.edx = edx;
43fe83
-
43fe83
         if (x86DataAddCpuid(feature->data, &cpuid))
43fe83
             goto error;
43fe83
     }
43fe83
@@ -1124,6 +1136,85 @@ error:
43fe83
 }
43fe83
 
43fe83
 
43fe83
+static char *
43fe83
+x86CPUDataFormat(const virCPUData *data)
43fe83
+{
43fe83
+    struct data_iterator iter = DATA_ITERATOR_INIT(data->data.x86);
43fe83
+    struct cpuX86cpuid *cpuid;
43fe83
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
43fe83
+
43fe83
+    virBufferAddLit(&buf, "<cpudata arch='x86'>\n");
43fe83
+    while ((cpuid = x86DataCpuidNext(&iter))) {
43fe83
+        virBufferAsprintf(&buf,
43fe83
+                          "  
43fe83
+                          " eax='0x%08x' ebx='0x%08x'"
43fe83
+                          " ecx='0x%08x' edx='0x%08x'/>\n",
43fe83
+                          cpuid->function,
43fe83
+                          cpuid->eax, cpuid->ebx, cpuid->ecx, cpuid->edx);
43fe83
+    }
43fe83
+    virBufferAddLit(&buf, "</cpudata>\n");
43fe83
+
43fe83
+    if (virBufferError(&buf)) {
43fe83
+        virBufferFreeAndReset(&buf;;
43fe83
+        virReportOOMError();
43fe83
+        return NULL;
43fe83
+    }
43fe83
+
43fe83
+    return virBufferContentAndReset(&buf;;
43fe83
+}
43fe83
+
43fe83
+
43fe83
+static virCPUDataPtr
43fe83
+x86CPUDataParse(const char *xmlStr)
43fe83
+{
43fe83
+    xmlDocPtr xml = NULL;
43fe83
+    xmlXPathContextPtr ctxt = NULL;
43fe83
+    xmlNodePtr *nodes = NULL;
43fe83
+    virCPUDataPtr cpuData = NULL;
43fe83
+    struct cpuX86Data *data = NULL;
43fe83
+    struct cpuX86cpuid cpuid;
43fe83
+    size_t i;
43fe83
+    int n;
43fe83
+
43fe83
+    if (VIR_ALLOC(data) < 0)
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    if (!(xml = virXMLParseStringCtxt(xmlStr, _("CPU data"), &ctxt))) {
43fe83
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
43fe83
+                       _("cannot parse CPU data"));
43fe83
+        goto cleanup;
43fe83
+    }
43fe83
+    ctxt->node = xmlDocGetRootElement(xml);
43fe83
+
43fe83
+    n = virXPathNodeSet("/cpudata[@arch='x86']/data", ctxt, &nodes);
43fe83
+    if (n < 0) {
43fe83
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
43fe83
+                       _("no x86 CPU data found"));
43fe83
+        goto cleanup;
43fe83
+    }
43fe83
+
43fe83
+    for (i = 0; i < n; i++) {
43fe83
+        ctxt->node = nodes[i];
43fe83
+        if (x86ParseCPUID(ctxt, &cpuid) < 0) {
43fe83
+            virReportError(VIR_ERR_INTERNAL_ERROR,
43fe83
+                           _("failed to parse cpuid[%zu]"), i);
43fe83
+            goto cleanup;
43fe83
+        }
43fe83
+        if (x86DataAddCpuid(data, &cpuid) < 0)
43fe83
+            goto cleanup;
43fe83
+    }
43fe83
+
43fe83
+    cpuData = x86MakeCPUData(VIR_ARCH_X86_64, &data);
43fe83
+
43fe83
+cleanup:
43fe83
+    VIR_FREE(nodes);
43fe83
+    xmlXPathFreeContext(ctxt);
43fe83
+    xmlFreeDoc(xml);
43fe83
+    x86DataFree(data);
43fe83
+    return cpuData;
43fe83
+}
43fe83
+
43fe83
+
43fe83
 /* A helper macro to exit the cpu computation function without writing
43fe83
  * redundant code:
43fe83
  * MSG: error message
43fe83
@@ -1920,4 +2011,6 @@ struct cpuArchDriver cpuDriverX86 = {
43fe83
     .baseline   = x86Baseline,
43fe83
     .update     = x86Update,
43fe83
     .hasFeature = x86HasFeature,
43fe83
+    .dataFormat = x86CPUDataFormat,
43fe83
+    .dataParse  = x86CPUDataParse,
43fe83
 };
43fe83
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
43fe83
index ca6275c..722178b 100644
43fe83
--- a/src/libvirt_private.syms
43fe83
+++ b/src/libvirt_private.syms
43fe83
@@ -715,7 +715,9 @@ cpuBaseline;
43fe83
 cpuBaselineXML;
43fe83
 cpuCompare;
43fe83
 cpuCompareXML;
43fe83
+cpuDataFormat;
43fe83
 cpuDataFree;
43fe83
+cpuDataParse;
43fe83
 cpuDecode;
43fe83
 cpuEncode;
43fe83
 cpuGuestData;
43fe83
-- 
43fe83
1.8.4.2
43fe83