diff options
-rw-r--r-- | sys-utils/lscpu.c | 173 | ||||
-rw-r--r-- | sys-utils/lscpu.h | 5 | ||||
-rw-r--r-- | tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu | 2 | ||||
-rw-r--r-- | tests/expected/lscpu/lscpu-vbox-win | 29 | ||||
-rw-r--r-- | tests/ts/lscpu/dumps/ppc64-POWER7-64cpu.tar.gz | bin | 56662 -> 56867 bytes | |||
-rw-r--r-- | tests/ts/lscpu/dumps/vbox-win.tar.gz | bin | 0 -> 15769 bytes |
6 files changed, 205 insertions, 4 deletions
diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c index ad1a6b352..3b3faf81a 100644 --- a/sys-utils/lscpu.c +++ b/sys-utils/lscpu.c @@ -19,6 +19,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include <assert.h> #include <ctype.h> #include <dirent.h> #include <errno.h> @@ -33,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" @@ -60,6 +75,7 @@ #define _PATH_PROC_STATUS "/proc/self/status" #define _PATH_PROC_VZ "/proc/vz" #define _PATH_PROC_BC "/proc/bc" +#define _PATH_PROC_DEVICETREE "/proc/device-tree" #define _PATH_DEV_MEM "/dev/mem" /* virtualization types */ @@ -87,7 +103,28 @@ const char *hv_vendors[] = { [HYPER_UML] = "User-mode Linux", [HYPER_INNOTEK] = "Innotek GmbH", [HYPER_HITACHI] = "Hitachi", - [HYPER_PARALLELS] = "Parallels" + [HYPER_PARALLELS] = "Parallels", + [HYPER_VBOX] = "Oracle", + [HYPER_OS400] = "OS/400", + [HYPER_PHYP] = "pHyp", +}; + +const int hv_vendor_pci[] = { + [HYPER_NONE] = 0x0000, + [HYPER_XEN] = 0x5853, + [HYPER_KVM] = 0x0000, + [HYPER_MSHV] = 0x1414, + [HYPER_VMWARE] = 0x15ad, + [HYPER_VBOX] = 0x80ee, +}; + +const int hv_graphics_pci[] = { + [HYPER_NONE] = 0x0000, + [HYPER_XEN] = 0x0001, + [HYPER_KVM] = 0x0000, + [HYPER_MSHV] = 0x5353, + [HYPER_VMWARE] = 0x0710, + [HYPER_VBOX] = 0xbeef, }; /* CPU modes */ @@ -551,13 +588,133 @@ 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__))) { } #endif +static int +read_hypervisor_powerpc(struct lscpu_desc *desc) +{ + assert(!desc->hyper); + + /* powerpc: + * IBM iSeries: legacy, if /proc/iSeries exists, its para-virtualized on top of OS/400 + * IBM pSeries: always has a hypervisor + * if partition-name is "full", its kind of "bare-metal": full-system-partition + * otherwise its some partition created by Hardware Management Console + * in any case, its always some sort of HVM + * Note that pSeries could also be emulated by qemu/KVM. + * KVM: "linux,kvm" in /hypervisor/compatible indicates a KVM guest + * Xen: not in use, not detected + */ + if (path_exist("/proc/iSeries")) { + desc->hyper = HYPER_OS400; + desc->virtype = VIRT_PARA; + } else if (path_exist(_PATH_PROC_DEVICETREE "/ibm,partition-name") + && path_exist(_PATH_PROC_DEVICETREE "/hmc-managed?") + && !path_exist(_PATH_PROC_DEVICETREE "/chosen/qemu,graphic-width")) { + FILE *fd; + desc->hyper = HYPER_PHYP; + desc->virtype = VIRT_PARA; + fd = path_fopen("r", 0, _PATH_PROC_DEVICETREE "/ibm,partition-name"); + if (fd) { + char buf[256]; + if (fscanf(fd, "%s", buf) == 1 && !strcmp(buf, "full")) + desc->virtype = VIRT_NONE; + fclose(fd); + } + } else if (path_exist(_PATH_PROC_DEVICETREE "/hypervisor/compatible")) { + FILE *fd; + fd = path_fopen("r", 0, _PATH_PROC_DEVICETREE "/hypervisor/compatible"); + if (fd) { + char buf[256]; + size_t i, len; + memset(buf, 0, sizeof(buf)); + len = fread(buf, 1, sizeof(buf) - 1, fd); + fclose(fd); + for (i = 0; i < len;) { + if (!strcmp(&buf[i], "linux,kvm")) { + desc->hyper = HYPER_KVM; + desc->virtype = VIRT_FULL; + break; + } + i += strlen(&buf[i]); + i++; + } + } + } + + 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) { @@ -567,11 +724,15 @@ 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) desc->virtype = VIRT_FULL; + else if (read_hypervisor_powerpc(desc) > 0) {} + /* Xen para-virt or dom0 */ else if (path_exist(_PATH_PROC_XEN)) { int dom0 = 0; @@ -589,9 +750,15 @@ read_hypervisor(struct lscpu_desc *desc, struct lscpu_modifier *mod) desc->hyper = HYPER_XEN; /* Xen full-virt on non-x86_64 */ - } else if (has_pci_device(0x5853, 0x0001)) { + } else if (has_pci_device( hv_vendor_pci[HYPER_XEN], hv_graphics_pci[HYPER_XEN])) { desc->hyper = HYPER_XEN; desc->virtype = VIRT_FULL; + } else if (has_pci_device( hv_vendor_pci[HYPER_VMWARE], hv_graphics_pci[HYPER_VMWARE])) { + desc->hyper = HYPER_VMWARE; + desc->virtype = VIRT_FULL; + } else if (has_pci_device( hv_vendor_pci[HYPER_VBOX], hv_graphics_pci[HYPER_VBOX])) { + desc->hyper = HYPER_VBOX; + desc->virtype = VIRT_FULL; /* IBM PR/SM */ } else if (path_exist(_PATH_PROC_SYSINFO)) { diff --git a/sys-utils/lscpu.h b/sys-utils/lscpu.h index 312038fcc..e34029194 100644 --- a/sys-utils/lscpu.h +++ b/sys-utils/lscpu.h @@ -13,7 +13,10 @@ enum { HYPER_UML, HYPER_INNOTEK, /* VBOX */ HYPER_HITACHI, - HYPER_PARALLELS /* OpenVZ/VIrtuozzo */ + HYPER_PARALLELS, /* OpenVZ/VIrtuozzo */ + HYPER_VBOX, + HYPER_OS400, + HYPER_PHYP, }; extern int read_hypervisor_dmi(void); diff --git a/tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu b/tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu index 40e27369b..e48735ec6 100644 --- a/tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu +++ b/tests/expected/lscpu/lscpu-ppc64-POWER7-64cpu @@ -5,6 +5,8 @@ Core(s) per socket: 1 Socket(s): 16 NUMA node(s): 2 Model: IBM,8231-E2B +Hypervisor vendor: pHyp +Virtualization type: para L1d cache: 32K L1i cache: 32K NUMA node0 CPU(s): 0-63 diff --git a/tests/expected/lscpu/lscpu-vbox-win b/tests/expected/lscpu/lscpu-vbox-win new file mode 100644 index 000000000..569f0789f --- /dev/null +++ b/tests/expected/lscpu/lscpu-vbox-win @@ -0,0 +1,29 @@ +CPU op-mode(s): 32-bit, 64-bit +CPU(s): 2 +On-line CPU(s) list: 0,1 +Thread(s) per core: 1 +Core(s) per socket: 2 +Socket(s): 1 +NUMA node(s): 1 +Vendor ID: GenuineIntel +CPU family: 6 +Model: 58 +Model name: Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz +Stepping: 9 +CPU MHz: 1600.000 +CPU max MHz: 3800.0000 +CPU min MHz: 1600.0000 +BogoMIPS: 3355.62 +Hypervisor vendor: Oracle +Virtualization type: full +L1d cache: 32K +L1d cache: 32K +L2d cache: 6144K +NUMA node0 CPU(s): 0,1 + +# The following is the parsable format, which can be fed to other +# programs. Each different item in every column has an unique ID +# starting from zero. +# CPU,Core,Socket,Node,,L1d,L1d,L2d +0,0,0,0,,0,0,0 +1,1,0,0,,1,1,0 diff --git a/tests/ts/lscpu/dumps/ppc64-POWER7-64cpu.tar.gz b/tests/ts/lscpu/dumps/ppc64-POWER7-64cpu.tar.gz Binary files differindex ea74a01d6..ea8b79a81 100644 --- a/tests/ts/lscpu/dumps/ppc64-POWER7-64cpu.tar.gz +++ b/tests/ts/lscpu/dumps/ppc64-POWER7-64cpu.tar.gz diff --git a/tests/ts/lscpu/dumps/vbox-win.tar.gz b/tests/ts/lscpu/dumps/vbox-win.tar.gz Binary files differnew file mode 100644 index 000000000..e8204fe11 --- /dev/null +++ b/tests/ts/lscpu/dumps/vbox-win.tar.gz |