[libvirt] [PATCH 02/10] cpu_x86: Prepare for ecx_in CPUID parameter

Jiri Denemark jdenemar at redhat.com
Wed Jun 8 12:41:30 UTC 2016


CPUID instruction normally takes its parameter from EAX, but sometimes
ECX is used as an additional parameter. This patch prepares the x86 CPU
driver code for the new 'ecx_in' CPUID parameter.

Signed-off-by: Jiri Denemark <jdenemar at redhat.com>
---
 src/cpu/cpu_x86.c                                  | 52 +++++++++++++---------
 src/cpu/cpu_x86_data.h                             |  1 +
 src/qemu/qemu_monitor_json.c                       |  4 ++
 .../qemumonitorjson-getcpu-ecx.data                | 10 ++---
 .../qemumonitorjson-getcpu-full.data               |  6 +--
 .../qemumonitorjson-getcpu-host.data               |  8 ++--
 6 files changed, 49 insertions(+), 32 deletions(-)

diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index 82921db..ae809de 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -40,7 +40,7 @@ VIR_LOG_INIT("cpu.cpu_x86");
 
 #define VENDOR_STRING_LENGTH    12
 
-static const virCPUx86CPUID cpuidNull = { 0, 0, 0, 0, 0 };
+static const virCPUx86CPUID cpuidNull = { 0 };
 
 static const virArch archs[] = { VIR_ARCH_I686, VIR_ARCH_X86_64 };
 
@@ -250,6 +250,11 @@ virCPUx86CPUIDSorter(const void *a, const void *b)
     else if (da->eax_in < db->eax_in)
         return -1;
 
+    if (da->ecx_in > db->ecx_in)
+        return 1;
+    else if (da->ecx_in < db->ecx_in)
+        return -1;
+
     return 0;
 }
 
