Simplify and fix invocation of cpuid.
[virt-what.git] / virt-what-cpuid-helper.c
index 0cd4a6f..fdceb62 100644 (file)
 #if defined(__i386__) || defined(__x86_64__)
 
 /* Known x86 hypervisor signatures.  Note that if you add a new test
- * to virt-what.in you may need to update this list.  The signature is
- * always 12 bytes except in the case of KVM.
+ * to virt-what.in you may need to update this list.  Note the
+ * signature is always 12 bytes long, plus we add \0 to the end to
+ * make it 13 bytes.
  */
 static int
-known_signature (char *sig)
+known_signature (const char *sig)
 {
   return
     strcmp (sig, "bhyve bhyve ") == 0 ||
-    strcmp (sig, "KVMKVMKVM") == 0 ||
+    memcmp (sig, "KVMKVMKVM\0\0\0", 12) == 0 ||
     strcmp (sig, "LKVMLKVMLKVM") == 0 ||
     strcmp (sig, "Microsoft Hv") == 0 ||
     strcmp (sig, "OpenBSDVMM58") == 0 ||
@@ -46,17 +47,25 @@ known_signature (char *sig)
     0;
 }
 
+/* Copied from the Linux kernel definition in
+ * arch/x86/include/asm/processor.h
+ */
+static inline void
+cpuid (uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
+{
+  asm volatile ("cpuid"
+                : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
+                : "0" (*eax), "2" (*ecx)
+                : "memory");
+}
+
 static uint32_t
-cpuid (uint32_t eax, char *sig)
+cpuid_leaf (uint32_t eax, char *sig)
 {
   uint32_t *sig32 = (uint32_t *) sig;
 
-  asm volatile (
-        "xchgl %%ebx,%1; xor %%ebx,%%ebx; cpuid; xchgl %%ebx,%1"
-        : "=a" (eax), "+r" (sig32[0]), "=c" (sig32[1]), "=d" (sig32[2])
-        : "0" (eax));
-  sig[12] = 0;
-
+  cpuid (&eax, &sig32[0], &sig32[1], &sig32[2]);
+  sig[12] = 0; /* \0-terminate the string to make string comparison possible */
   return eax;
 }
 
@@ -86,7 +95,7 @@ cpu_sig (void)
    */
   for (leaf = base + 0xff00; leaf >= base; leaf -= 0x100) {
     memset (sig, 0, sizeof sig);
-    cpuid (leaf, sig);
+    cpuid_leaf (leaf, sig);
     if (known_signature (sig)) {
       puts (sig);
       break;