diff options
author | Ruediger Meier | 2014-05-20 13:26:48 +0200 |
---|---|---|
committer | Ruediger Meier | 2014-05-29 13:17:46 +0200 |
commit | b7744730f6e4b5b91c9846f3e7c58aaa7423a167 (patch) | |
tree | fa26bf0e7327a57d0793479cd244ef834ca5012f /sys-utils/lscpu.c | |
parent | tests: add lscpu IBM pSeries test data (diff) | |
download | kernel-qcow2-util-linux-b7744730f6e4b5b91c9846f3e7c58aaa7423a167.tar.gz kernel-qcow2-util-linux-b7744730f6e4b5b91c9846f3e7c58aaa7423a167.tar.xz kernel-qcow2-util-linux-b7744730f6e4b5b91c9846f3e7c58aaa7423a167.zip |
lscpu: improve vmware detection
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>
Diffstat (limited to 'sys-utils/lscpu.c')
-rw-r--r-- | sys-utils/lscpu.c | 83 |
1 files changed, 82 insertions, 1 deletions
diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c index 11224b0bc..3b3faf81a 100644 --- a/sys-utils/lscpu.c +++ b/sys-utils/lscpu.c @@ -34,6 +34,20 @@ #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) |