@@ -274,12 +279,13 @@ x86DataCpuidNext(virCPUx86DataIteratorPtr iterator)
 
 static virCPUx86CPUID *
 x86DataCpuid(const virCPUx86Data *data,
-             uint32_t eax_in)
+             const virCPUx86CPUID *cpuid)
 {
     size_t i;
 
     for (i = 0; i < data->len; i++) {
-        if (data->data[i].eax_in == eax_in)
+        if (data->data[i].eax_in == cpuid->eax_in &&
+            data->data[i].ecx_in == cpuid->ecx_in)
             return data->data + i;
     }
 
@@ -345,7 +351,7 @@ virCPUx86DataAddCPUID(virCPUx86Data *data,
 {
     virCPUx86CPUID *existing;
 
-    if ((existing = x86DataCpuid(data, cpuid->eax_in))) {
+    if ((existing = x86DataCpuid(data, cpuid))) {
         x86cpuidSetBits(existing, cpuid);
     } else {
         if (VIR_APPEND_ELEMENT_COPY(data->data, data->len,
@@ -369,7 +375,7 @@ x86DataAdd(virCPUx86Data *data1,
     virCPUx86CPUID *cpuid2;
 
     while ((cpuid2 = x86DataCpuidNext(&iter))) {
-        cpuid1 = x86DataCpuid(data1, cpuid2->eax_in);
+        cpuid1 = x86DataCpuid(data1, cpuid2);
 
         if (cpuid1) {
             x86cpuidSetBits(cpuid1, cpuid2);
@@ -392,7 +398,7 @@ x86DataSubtract(virCPUx86Data *data1,
     virCPUx86CPUID *cpuid2;
 
     while ((cpuid1 = x86DataCpuidNext(&iter))) {
-        cpuid2 = x86DataCpuid(data2, cpuid1->eax_in);
+        cpuid2 = x86DataCpuid(data2, cpuid1);
         x86cpuidClearBits(cpuid1, cpuid2);
     }
 }
@@ -407,7 +413,7 @@ x86DataIntersect(virCPUx86Data *data1,
     virCPUx86CPUID *cpuid2;
 
     while ((cpuid1 = x86DataCpuidNext(&iter))) {
-        cpuid2 = x86DataCpuid(data2, cpuid1->eax_in);
+        cpuid2 = x86DataCpuid(data2, cpuid1);
         if (cpuid2)
             x86cpuidAndBits(cpuid1, cpuid2);
         else
@@ -435,7 +441,7 @@ x86DataIsSubset(const virCPUx86Data *data,
     const virCPUx86CPUID *cpuidSubset;
 
     while ((cpuidSubset = x86DataCpuidNext(&iter))) {
-        if (!(cpuid = x86DataCpuid(data, cpuidSubset->eax_in)) ||
+        if (!(cpuid = x86DataCpuid(data, cpuidSubset)) ||
             !x86cpuidMatchMasked(cpuid, cpuidSubset))
             return false;
     }
@@ -476,7 +482,7 @@ x86DataToVendor(const virCPUx86Data *data,
 
     for (i = 0; i < map->nvendors; i++) {
         virCPUx86VendorPtr vendor = map->vendors[i];
-        if ((cpuid = x86DataCpuid(data, vendor->cpuid.eax_in)) &&
+        if ((cpuid = x86DataCpuid(data, &vendor->cpuid)) &&
             x86cpuidMatchMasked(cpuid, &vendor->cpuid)) {
             x86cpuidClearBits(cpuid, &vendor->cpuid);
             return vendor;
@@ -592,6 +598,7 @@ x86VendorParse(xmlXPathContextPtr ctxt,
     }
 
     vendor->cpuid.eax_in = 0;
+    vendor->cpuid.ecx_in = 0;
     vendor->cpuid.ebx = virReadBufInt32LE(string);
     vendor->cpuid.edx = virReadBufInt32LE(string + 4);
     vendor->cpuid.ecx = virReadBufInt32LE(string + 8);
@@ -715,25 +722,27 @@ static int
 x86ParseCPUID(xmlXPathContextPtr ctxt,
               virCPUx86CPUID *cpuid)
 {
-    unsigned long eax_in;
+    unsigned long eax_in, ecx_in;
     unsigned long eax, ebx, ecx, edx;
-    int ret_eax_in, ret_eax, ret_ebx, ret_ecx, ret_edx;
+    int ret_eax_in, ret_ecx_in, ret_eax, ret_ebx, ret_ecx, ret_edx;
 
     memset(cpuid, 0, sizeof(*cpuid));
 
-    eax_in = 0;
+    eax_in = ecx_in = 0;
     eax = ebx = ecx = edx = 0;
     ret_eax_in = virXPathULongHex("string(@eax_in)", ctxt, &eax_in);
+    ret_ecx_in = virXPathULongHex("string(@ecx_in)", ctxt, &ecx_in);
     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_eax_in < 0 ||
+    if (ret_eax_in < 0 || ret_ecx_in == -2 ||
         ret_eax == -2 || ret_ebx == -2 || ret_ecx == -2 || ret_edx == -2)
         return -1;
 
     cpuid->eax_in = eax_in;
+    cpuid->ecx_in = ecx_in;
     cpuid->eax = eax;
     cpuid->ebx = ebx;
     cpuid->ecx = ecx;
@@ -1004,7 +1013,7 @@ x86ModelCompare(virCPUx86ModelPtr model1,
     while ((cpuid1 = x86DataCpuidNext(&iter1))) {
         virCPUx86CompareResult match = SUPERSET;
 
-        if ((cpuid2 = x86DataCpuid(&model2->data, cpuid1->eax_in))) {
+        if ((cpuid2 = x86DataCpuid(&model2->data, cpuid1))) {
             if (x86cpuidMatch(cpuid1, cpuid2))
                 continue;
             else if (!x86cpuidMatchMasked(cpuid1, cpuid2))
@@ -1020,7 +1029,7 @@ x86ModelCompare(virCPUx86ModelPtr model1,
     while ((cpuid2 = x86DataCpuidNext(&iter2))) {
         virCPUx86CompareResult match = SUBSET;
 
-        if ((cpuid1 = x86DataCpuid(&model1->data, cpuid2->eax_in))) {
+        if ((cpuid1 = x86DataCpuid(&model1->data, cpuid2))) {
             if (x86cpuidMatch(cpuid2, cpuid1))
                 continue;
             else if (!x86cpuidMatchMasked(cpuid2, cpuid1))
@@ -1265,10 +1274,10 @@ x86CPUDataFormat(const virCPUData *data)
     virBufferAddLit(&buf, "<cpudata arch='x86'>\n");
     while ((cpuid = x86DataCpuidNext(&iter))) {
         virBufferAsprintf(&buf,
-                          "  <cpuid eax_in='0x%08x'"
+                          "  <cpuid eax_in='0x%08x' ecx_in='0x%08x'"
                           " eax='0x%08x' ebx='0x%08x'"
                           " ecx='0x%08x' edx='0x%08x'/>\n",
-                          cpuid->eax_in,
+                          cpuid->eax_in, cpuid->ecx_in,
                           cpuid->eax, cpuid->ebx, cpuid->ecx, cpuid->edx);
     }
     virBufferAddLit(&buf, "</cpudata>\n");
@@ -1860,7 +1869,8 @@ cpuidCall(virCPUx86CPUID *cpuid)
           "=b" (cpuid->ebx),
           "=c" (cpuid->ecx),
           "=d" (cpuid->edx)
-        : "a" (cpuid->eax_in));
+        : "a" (cpuid->eax_in),
+          "c" (cpuid->ecx_in));
 # else
     /* we need to avoid direct use of ebx for CPUID output as it is used
      * for global offset table on i386 with -fPIC
@@ -1876,7 +1886,8 @@ cpuidCall(virCPUx86CPUID *cpuid)
           "=r" (cpuid->ebx),
           "=c" (cpuid->ecx),
           "=d" (cpuid->edx)
-        : "a" (cpuid->eax_in)
+        : "a" (cpuid->eax_in),
+          "c" (cpuid->ecx_in)
         : "cc");
 # endif
 }
@@ -1887,13 +1898,14 @@ cpuidSet(uint32_t base, virCPUx86Data *data)
 {
     uint32_t max;
     uint32_t i;
-    virCPUx86CPUID cpuid = { base, 0, 0, 0, 0 };
+    virCPUx86CPUID cpuid = { .eax_in = base };
 
     cpuidCall(&cpuid);
     max = cpuid.eax;
 
     for (i = base; i <= max; i++) {
         cpuid.eax_in = i;
+        cpuid.ecx_in = 0;
         cpuidCall(&cpuid);
         if (virCPUx86DataAddCPUID(data, &cpuid) < 0)
             return -1;
diff --git a/src/cpu/cpu_x86_data.h b/src/cpu/cpu_x86_data.h
index 75f7b30..4660ab6 100644
--- a/src/cpu/cpu_x86_data.h
+++ b/src/cpu/cpu_x86_data.h
@@ -29,6 +29,7 @@
 typedef struct _virCPUx86CPUID virCPUx86CPUID;
 struct _virCPUx86CPUID {
     uint32_t eax_in;
+    uint32_t ecx_in;
     uint32_t eax;
     uint32_t ebx;
     uint32_t ecx;
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 2cb0198..12d2e22 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -6364,6 +6364,7 @@ qemuMonitorJSONParseCPUx86FeatureWord(virJSONValuePtr data,
 {
     const char *reg;
     unsigned long long eax_in;
+    unsigned long long ecx_in = 0;
     unsigned long long features;
 
     memset(cpuid, 0, sizeof(*cpuid));
@@ -6378,6 +6379,8 @@ qemuMonitorJSONParseCPUx86FeatureWord(virJSONValuePtr data,
                        _("missing or invalid cpuid-input-eax in CPU data"));
         return -1;
     }
+    ignore_value(virJSONValueObjectGetNumberUlong(data, "cpuid-input-ecx",
+                                                  &ecx_in));
     if (virJSONValueObjectGetNumberUlong(data, "features", &features) < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("missing or invalid features in CPU data"));
@@ -6385,6 +6388,7 @@ qemuMonitorJSONParseCPUx86FeatureWord(virJSONValuePtr data,
     }
 
     cpuid->eax_in = eax_in;
+    cpuid->ecx_in = ecx_in;
     if (STREQ(reg, "EAX")) {
         cpuid->eax = features;
     } else if (STREQ(reg, "EBX")) {
diff --git a/tests/qemumonitorjsondata/qemumonitorjson-getcpu-ecx.data b/tests/qemumonitorjsondata/qemumonitorjson-getcpu-ecx.data
index c39e3dc..457bbbe 100644
--- a/tests/qemumonitorjsondata/qemumonitorjson-getcpu-ecx.data
+++ b/tests/qemumonitorjsondata/qemumonitorjson-getcpu-ecx.data
@@ -1,7 +1,7 @@
 <cpudata arch='x86'>
-  <cpuid eax_in='0x00000001' eax='0x00000000' ebx='0x00000000' ecx='0xf7fa3203' edx='0x0f8bfbff'/>
-  <cpuid eax_in='0x00000007' eax='0x00000000' ebx='0x001c0fbb' ecx='0x00000000' edx='0x00000000'/>
-  <cpuid eax_in='0x0000000d' eax='0x00000001' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
-  <cpuid eax_in='0x40000001' eax='0x010000fb' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
-  <cpuid eax_in='0x80000001' eax='0x00000000' ebx='0x00000000' ecx='0x00000121' edx='0x2c100800'/>
+  <cpuid eax_in='0x00000001' ecx_in='0x00000000' eax='0x00000000' ebx='0x00000000' ecx='0xf7fa3203' edx='0x0f8bfbff'/>
+  <cpuid eax_in='0x00000007' ecx_in='0x00000000' eax='0x00000000' ebx='0x001c0fbb' ecx='0x00000000' edx='0x00000000'/>
+  <cpuid eax_in='0x0000000d' ecx_in='0x00000001' eax='0x00000001' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
+  <cpuid eax_in='0x40000001' ecx_in='0x00000000' eax='0x010000fb' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
+  <cpuid eax_in='0x80000001' ecx_in='0x00000000' eax='0x00000000' ebx='0x00000000' ecx='0x00000121' edx='0x2c100800'/>
 </cpudata>
diff --git a/tests/qemumonitorjsondata/qemumonitorjson-getcpu-full.data b/tests/qemumonitorjsondata/qemumonitorjson-getcpu-full.data
index 87a8fb1..b581821 100644
--- a/tests/qemumonitorjsondata/qemumonitorjson-getcpu-full.data
+++ b/tests/qemumonitorjsondata/qemumonitorjson-getcpu-full.data
@@ -1,5 +1,5 @@
 <cpudata arch='x86'>
-  <cpuid eax_in='0x00000001' eax='0x00000000' ebx='0x00000000' ecx='0x97ba2223' edx='0x078bfbfd'/>
-  <cpuid eax_in='0x40000001' eax='0x0100003b' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
-  <cpuid eax_in='0x80000001' eax='0x00000000' ebx='0x00000000' ecx='0x00000001' edx='0x28100800'/>
+  <cpuid eax_in='0x00000001' ecx_in='0x00000000' eax='0x00000000' ebx='0x00000000' ecx='0x97ba2223' edx='0x078bfbfd'/>
+  <cpuid eax_in='0x40000001' ecx_in='0x00000000' eax='0x0100003b' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
+  <cpuid eax_in='0x80000001' ecx_in='0x00000000' eax='0x00000000' ebx='0x00000000' ecx='0x00000001' edx='0x28100800'/>
 </cpudata>
diff --git a/tests/qemumonitorjsondata/qemumonitorjson-getcpu-host.data b/tests/qemumonitorjsondata/qemumonitorjson-getcpu-host.data
index 83bafe1..a4c503e 100644
--- a/tests/qemumonitorjsondata/qemumonitorjson-getcpu-host.data
+++ b/tests/qemumonitorjsondata/qemumonitorjson-getcpu-host.data
@@ -1,6 +1,6 @@
 <cpudata arch='x86'>
-  <cpuid eax_in='0x00000001' eax='0x00000000' ebx='0x00000000' ecx='0x97ba2223' edx='0x0f8bfbff'/>
-  <cpuid eax_in='0x00000007' eax='0x00000000' ebx='0x00000002' ecx='0x00000000' edx='0x00000000'/>
-  <cpuid eax_in='0x40000001' eax='0x0100007b' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
-  <cpuid eax_in='0x80000001' eax='0x00000000' ebx='0x00000000' ecx='0x00000001' edx='0x2993fbff'/>
+  <cpuid eax_in='0x00000001' ecx_in='0x00000000' eax='0x00000000' ebx='0x00000000' ecx='0x97ba2223' edx='0x0f8bfbff'/>
+  <cpuid eax_in='0x00000007' ecx_in='0x00000000' eax='0x00000000' ebx='0x00000002' ecx='0x00000000' edx='0x00000000'/>
+  <cpuid eax_in='0x40000001' ecx_in='0x00000000' eax='0x0100007b' ebx='0x00000000' ecx='0x00000000' edx='0x00000000'/>
+  <cpuid eax_in='0x80000001' ecx_in='0x00000000' eax='0x00000000' ebx='0x00000000' ecx='0x00000001' edx='0x2993fbff'/>
 </cpudata>
-- 
2.8.4




More information about the libvir-list mailing list