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

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