svn commit: r204799 - in stable/7/sys: amd64/amd64 i386/i386 kern sys

Ivan Voras ivoras at FreeBSD.org
Sat Mar 6 16:45:55 UTC 2010


Author: ivoras
Date: Sat Mar  6 16:45:55 2010
New Revision: 204799
URL: http://svn.freebsd.org/changeset/base/204799

Log:
  MFC virtual machine guest detection code and r204420 - code to disable
  superpages on buggy AMD CPUs.
  
  Reviewed by:	alc

Modified:
  stable/7/sys/amd64/amd64/pmap.c
  stable/7/sys/i386/i386/pmap.c
  stable/7/sys/kern/subr_param.c
  stable/7/sys/sys/systm.h
Directory Properties:
  stable/7/sys/   (props changed)
  stable/7/sys/cddl/contrib/opensolaris/   (props changed)
  stable/7/sys/contrib/dev/acpica/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)

Modified: stable/7/sys/amd64/amd64/pmap.c
==============================================================================
--- stable/7/sys/amd64/amd64/pmap.c	Sat Mar  6 16:27:43 2010	(r204798)
+++ stable/7/sys/amd64/amd64/pmap.c	Sat Mar  6 16:45:55 2010	(r204799)
@@ -658,6 +658,15 @@ pmap_init(void)
 	pv_entry_high_water = 9 * (pv_entry_max / 10);
 
 	/*
+	 * Disable large page mappings by default if the kernel is running in
+	 * a virtual machine on an AMD Family 10h processor.  This is a work-
+	 * around for Erratum 383.
+	 */
+	if (vm_guest == VM_GUEST_VM && cpu_vendor_id == CPU_VENDOR_AMD &&
+	    CPUID_TO_FAMILY(cpu_id) == 0x10)
+		pg_ps_enabled = 0;
+
+	/*
 	 * Are large page mappings enabled?
 	 */
 	TUNABLE_INT_FETCH("vm.pmap.pg_ps_enabled", &pg_ps_enabled);

Modified: stable/7/sys/i386/i386/pmap.c
==============================================================================
--- stable/7/sys/i386/i386/pmap.c	Sat Mar  6 16:27:43 2010	(r204798)
+++ stable/7/sys/i386/i386/pmap.c	Sat Mar  6 16:45:55 2010	(r204799)
@@ -672,6 +672,15 @@ pmap_init(void)
 	pv_entry_high_water = 9 * (pv_entry_max / 10);
 
 	/*
+	 * Disable large page mappings by default if the kernel is running in
+	 * a virtual machine on an AMD Family 10h processor.  This is a work-
+	 * around for Erratum 383.
+	 */
+	if (vm_guest == VM_GUEST_VM && cpu_vendor_id == CPU_VENDOR_AMD &&
+	    CPUID_TO_FAMILY(cpu_id) == 0x10)
+		pg_ps_enabled = 0;
+
+	/*
 	 * Are large page mappings enabled?
 	 */
 	TUNABLE_INT_FETCH("vm.pmap.pg_ps_enabled", &pg_ps_enabled);

Modified: stable/7/sys/kern/subr_param.c
==============================================================================
--- stable/7/sys/kern/subr_param.c	Sat Mar  6 16:27:43 2010	(r204798)
+++ stable/7/sys/kern/subr_param.c	Sat Mar  6 16:45:55 2010	(r204799)
@@ -57,6 +57,13 @@ __FBSDID("$FreeBSD$");
 #  else
 #    define	HZ 100
 #  endif
+#  ifndef HZ_VM
+#    define	HZ_VM 100
+#  endif
+#else
+#  ifndef HZ_VM
+#    define	HZ_VM HZ
+#  endif
 #endif
 #define	NPROC (20 + 16 * maxusers)
 #ifndef NBUF
@@ -66,6 +73,8 @@ __FBSDID("$FreeBSD$");
 #define	MAXFILES (maxproc * 2)
 #endif
 
+static int sysctl_kern_vm_guest(SYSCTL_HANDLER_ARGS);
+
 int	hz;
 int	tick;
 int	maxusers;			/* base tunable */
@@ -79,6 +88,7 @@ int	nswbuf;
 long	maxswzone;			/* max swmeta KVA storage */
 long	maxbcache;			/* max buffer cache KVA storage */
 long	maxpipekva;			/* Limit on pipe KVA */
+int 	vm_guest;			/* Running as virtual machine guest? */
 u_long	maxtsiz;			/* max text size */
 u_long	dfldsiz;			/* initial data size limit */
 u_long	maxdsiz;			/* max data size */
