a03d84
From a4968db599321fe4178423c50874260a21885223 Mon Sep 17 00:00:00 2001
a03d84
From: "Richard W.M. Jones" <rjones@redhat.com>
a03d84
Date: Fri, 4 Oct 2019 15:57:42 +0300
a03d84
Subject: [PATCH 5/8] Fix virt-what-cpuid-helper.
a03d84
a03d84
The value returned in %eax is the max_entry (eg. 0x40000000
a03d84
if there are no further leafs).  However it is not reliable.
a03d84
In addition if there are multiple leafs we should probably
a03d84
only print the highest one.
a03d84
a03d84
Also use uint32_t instead of unsigned int.
a03d84
a03d84
Thanks: Paolo Bonzini.
a03d84
(cherry picked from commit 0a0d9fa7c85c5474870cae37832d28ccd899d4ee)
a03d84
---
a03d84
 virt-what-cpuid-helper.c | 67 ++++++++++++++++++++++++++++------------
a03d84
 1 file changed, 48 insertions(+), 19 deletions(-)
a03d84
a03d84
diff --git a/virt-what-cpuid-helper.c b/virt-what-cpuid-helper.c
a03d84
index 7812545..0cd4a6f 100644
a03d84
--- a/virt-what-cpuid-helper.c
a03d84
+++ b/virt-what-cpuid-helper.c
a03d84
@@ -1,5 +1,5 @@
a03d84
 /* virt-what-cpuid-helper: Are we running inside KVM or Xen HVM?
a03d84
- * Copyright (C) 2008 Red Hat Inc.
a03d84
+ * Copyright (C) 2008-2019 Red Hat Inc.
a03d84
  *
a03d84
  * This program is free software; you can redistribute it and/or modify
a03d84
  * it under the terms of the GNU General Public License as published by
a03d84
@@ -21,14 +21,35 @@
a03d84
  */
a03d84
 
a03d84
 #include <stdio.h>
a03d84
+#include <stdlib.h>
a03d84
+#include <stdint.h>
a03d84
 #include <string.h>
a03d84
 
a03d84
 #if defined(__i386__) || defined(__x86_64__)
a03d84
 
a03d84
-static unsigned int
a03d84
-cpuid (unsigned int eax, char *sig)
a03d84
+/* Known x86 hypervisor signatures.  Note that if you add a new test
a03d84
+ * to virt-what.in you may need to update this list.  The signature is
a03d84
+ * always 12 bytes except in the case of KVM.
a03d84
+ */
a03d84
+static int
a03d84
+known_signature (char *sig)
a03d84
 {
a03d84
-  unsigned int *sig32 = (unsigned int *) sig;
a03d84
+  return
a03d84
+    strcmp (sig, "bhyve bhyve ") == 0 ||
a03d84
+    strcmp (sig, "KVMKVMKVM") == 0 ||
a03d84
+    strcmp (sig, "LKVMLKVMLKVM") == 0 ||
a03d84
+    strcmp (sig, "Microsoft Hv") == 0 ||
a03d84
+    strcmp (sig, "OpenBSDVMM58") == 0 ||
a03d84
+    strcmp (sig, "TCGTCGTCGTCG") == 0 ||
a03d84
+    strcmp (sig, "VMwareVMware") == 0 ||
a03d84
+    strcmp (sig, "XenVMMXenVMM") == 0 ||
a03d84
+    0;
a03d84
+}
a03d84
+
a03d84
+static uint32_t
a03d84
+cpuid (uint32_t eax, char *sig)
a03d84
+{
a03d84
+  uint32_t *sig32 = (uint32_t *) sig;
a03d84
 
a03d84
   asm volatile (
a03d84
         "xchgl %%ebx,%1; xor %%ebx,%%ebx; cpuid; xchgl %%ebx,%1"
a03d84
@@ -43,24 +64,32 @@ static void
a03d84
 cpu_sig (void)
a03d84
 {
a03d84
   char sig[13];
a03d84
-  unsigned int base = 0x40000000, leaf = base;
a03d84
-  unsigned int max_entries;
a03d84
+  const uint32_t base = 0x40000000;
a03d84
+  uint32_t leaf;
a03d84
 
a03d84
-  memset (sig, 0, sizeof sig);
a03d84
-  max_entries = cpuid (leaf, sig);
a03d84
-  puts (sig);
a03d84
-
a03d84
-  /* Most hypervisors only have information in leaf 0x40000000, but
a03d84
-   * upstream Xen contains further leaf entries (in particular when
a03d84
-   * used with Viridian [HyperV] extensions).  CPUID is supposed to
a03d84
-   * return the maximum leaf offset in %eax, so that's what we use,
a03d84
-   * but only if it looks sensible.
a03d84
+  /* Most hypervisors only have information in leaf 0x40000000.
a03d84
+   *
a03d84
+   * Some hypervisors have "Viridian [HyperV] extensions", and those
a03d84
+   * must appear in slot 0x40000000, but they will also have the true
a03d84
+   * hypervisor in a higher slot.
a03d84
+   *
a03d84
+   * CPUID is supposed to return the maximum leaf offset in %eax, but
a03d84
+   * this is not reliable.  Instead we check the returned signatures
a03d84
+   * against a known list (the others will be empty or garbage) and
a03d84
+   * only print the ones we know about.  This is OK because if we add
a03d84
+   * a new test in virt-what we can update the list.
a03d84
+   *
a03d84
+   * By searching backwards we only print the highest entry, thus
a03d84
+   * ignoring Viridian for Xen (and Nutanix).  If we ever encounter a
a03d84
+   * hypervisor that has more than 2 entries we may need to revisit
a03d84
+   * this.
a03d84
    */
a03d84
-  if (max_entries > 3 && max_entries < 0x10000) {
a03d84
-    for (leaf = base + 0x100; leaf <= base + max_entries; leaf += 0x100) {
a03d84
-      memset (sig, 0, sizeof sig);
a03d84
-      cpuid (leaf, sig);
a03d84
+  for (leaf = base + 0xff00; leaf >= base; leaf -= 0x100) {
a03d84
+    memset (sig, 0, sizeof sig);
a03d84
+    cpuid (leaf, sig);
a03d84
+    if (known_signature (sig)) {
a03d84
       puts (sig);
a03d84
+      break;
a03d84
     }
a03d84
   }
a03d84
 }
a03d84
-- 
a03d84
2.32.0
a03d84