File util-linux-2.14.1-lscpu_add_hypervisor_detection.patch of Package util-linux

commit c8b64f6d7770d62065bdc4fa5c4f80cc2326e203
Author: Karel Zak <kzak@redhat.com>
Date:   Wed Oct 1 01:29:32 2008 +0200

    lscpu: add Hypervisor detection
    
    This patch adds two new fields:
    
     * "Hypervisor vendor"  -- based on CPUID and hypervisor specific
       PCI devices. lscpu(1) supports KVM, XEN, Microsoft HV now.
    
     * "Virtualization type"
    	- "none"	= Xen dom0
    	- "full"	= full virtualization (KVM, Xen, ...)
    	- "para"	= Xen paravirtualization
    
    Co-Author: Ky Srinivasan <ksrinivasan@novell.com>
    Signed-off-by: Karel Zak <kzak@redhat.com>

diff --git a/sys-utils/lscpu.1 b/sys-utils/lscpu.1
index 78da8a1..e0e9935 100644
--- a/sys-utils/lscpu.1
+++ b/sys-utils/lscpu.1
@@ -22,6 +22,8 @@ Print out in parsable instead of printable format.
 .SH BUGS
 The program at the moment does not handle the system installed with
 different types of physical processors.
+
+Sometimes in Xen Dom0 kernel reports wrong data.
 .SH AUTHOR
 Cai Qian <qcai@redhat.com>
 .SH AVAILABILITY
diff --git a/sys-utils/lscpu.c b/sys-utils/lscpu.c
index d6bb8b9..82972b3 100644
--- a/sys-utils/lscpu.c
+++ b/sys-utils/lscpu.c
@@ -38,8 +38,10 @@
 /* /sys paths */
 #define _PATH_SYS_SYSTEM	"sys/devices/system"
 #define _PATH_SYS_CPU0		_PATH_SYS_SYSTEM "/cpu/cpu0"
-#define _PATH_PROC_XENCAP	"proc/xen/capabilities"
+#define _PATH_PROC_XEN		"proc/xen"
+#define _PATH_PROC_XENCAP	_PATH_PROC_XEN "/capabilities"
 #define _PATH_PROC_CPUINFO	"proc/cpuinfo"
+#define _PATH_PROC_PCIDEVS	"proc/bus/pci/devices"
 
 int have_topology;
 int have_cache;
@@ -52,6 +54,33 @@ struct ca_desc {
 	int	camap;
 };
 
+/* virtualization types */
+enum {
+	VIRT_NONE	= 0,
+	VIRT_PARA,
+	VIRT_FULL
+};
+const char *virt_types[] = {
+	[VIRT_NONE]	= N_("none"),
+	[VIRT_PARA]	= N_("para"),
+	[VIRT_FULL]	= N_("full")
+};
+
+/* hypervisor vendors */
+enum {
+	HYPER_NONE	= 0,
+	HYPER_XEN,
+	HYPER_KVM,
+	HYPER_MSHV
+};
+const char *hv_vendors[] = {
+	[HYPER_NONE]	= NULL,
+	[HYPER_XEN]	= "Xen",
+	[HYPER_KVM]	= "KVM",
+	[HYPER_MSHV]	= "Microsoft"
+};
+
+
 /* CPU(s) description */
 struct cpu_desc {
 	/* counters */
@@ -67,6 +96,9 @@ struct cpu_desc {
 	char	*vendor;
 	char	*family;
 	char	*model;
+	char	*virtflag;	/* virtualization flag (vmx, svm) */
+	int	hyper;		/* hypervisor vendor ID */
+	int	virtype;	/* VIRT_PARA|FULL|NONE ? */
 
 	/* caches */
 	struct ca_desc	cache[CACHE_MAX];
@@ -246,9 +278,130 @@ read_basicinfo(struct cpu_desc *cpu)
 		else
 			continue;
 	}
+
+	if (cpu->flags) {
+		snprintf(buf, sizeof(buf), " %s ", cpu->flags);
+		if (strstr(buf, " svm "))
+			cpu->virtflag = strdup("svm");
+		else if (strstr(buf, " vmx "))
+			cpu->virtflag = strdup("vmx");
+	}
+
 	fclose(fp);
 }
 