@@ -110,6 +120,9 @@ SYSCTL_ULONG(_kern, OID_AUTO, maxssiz, C
     "Maximum stack size");
 SYSCTL_ULONG(_kern, OID_AUTO, sgrowsiz, CTLFLAG_RDTUN, &sgrowsiz, 0,
     "Amount to grow stack on a stack fault");
+SYSCTL_PROC(_kern, OID_AUTO, vm_guest, CTLFLAG_RD | CTLTYPE_STRING,
+    NULL, 0, sysctl_kern_vm_guest, "A",
+    "Virtual machine guest detected? (none|generic)");
 
 /*
  * These have to be allocated somewhere; allocating
@@ -119,14 +132,73 @@ SYSCTL_ULONG(_kern, OID_AUTO, sgrowsiz, 
 struct	buf *swbuf;
 
 /*
+ * The elements of this array are ordered based upon the values of the
+ * corresponding enum VM_GUEST members.
+ */
+static const char *const vm_guest_sysctl_names[] = {
+	"none",
+	"generic",
+	NULL
+};
+
+static const char *const vm_bnames[] = {
+	"QEMU",				/* QEMU */
+	"Plex86",			/* Plex86 */
+	"Bochs",			/* Bochs */
+	NULL
+};
+
+static const char *const vm_pnames[] = {
+	"VMware Virtual Platform",	/* VMWare VM */
+	"Virtual Machine",		/* Microsoft VirtualPC */
+	"VirtualBox",			/* Sun xVM VirtualBox */
+	"Parallels Virtual Platform",	/* Parallels VM */
+	NULL
+};
+
+
+/*
+ * Detect known Virtual Machine hosts by inspecting the emulated BIOS.
+ */
+static enum VM_GUEST
+detect_virtual(void)
+{
+	char *sysenv;
+	int i;
+
+	sysenv = getenv("smbios.bios.vendor");
+	if (sysenv != NULL) {
+		for (i = 0; vm_bnames[i] != NULL; i++)
+			if (strcmp(sysenv, vm_bnames[i]) == 0) {
+				freeenv(sysenv);
+				return (VM_GUEST_VM);
+			}
+		freeenv(sysenv);
+	}
+	sysenv = getenv("smbios.system.product");
+	if (sysenv != NULL) {
+		for (i = 0; vm_pnames[i] != NULL; i++)
+			if (strcmp(sysenv, vm_pnames[i]) == 0) {
+				freeenv(sysenv);
+				return (VM_GUEST_VM);
+			}
+		freeenv(sysenv);
+	}
+	return (VM_GUEST_NO);
+}
+
+/*
  * Boot time overrides that are not scaled against main memory
  */
 void
 init_param1(void)
 {
 
-	hz = HZ;
+	vm_guest = detect_virtual();
+	hz = -1;
 	TUNABLE_INT_FETCH("kern.hz", &hz);
+	if (hz == -1)
+		hz = vm_guest > VM_GUEST_NO ? HZ_VM : HZ;
 	tick = 1000000 / hz;
 
 #ifdef VM_SWZONE_SIZE_MAX
@@ -213,3 +285,13 @@ init_param3(long kmempages)
 		maxpipekva = 512 * 1024;
 	TUNABLE_LONG_FETCH("kern.ipc.maxpipekva", &maxpipekva);
 }
+
+/*
+ * Sysctl stringiying handler for kern.vm_guest.
+ */
+static int
+sysctl_kern_vm_guest(SYSCTL_HANDLER_ARGS)
+{
+	return (SYSCTL_OUT(req, vm_guest_sysctl_names[vm_guest], 
+	    strlen(vm_guest_sysctl_names[vm_guest])));
+}

Modified: stable/7/sys/sys/systm.h
==============================================================================
--- stable/7/sys/sys/systm.h	Sat Mar  6 16:27:43 2010	(r204798)
+++ stable/7/sys/sys/systm.h	Sat Mar  6 16:45:55 2010	(r204799)
@@ -70,6 +70,14 @@ extern int boothowto;		/* reboot flags, 
 extern int bootverbose;		/* nonzero to print verbose messages */
 
 extern int maxusers;		/* system tune hint */
+extern int vm_guest;		/* Running as virtual machine guest? */
+
+/*
+ * Detected virtual machine guest types. The intention is to expand
+ * and/or add to the VM_GUEST_VM type if specific VM functionality is
+ * ever implemented (e.g. vendor-specific paravirtualization features).
+ */
+enum VM_GUEST { VM_GUEST_NO = 0, VM_GUEST_VM };
 
 #ifdef	INVARIANTS		/* The option is always available */
 #define	KASSERT(exp,msg) do {						\


More information about the svn-src-stable-7 mailing list