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 {                                           
\
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to