Blame SOURCES/0018-Fix-virt-what-cpuid-helper.patch

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