]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lscpu: improve vmware detection
authorRuediger Meier <ruediger.meier@ga-group.nl>
Tue, 20 May 2014 11:26:48 +0000 (11:26 +0000)
committerRuediger Meier <ruediger.meier@ga-group.nl>
Thu, 29 May 2014 11:17:46 +0000 (13:17 +0200)
This patch comes from openSUSE / SLE. Original author was probably
Petr Uzel.
Internal SUSE references: fate310255, sr226509

VMmware backdoor assembler code has been fixed for old clang compiler
(travis), see
see http://llvm.org/bugs/show_bug.cgi?id=9379

CC: Stanislav Brabec <sbrabec@suse.cz>
CC: Petr Uzel <petr.uzel@suse.cz>
Signed-off-by: Ruediger Meier <ruediger.meier@ga-group.nl>
sys-utils/lscpu.c

index 11224b0bc90fb79a65b227029967ee720cb00a02..3b3faf81ad8d7db328f0fad0a9c9525db0303638 100644 (file)
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#if defined(__x86_64__) || defined(__i386__)
+# define INCLUDE_VMWARE_BDOOR
+#endif
+
+#ifdef INCLUDE_VMWARE_BDOOR
+# include <stdint.h>
+# include <signal.h>
+# include <strings.h>
+# include <setjmp.h>
+# ifdef HAVE_sys_io_h
+#  include <sys/io.h>
+# endif
+#endif
+
 #include <libsmartcols.h>
 
 #include "cpuset.h"
@@ -574,7 +588,7 @@ read_hypervisor_cpuid(struct lscpu_desc *desc)
                desc->hyper = HYPER_VMWARE;
 }
 
-#else  /* ! __x86_64__ */
+#else /* ! (__x86_64__ || __i386__) */
 static void
 read_hypervisor_cpuid(struct lscpu_desc *desc __attribute__((__unused__)))
 {
@@ -636,6 +650,71 @@ read_hypervisor_powerpc(struct lscpu_desc *desc)
        return desc->hyper;
 }
 
+#ifdef INCLUDE_VMWARE_BDOOR
+
+#define VMWARE_BDOOR_MAGIC          0x564D5868
+#define VMWARE_BDOOR_PORT           0x5658
+#define VMWARE_BDOOR_CMD_GETVERSION 10
+
+#define VMWARE_BDOOR(eax, ebx, ecx, edx)                                  \
+        __asm__("inl (%%dx), %%eax" :                                     \
+               "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) :               \
+               "0"(VMWARE_BDOOR_MAGIC), "1"(VMWARE_BDOOR_CMD_GETVERSION), \
+               "2"(VMWARE_BDOOR_PORT), "3"(0) :                           \
+               "memory");
+
+static jmp_buf segv_handler_env;
+
+static void
+segv_handler(__attribute__((__unused__)) int sig,
+             __attribute__((__unused__)) siginfo_t *info,
+             __attribute__((__unused__)) void *ignored)
+{
+       siglongjmp(segv_handler_env, 1);
+}
+
+static int
+is_vmware_platform(void)
+{
+       uint32_t eax, ebx, ecx, edx;
+       struct sigaction act, oact;
+
+       /*
+        * The assembly routine for vmware detection works
+        * fine under vmware, even if ran as regular user. But
+        * on real HW or under other hypervisors, it segfaults (which is
+        * expected). So we temporarily install SIGSEGV handler to catch
+        * the signal. All this magic is needed because lscpu
+        * isn't supposed to require root privileges.
+        */
+       if (sigsetjmp(segv_handler_env, 1))
+               return 0;
+
+       bzero(&act, sizeof(act));
+       act.sa_sigaction = segv_handler;
+       act.sa_flags = SA_SIGINFO;
+
+       if (sigaction(SIGSEGV, &act, &oact))
+               err(EXIT_FAILURE, _("error: can not set signal handler"));
+
+       VMWARE_BDOOR(eax, ebx, ecx, edx);
+
+       if (sigaction(SIGSEGV, &oact, NULL))
+               err(EXIT_FAILURE, _("error: can not restore signal handler"));
+
+       return eax != (uint32_t)-1 && ebx == VMWARE_BDOOR_MAGIC;
+}
+
+#else /* ! INCLUDE_VMWARE_BDOOR */
+
+static int
+is_vmware_platform(void)
+{
+       return 0;
+}
+
+#endif /* INCLUDE_VMWARE_BDOOR */
+
 static void
 read_hypervisor(struct lscpu_desc *desc, struct lscpu_modifier *mod)
 {
@@ -645,6 +724,8 @@ read_hypervisor(struct lscpu_desc *desc, struct lscpu_modifier *mod)
                read_hypervisor_cpuid(desc);
                if (!desc->hyper)
                        desc->hyper = read_hypervisor_dmi();
+               if (!desc->hyper && is_vmware_platform())
+                       desc->hyper = HYPER_VMWARE;
        }
 
        if (desc->hyper)