This will be needed directly in the QEMU driver in a later patch.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
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