---
 sys-utils/lscpu.c |  156 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 152 insertions(+), 4 deletions(-)

Index: util-linux-2.19.1/sys-utils/lscpu.c
===================================================================
--- util-linux-2.19.1.orig/sys-utils/lscpu.c
+++ util-linux-2.19.1/sys-utils/lscpu.c
@@ -32,6 +32,15 @@
 #include <stdarg.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <stdint.h>
+#include <signal.h>
+#include <strings.h>
+#include <setjmp.h>
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef HAVE_sys_io_h
+#include <sys/io.h>
+#endif
+#endif
 
 #include "strutils.h"
 #include "cpuset.h"
@@ -55,6 +64,7 @@
 #define _PATH_PROC_CPUINFO	"/proc/cpuinfo"
 #define _PATH_PROC_PCIDEVS	"/proc/bus/pci/devices"
 #define _PATH_PROC_SYSINFO	"/proc/sysinfo"
+#define _PATH_PROC_DEVICETREE   "/proc/device-tree"
 
 /* virtualization types */
 enum {
@@ -75,15 +85,40 @@ enum {
 	HYPER_KVM,
 	HYPER_MSHV,
 	HYPER_VMWARE,
-	HYPER_IBM
+	HYPER_IBM,
+	HYPER_VBOX,
+	HYPER_OS400,
+	HYPER_PHYP
 };
+
 const char *hv_vendors[] = {
 	[HYPER_NONE]	= NULL,
 	[HYPER_XEN]	= "Xen",
 	[HYPER_KVM]	= "KVM",
 	[HYPER_MSHV]	= "Microsoft",
 	[HYPER_VMWARE]  = "VMware",
-	[HYPER_IBM]	= "IBM"
+	[HYPER_IBM]	= "IBM",
+	[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 */
@@ -493,10 +528,111 @@ read_hypervisor_cpuid(struct lscpu_desc
 		desc->hyper = HYPER_VMWARE;
 }
 
+#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)" :                                            \
+               "=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(int sig, siginfo_t *info, 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	/* ! __x86_64__ */
 static void
 read_hypervisor_cpuid(struct lscpu_desc *desc)
 {
+#ifdef __powerpc__
+	/* 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
+	 * 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_FULL;
+	} else if (path_exist(_PATH_PROC_DEVICETREE "/ibm,partition-name")) {
+		FILE *fd;
+		desc->hyper = HYPER_PHYP;
+		desc->virtype = VIRT_FULL;
+		fd = fopen(_PATH_PROC_DEVICETREE "/ibm,partition-name", "r");
+		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 = fopen(_PATH_PROC_DEVICETREE "/hypervisor/compatible", "r");
+		if (fd) {
+			char buf[256];
+			int i;
+			memset(buf, 0, sizeof(buf));
+			fread(buf, sizeof(buf) - 1, 1, fd);
+			fclose(fd);
+			for (i = 0; i < sizeof(buf);) {
+				if (!strcmp(&buf[i], "linux,kvm")) {
+					desc->hyper = HYPER_KVM;
+					desc->virtype = VIRT_FULL;
+					break;
+				}
+				i += strlen(&buf[i]);
+				i++;
+			}
+		}
+	}
+#endif
+}
+
+static int is_vmware_platform(void)
+{
+	return 0;
 }
 #endif
 
@@ -525,10 +661,19 @@ read_hypervisor(struct lscpu_desc *desc)
 		desc->virtype = dom0 ? VIRT_NONE : VIRT_PARA;
 		desc->hyper = HYPER_XEN;
 
-	} else if (has_pci_device(0x5853, 0x0001)) {
+	} else if (has_pci_device( hv_vendor_pci[HYPER_XEN], hv_graphics_pci[HYPER_XEN])) {
 		/* Xen full-virt on non-x86_64 */
 		desc->hyper = HYPER_XEN;
 		desc->virtype = VIRT_FULL;
+	} else if (is_vmware_platform()) {
+		desc->hyper = HYPER_VMWARE;
+		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;
 	} else if (path_exist(_PATH_PROC_SYSINFO)) {
 		FILE *fd = path_fopen("r", 0, _PATH_PROC_SYSINFO);
 		char buf[BUFSIZ];
@@ -978,6 +1123,7 @@ print_parsable(struct lscpu_desc *desc,
 		}
 		fputs(data && *data ? data : "", stdout);
 	}
+	printf(",HvVendor,VirtType");
 	putchar('\n');
 
 	/*
@@ -1004,7 +1150,9 @@ print_parsable(struct lscpu_desc *desc,
 					     buf, sizeof(buf));
 			fputs(data && *data ? data : "", stdout);
 		}
-		putchar('\n');
+		printf(",%s,%s\n",
+		       hv_vendors[desc->hyper] ? hv_vendors[desc->hyper] : "none",
+		       virt_types[desc->virtype]);
 	}
 }
 
