On Wed, Jun 08, 2016 at 14:41:31 +0200, Jiri Denemark wrote: > This patch makes our CPUID handling code up-to-date with the current > specification found in > > Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 2A > http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html > > Signed-off-by: Jiri Denemark <jdenemar@xxxxxxxxxx> > --- > src/cpu/cpu_map.xml | 1 - > src/cpu/cpu_x86.c | 278 ++++++++++++++++++++++++++++++++++++++++++++++++++-- > 2 files changed, 269 insertions(+), 10 deletions(-) > [] > @@ -1862,8 +1862,7 @@ 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), > @@ -1877,8 +1876,7 @@ cpuidCall(virCPUx86CPUID *cpuid) > */ > 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;" As said. This belongs to previous patch. > @@ -1893,21 +1891,283 @@ cpuidCall(virCPUx86CPUID *cpuid) > } > > > +/* Leaf 0x4 Deterministic cache parameters. This leaf is borderline useful for CPU identification. > + * > + * Sub leaf n+1 is invalid if eax[4:0] in sub leaf n equals 0. > + */ > +static int > +cpuidSetLeaf4(virCPUx86Data *data, > + virCPUx86CPUID *subLeaf0) > +{ > + virCPUx86CPUID cpuid = *subLeaf0; > + > + if (virCPUx86DataAddCPUID(data, subLeaf0) < 0) > + return -1; > + > + while (cpuid.eax & 0x1f) { > + cpuid.ecx_in++; > + cpuidCall(&cpuid); > + if (virCPUx86DataAddCPUID(data, &cpuid) < 0) > + return -1; > + } > + return 0; > +} > + > + > +/* Leaf 0x7 Structured extended feature flags enumeration. Very useful. Although it looks like all the data is currently reported with ECX == 0. > + * > + * Sub leaf n is invalid if n > eax in sub leaf 0. > + */ > +static int > +cpuidSetLeaf7(virCPUx86Data *data, > + virCPUx86CPUID *subLeaf0) > +{ > + virCPUx86CPUID cpuid = { .eax_in = 0x7 }; > + uint32_t sub; > + > + if (virCPUx86DataAddCPUID(data, subLeaf0) < 0) > + return -1; > + > + for (sub = 1; sub <= subLeaf0->eax; sub++) { > + cpuid.ecx_in = sub; > + cpuidCall(&cpuid); > + if (virCPUx86DataAddCPUID(data, &cpuid) < 0) > + return -1; > + } > + return 0; > +} > + > + > +/* Leaf 0xb Extended topology enumeration > + * > + * Sub leaf n is invalid if it returns 0 in ecx[15:8]. > + * Sub leaf n+1 is invalid if sub leaf n is invalid. > + * Some output values do not depend on ecx, thus sub leaf 0 provides > + * meaningful data even if it was (theoretically) considered invalid. Mostly EDX which reports APIC ID of the current processor which is volatile anyways. Not sure whether it's worth collecting this leaf at all since the returned data depend very specifically on the cpu where it's executed. Also as we don't call it for all cpus it might be pre-empted to a different CPU while enumerating. > + */ > +static int > +cpuidSetLeafB(virCPUx86Data *data, > + virCPUx86CPUID *subLeaf0) > +{ > + virCPUx86CPUID cpuid = *subLeaf0; > + > + while (cpuid.ecx & 0xff00) { > + if (virCPUx86DataAddCPUID(data, &cpuid) < 0) > + return -1; > + cpuid.ecx_in++; > + cpuidCall(&cpuid); > + } > + return 0; > +} > + > + > +/* Leaf 0xd processor extended state enumeration > + * > + * Sub leaves 0 and 1 are valid. > + * Sub leaf n (2 <= n < 32) is invalid if eax[n] from sub leaf 0 is not set > + * and ecx[n] from sub leaf 1 is not set. > + * Sub leaf n (32 <= n < 64) is invalid if edx[n-32] from sub leaf 0 is not set > + * and edx[n-32] from sub leaf 1 is not set. > + */ > +static int > +cpuidSetLeafD(virCPUx86Data *data, > + virCPUx86CPUID *subLeaf0) > +{ > + virCPUx86CPUID cpuid = { .eax_in = 0xd }; > + virCPUx86CPUID sub0; > + virCPUx86CPUID sub1; > + uint32_t sub; > + > + if (virCPUx86DataAddCPUID(data, subLeaf0) < 0) > + return -1; > + > + cpuid.ecx_in = 1; > + cpuidCall(&cpuid); > + if (virCPUx86DataAddCPUID(data, &cpuid) < 0) > + return -1; > + > + sub0 = *subLeaf0; > + sub1 = cpuid; > + for (sub = 2; sub < 64; sub++) { > + if (sub < 32 && > + !(sub0.eax & (1 << sub)) && > + !(sub1.ecx & (1 << sub))) > + continue; > + if (sub >= 32 && > + !(sub0.edx & (1 << (sub - 32))) && > + !(sub1.edx & (1 << (sub - 32)))) > + continue; > + > + cpuid.ecx_in = sub; > + cpuidCall(&cpuid); > + if (virCPUx86DataAddCPUID(data, &cpuid) < 0) > + return -1; > + } > + return 0; > +} > + > + > +/* Leaf 0xf, 0x10 0x0f - L3 cached RDT monitoring capability enumeration 0x10 - RDT allocation enumeration > + * > + * res reports valid resource identification (ResID) starting at bit 1. > + * Values associated with each valid ResID are reported by ResID sub leaf. > + * > + * 0xf: Sub leaf n is valid if edx[n] (= res[ResID]) from sub leaf 0 is set. > + * 0x10: Sub leaf n is valid if ebx[n] (= res[ResID]) from sub leaf 0 is set. > + */ > +static int > +cpuidSetLeafResID(virCPUx86Data *data, > + virCPUx86CPUID *subLeaf0, > + uint32_t res) > +{ > + virCPUx86CPUID cpuid = { .eax_in = subLeaf0->eax_in }; > + uint32_t sub; > + > + if (virCPUx86DataAddCPUID(data, subLeaf0) < 0) > + return -1; > + > + for (sub = 1; sub < 32; sub++) { > + if (!(res & (1 << sub))) > + continue; > + cpuid.ecx_in = sub; > + cpuidCall(&cpuid); > + if (virCPUx86DataAddCPUID(data, &cpuid) < 0) > + return -1; > + } > + return 0; > +} > + > + > +/* Leaf 0x12 SGX Capability enumeration > + * > + * Sub leaves 0 and 1 is supported if ebx[2] from leaf 0x7 (SGX) is set. > + * Sub leaves n >= 2 are valid as long as eax[3:0] != 0. > + */ > +static int > +cpuidSetLeaf12(virCPUx86Data *data, > + virCPUx86CPUID *subLeaf0) > +{ > + virCPUx86CPUID cpuid = { .eax_in = 0x7 }; > + virCPUx86CPUID *cpuid7; > + > + if (!(cpuid7 = x86DataCpuid(data, &cpuid)) || > + !(cpuid7->ebx & (1 << 2))) > + return 0; > + > + if (virCPUx86DataAddCPUID(data, subLeaf0) < 0) > + return -1; > + > + cpuid.eax_in = 0x12; > + cpuid.ecx_in = 1; > + cpuidCall(&cpuid); > + if (virCPUx86DataAddCPUID(data, &cpuid) < 0) > + return -1; > + > + cpuid.ecx_in = 2; > + cpuidCall(&cpuid); > + while (cpuid.eax & 0xf) { > + if (virCPUx86DataAddCPUID(data, &cpuid) < 0) > + return -1; > + cpuid.ecx_in++; > + cpuidCall(&cpuid); > + } > + return 0; > +} > + > + > +/* Leaf 0x14 Processor trace enumeration This function is the same as for 0x07 > + * > + * Sub leaf 0 reports the maximum supported sub leaf in eax. > + */ > +static int > +cpuidSetLeaf14(virCPUx86Data *data, > + virCPUx86CPUID *subLeaf0) > +{ > + virCPUx86CPUID cpuid = { .eax_in = 0x14 }; > + uint32_t sub; > + > + if (virCPUx86DataAddCPUID(data, subLeaf0) < 0) > + return -1; > + > + for (sub = 1; sub <= subLeaf0->eax; sub++) { > + cpuid.ecx_in = sub; > + cpuidCall(&cpuid); > + if (virCPUx86DataAddCPUID(data, &cpuid) < 0) > + return -1; > + } > + return 0; > +} > + > + > +/* Leaf 0x17 SOC Vendor > + * > + * Sub leaf 0 is valid if eax >= 3. > + * Sub leaf 0 reports the maximum supported sub leaf in eax. > + */ > +static int > +cpuidSetLeaf17(virCPUx86Data *data, > + virCPUx86CPUID *subLeaf0) > +{ > + virCPUx86CPUID cpuid = { .eax_in = 0x17 }; > + uint32_t sub; > + > + if (subLeaf0->eax < 3) > + return 0; > + > + if (virCPUx86DataAddCPUID(data, subLeaf0) < 0) > + return -1; > + > + for (sub = 1; sub <= subLeaf0->eax; sub++) { > + cpuid.ecx_in = sub; > + cpuidCall(&cpuid); > + if (virCPUx86DataAddCPUID(data, &cpuid) < 0) > + return -1; > + } > + return 0; > +} Most of the data collected in other leaves is not very useful for cpu identification for our purposes but that's true also for the main leaves (ECX=0). ACK. I'd appreciate if you added names for the leaves for future reference (not everyone enjoys reading through the x86_64 reference) but it's not strictly required. -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list