cpu_x86: Prepare for ecx_in CPUID parameter

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@redhat.com>
This commit is contained in:
Jiri Denemark 2016-05-20 10:59:13 +02:00
parent 7b7cc3aaec
commit f0fd7ae122
6 changed files with 51 additions and 36 deletions

View File

@ -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");
@ -1853,22 +1862,21 @@ cpuidCall(virCPUx86CPUID *cpuid)
{
# if __x86_64__
asm("xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */
"xor %%ecx, %%ecx;" /* functions may use them as additional */
"xor %%edx, %%edx;" /* arguments */
"xor %%edx, %%edx;" /* functions may use them as additional arguments */
"cpuid;"
: "=a" (cpuid->eax),
"=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
*/
asm("push %%ebx;"
"xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */
"xor %%ecx, %%ecx;" /* functions may use them as additional */
"xor %%edx, %%edx;" /* arguments */
"xor %%edx, %%edx;" /* functions may use them as additional arguments */
"cpuid;"
"mov %%ebx, %1;"
"pop %%ebx;"
@ -1876,7 +1884,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 +1896,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;

View File

@ -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;

View File

@ -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")) {

View File

@ -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>

View File

@ -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>

View File

@ -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>