diff usr/src/uts/i86pc/os/cpuid.c @ 14043:0291cd939b43

3506 Use "hypervisor" CPUID bit to detect hypervisor environment Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com> Reviewed by: Albert Lee <trisk@nexenta.com> Approved by: Robert Mustacchi <rm@joyent.com>
author Yuri Pankov <yuri.pankov@nexenta.com>
date Mon, 10 Jun 2013 09:51:40 -0700
parents b151bd260b71
children
line wrap: on
line diff
--- a/usr/src/uts/i86pc/os/cpuid.c	Sun Jun 09 14:38:37 2013 +0400
+++ b/usr/src/uts/i86pc/os/cpuid.c	Mon Jun 10 09:51:40 2013 -0700
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  */
 /*
  * Copyright (c) 2010, Intel Corporation.
@@ -220,7 +221,7 @@
 boolean_t xsave_force_disable = B_FALSE;
 
 /*
- * This is set to platform type Solaris is running on.
+ * This is set to platform type we are running on.
  */
 static int platform_type = -1;
 
@@ -597,20 +598,20 @@
 }
 
 #if !defined(__xpv)
-
 /*
  * Determine the type of the underlying platform. This is used to customize
  * initialization of various subsystems (e.g. TSC). determine_platform() must
  * only ever be called once to prevent two processors from seeing different
- * values of platform_type, it must be called before cpuid_pass1(), the
- * earliest consumer to execute.
+ * values of platform_type. Must be called before cpuid_pass1(), the earliest
+ * consumer to execute (uses _cpuid_chiprev --> synth_amd_info --> get_hwenv).
  */
 void
 determine_platform(void)
 {
 	struct cpuid_regs cp;
-	char *xen_str;
-	uint32_t xen_signature[4], base;
+	uint32_t base;
+	uint32_t regs[4];
+	char *hvstr = (char *)regs;
 
 	ASSERT(platform_type == -1);
 
@@ -620,31 +621,75 @@
 		return;
 
 	/*
-	 * In a fully virtualized domain, Xen's pseudo-cpuid function
-	 * returns a string representing the Xen signature in %ebx, %ecx,
-	 * and %edx. %eax contains the maximum supported cpuid function.
-	 * We need at least a (base + 2) leaf value to do what we want
-	 * to do. Try different base values, since the hypervisor might
-	 * use a different one depending on whether hyper-v emulation
-	 * is switched on by default or not.
+	 * If Hypervisor CPUID bit is set, try to determine hypervisor
+	 * vendor signature, and set platform type accordingly.
+	 *
+	 * References:
+	 * http://lkml.org/lkml/2008/10/1/246
+	 * http://kb.vmware.com/kb/1009458
+	 */
+	cp.cp_eax = 0x1;
+	(void) __cpuid_insn(&cp);
+	if ((cp.cp_ecx & CPUID_INTC_ECX_HV) != 0) {
+		cp.cp_eax = 0x40000000;
+		(void) __cpuid_insn(&cp);
+		regs[0] = cp.cp_ebx;
+		regs[1] = cp.cp_ecx;
+		regs[2] = cp.cp_edx;
+		regs[3] = 0;
+		if (strcmp(hvstr, HVSIG_XEN_HVM) == 0) {
+			platform_type = HW_XEN_HVM;
+			return;
+		}
+		if (strcmp(hvstr, HVSIG_VMWARE) == 0) {
+			platform_type = HW_VMWARE;
+			return;
+		}
+		if (strcmp(hvstr, HVSIG_KVM) == 0) {
+			platform_type = HW_KVM;
+			return;
+		}
+		if (strcmp(hvstr, HVSIG_MICROSOFT) == 0)
+			platform_type = HW_MICROSOFT;
+	} else {
+		/*
+		 * Check older VMware hardware versions. VMware hypervisor is
+		 * detected by performing an IN operation to VMware hypervisor
+		 * port and checking that value returned in %ebx is VMware
+		 * hypervisor magic value.
+		 *
+		 * References: http://kb.vmware.com/kb/1009458
+		 */
+		vmware_port(VMWARE_HVCMD_GETVERSION, regs);
+		if (regs[1] == VMWARE_HVMAGIC) {
+			platform_type = HW_VMWARE;
+			return;
+		}
+	}
+
+	/*
+	 * Check Xen hypervisor. In a fully virtualized domain,
+	 * Xen's pseudo-cpuid function returns a string representing the
+	 * Xen signature in %ebx, %ecx, and %edx. %eax contains the maximum
+	 * supported cpuid function. We need at least a (base + 2) leaf value
+	 * to do what we want to do. Try different base values, since the
+	 * hypervisor might use a different one depending on whether Hyper-V
+	 * emulation is switched on by default or not.
 	 */
 	for (base = 0x40000000; base < 0x40010000; base += 0x100) {
 		cp.cp_eax = base;
 		(void) __cpuid_insn(&cp);
-		xen_signature[0] = cp.cp_ebx;
-		xen_signature[1] = cp.cp_ecx;
-		xen_signature[2] = cp.cp_edx;
-		xen_signature[3] = 0;
-		xen_str = (char *)xen_signature;
-		if (strcmp("XenVMMXenVMM", xen_str) == 0 &&
+		regs[0] = cp.cp_ebx;
+		regs[1] = cp.cp_ecx;
+		regs[2] = cp.cp_edx;
+		regs[3] = 0;
+		if (strcmp(hvstr, HVSIG_XEN_HVM) == 0 &&
 		    cp.cp_eax >= (base + 2)) {
-			platform_type = HW_XEN_HVM;
+			platform_type &= ~HW_NATIVE;
+			platform_type |= HW_XEN_HVM;
 			return;
 		}
 	}
-
-	if (vmware_platform()) /* running under vmware hypervisor? */
-		platform_type = HW_VMWARE;
 }
 
 int
@@ -2366,7 +2411,7 @@
  * the other cpus.
  *
  * Fixup the brand string, and collect any information from cpuid
- * that requires dynamicically allocated storage to represent.
+ * that requires dynamically allocated storage to represent.
  */
 /*ARGSUSED*/
 void