This will be needed directly in the QEMU driver in a later patch. Signed-off-by: Daniel P. Berrangé <berrange@xxxxxxxxxx> --- src/cpu/cpu_x86.c | 34 +++++------------------ src/libvirt_private.syms | 1 + src/util/virhostcpu.c | 58 ++++++++++++++++++++++++++++++++++++++++ src/util/virhostcpu.h | 7 +++++ 4 files changed, 72 insertions(+), 28 deletions(-) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 0b2ff82d40..5cb9caef8a 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2377,34 +2377,12 @@ virCPUx86DataCheckFeature(const virCPUData *data, static inline void cpuidCall(virCPUx86CPUID *cpuid) { -# if __x86_64__ - asm("xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */ - "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), - "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 %%edx, %%edx;" /* functions may use them as additional arguments */ - "cpuid;" - "mov %%ebx, %1;" - "pop %%ebx;" - : "=a" (cpuid->eax), - "=r" (cpuid->ebx), - "=c" (cpuid->ecx), - "=d" (cpuid->edx) - : "a" (cpuid->eax_in), - "c" (cpuid->ecx_in) - : "cc"); -# endif + virHostCPUX86GetCPUID(cpuid->eax_in, + cpuid->ecx_in, + &cpuid->eax, + &cpuid->ebx, + &cpuid->ecx, + &cpuid->edx); } diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index da27ee7b53..53262e25b7 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2417,6 +2417,7 @@ virHostCPUGetThreadsPerSubcore; virHostCPUHasBitmap; virHostCPUReadSignature; virHostCPUStatsAssign; +virHostCPUX86GetCPUID; # util/virhostmem.h diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c index 54e2462a95..a07c00a0e9 100644 --- a/src/util/virhostcpu.c +++ b/src/util/virhostcpu.c @@ -1583,3 +1583,61 @@ virHostCPUGetHaltPollTime(pid_t pid, return 0; } + +void +virHostCPUX86GetCPUID(uint32_t leaf G_GNUC_UNUSED, + uint32_t extended G_GNUC_UNUSED, + uint32_t *eax, + uint32_t *ebx, + uint32_t *ecx, + uint32_t *edx) +{ +#if defined(__i386__) || defined(__x86_64__) + uint32_t out[4]; +# if __x86_64__ + asm("xor %%ebx, %%ebx;" /* clear the other registers as some cpuid */ + "xor %%edx, %%edx;" /* functions may use them as additional arguments */ + "cpuid;" + : "=a" (out[0]), + "=b" (out[1]), + "=c" (out[2]), + "=d" (out[3]) + : "a" (leaf), + "c" (extended)); +# 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 %%edx, %%edx;" /* functions may use them as additional arguments */ + "cpuid;" + "mov %%ebx, %1;" + "pop %%ebx;" + : "=a" (out[0]), + "=r" (out[1]), + "=c" (out[2]), + "=d" (out[3]) + : "a" (leaf), + "c" (extended) + : "cc"); +# endif + if (eax) + *eax = out[0]; + if (ebx) + *ebx = out[1]; + if (ecx) + *ecx = out[2]; + if (edx) + *edx = out[3]; +#else + if (eax) + *eax = 0; + if (ebx) + *ebx = 0; + if (ecx) + *ecx = 0; + if (edx) + *edx = 0; +#endif +} diff --git a/src/util/virhostcpu.h b/src/util/virhostcpu.h index a96dd5afba..86a231daa2 100644 --- a/src/util/virhostcpu.h +++ b/src/util/virhostcpu.h @@ -89,3 +89,10 @@ int virHostCPUGetSignature(char **signature); int virHostCPUGetHaltPollTime(pid_t pid, unsigned long long *haltPollSuccess, unsigned long long *haltPollFail); + +void virHostCPUX86GetCPUID(uint32_t leaf, + uint32_t extended, + uint32_t *eax, + uint32_t *ebx, + uint32_t *ecx, + uint32_t *edx); -- 2.33.1