+static int
+has_pci_device(int vendor, int device)
+{
+	FILE *f;
+	int num, fn, ven, dev;
+	int res = 1;
+
+	f = fopen(_PATH_PROC_PCIDEVS, "r");
+	if (!f)
+		return 0;
+
+	 /* for more details about bus/pci/devices format see
+	  * drivers/pci/proc.c in linux kernel
+	  */
+	while(fscanf(f, "%02x%02x\t%04x%04x\t%*[^\n]",
+			&num, &fn, &ven, &dev) == 4) {
+
+		if (ven == vendor && dev == device)
+			goto found;
+	}
+
+	res = 0;
+found:
+	fclose(f);
+	return res;
+}
+
+#if defined(__x86_64__) || defined(__i386__)
+
+/*
+ * This CPUID leaf returns the information about the hypervisor.
+ * EAX : maximum input value for CPUID supported by the hypervisor.
+ * EBX, ECX, EDX : Hypervisor vendor ID signature. E.g. VMwareVMware.
+ */
+#define HYPERVISOR_INFO_LEAF   0x40000000
+
+static inline void
+cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
+			 unsigned int *ecx, unsigned int *edx)
+{
+	__asm__("cpuid"
+		: "=a" (*eax),
+		  "=b" (*ebx),
+		  "=c" (*ecx),
+		  "=d" (*edx)
+		: "0" (op), "c"(0));
+}
+
+static void
+read_hypervisor_cpuid(struct cpu_desc *cpu)
+{
+	unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
+	char hyper_vendor_id[13];
+
+	memset(hyper_vendor_id, 0, sizeof(hyper_vendor_id));
+
+	cpuid(HYPERVISOR_INFO_LEAF, &eax, &ebx, &ecx, &edx);
+	memcpy(hyper_vendor_id + 0, &ebx, 4);
+	memcpy(hyper_vendor_id + 4, &ecx, 4);
+	memcpy(hyper_vendor_id + 8, &edx, 4);
+	hyper_vendor_id[12] = '\0';
+
+	if (!hyper_vendor_id[0])
+		return;
+
+	if (!strncmp("XenVMMXenVMM", hyper_vendor_id, 12))
+		cpu->hyper = HYPER_XEN;
+	else if (!strncmp("KVMKVMKVM", hyper_vendor_id, 9))
+		cpu->hyper = HYPER_KVM;
+	else if (!strncmp("Microsoft Hv", hyper_vendor_id, 12))
+		cpu->hyper = HYPER_MSHV;
+}
+
+#else	/* ! __x86_64__ */
+static void
+read_hypervisor_cpuid(struct cpu_desc *cpu)
+{
+}
+#endif
+
+static void
+read_hypervisor(struct cpu_desc *cpu)
+{
+	read_hypervisor_cpuid(cpu);
+
+	if (cpu->hyper)
+		/* hvm */
+		cpu->virtype = VIRT_FULL;
+
+	else if (!access(_PATH_PROC_XEN, F_OK)) {
+		/* Xen para-virt or dom0 */
+		FILE *fd = fopen(_PATH_PROC_XENCAP, "r");
+		int dom0 = 0;
+
+		if (fd) {
+			char buf[256];
+
+			if (fscanf(fd, "%s", buf) == 1 &&
+			    !strcmp(buf, "control_d"))
+				dom0 = 1;
+			fclose(fd);
+		}
+		cpu->virtype = dom0 ? VIRT_NONE : VIRT_PARA;
+		cpu->hyper = HYPER_XEN;
+
+	} else if (has_pci_device(0x5853, 0x0001)) {
+		/* Xen full-virt on non-x86_64 */
+		cpu->hyper = HYPER_XEN;
+		cpu->virtype = VIRT_FULL;
+	}
+}
+
 static void
 read_topology(struct cpu_desc *cpu)
 {
@@ -337,18 +490,6 @@ read_nodes(struct cpu_desc *cpu)
 static void
 check_system(void)
 {
-	FILE *fd;
-	char buf[256];
-
-	/* Dom0 Kernel gives wrong information. */
-	fd = fopen(_PATH_PROC_XENCAP, "r");
-	if (fd) {
-		if (fscanf(fd, "%s", buf) == 1 && !strcmp(buf, "control_d"))
-			errx(EXIT_FAILURE,
-			     _("error: Dom0 Kernel is unsupported."));
-		fclose(fd);
-	}
-
 	/* Read through sysfs. */
 	if (access(_PATH_SYS_SYSTEM, F_OK))
 		errx(EXIT_FAILURE,
@@ -432,8 +573,6 @@ print_parsable(struct cpu_desc *cpu)
 static void
 print_readable(struct cpu_desc *cpu)
 {
-	char buf[BUFSIZ];
-
 	print_s("Architecture:", cpu->arch);
 	print_n("CPU(s):", cpu->ct_cpu);
 
@@ -455,15 +594,18 @@ print_readable(struct cpu_desc *cpu)
 		print_s(_("Stepping:"), cpu->stepping);
 	if (cpu->mhz)
 		print_s(_("CPU MHz:"), cpu->mhz);
-	if (cpu->flags) {
-		snprintf(buf, sizeof(buf), " %s ", cpu->flags);
-		if (strstr(buf, " svm "))
+	if (cpu->virtflag) {
+		if (!strcmp(cpu->virtflag, "svm"))
 			print_s(_("Virtualization:"), "AMD-V");
-		else if (strstr(buf, " vmx "))
+		else if (!strcmp(cpu->virtflag, "vmx"))
 			print_s(_("Virtualization:"), "VT-x");
 	}
-
+	if (cpu->hyper) {
+		print_s(_("Hypervisor vendor:"), hv_vendors[cpu->hyper]);
+		print_s(_("Virtualization type:"), virt_types[cpu->virtype]);
+	}
 	if (have_cache) {
+		char buf[512];
 		int i;
 
 		for (i = cpu->ct_cache - 1; i >= 0; i--) {
@@ -545,6 +687,8 @@ int main(int argc, char *argv[])
 	if (have_node)
 		read_nodes(cpu);
 
+	read_hypervisor(cpu);
+
 	/* Show time! */
 	if (parsable)
 		print_parsable(cpu);
openSUSE Build Service is sponsored by