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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list