diff -u -r /usr/src/sys.old/amd64/amd64/machdep.c /usr/src/sys/amd64/amd64/machdep.c --- /usr/src/sys.old/amd64/amd64/machdep.c 2007-12-29 03:01:02.000000000 -0600 +++ /usr/src/sys/amd64/amd64/machdep.c 2007-12-29 18:57:01.000000000 -0600 @@ -1935,3 +1935,33 @@ } #endif /* KDB */ + +/* kenv strings used to identify various VM environments */ + +static char *vm_strings[] = { + "hint.acpi.0.oem", "QEMU", + "hint.acpi.0.oem", "VBOX", /* VirtualBox */ + "smbios.system.maker", "VMware, Inc.", + "smbios.bios.vendor", "Parallels Software International Inc.", + NULL + }; + +int +detect_virtualmachine(void) +{ + char *envptr; + int i; + for (i = 0; ; i += 2) { + if (vm_strings[i] == NULL) + break; + envptr = getenv(vm_strings[i]); + if (envptr) { + if (strncmp(envptr, vm_strings[i+1], strlen(vm_strings[i+1])) == 0) { + freeenv(envptr); + return 1; + } + freeenv(envptr); + } + } + return 0; +} diff -u -r /usr/src/sys.old/arm/arm/machdep.c /usr/src/sys/arm/arm/machdep.c --- /usr/src/sys.old/arm/arm/machdep.c 2007-12-29 03:01:06.000000000 -0600 +++ /usr/src/sys/arm/arm/machdep.c 2007-12-29 18:57:21.000000000 -0600 @@ -631,3 +631,9 @@ pcb->un_32.pcb32_lr = tf->tf_usr_lr; pcb->un_32.pcb32_sp = tf->tf_usr_sp; } + +int +detect_virtualmachine(void) +{ + return 0; +} diff -u -r /usr/src/sys.old/conf/NOTES /usr/src/sys/conf/NOTES --- /usr/src/sys.old/conf/NOTES 2007-12-29 03:01:19.000000000 -0600 +++ /usr/src/sys/conf/NOTES 2007-12-29 18:54:40.000000000 -0600 @@ -1115,6 +1115,7 @@ # the accuracy of operation. options HZ=100 +options VIRTUAL_HZ=100 # Enable support for the kernel PLL to use an external PPS signal, # under supervision of [x]ntpd(8) diff -u -r /usr/src/sys.old/conf/options /usr/src/sys/conf/options --- /usr/src/sys.old/conf/options 2007-12-29 03:01:19.000000000 -0600 +++ /usr/src/sys/conf/options 2007-12-29 03:06:22.000000000 -0600 @@ -262,6 +262,7 @@ # Options used only in subr_param.c. HZ opt_param.h +VIRTUAL_HZ opt_param.h MAXFILES opt_param.h NBUF opt_param.h NSFBUFS opt_param.h diff -u -r /usr/src/sys.old/i386/i386/machdep.c /usr/src/sys/i386/i386/machdep.c --- /usr/src/sys.old/i386/i386/machdep.c 2007-12-29 03:01:29.000000000 -0600 +++ /usr/src/sys/i386/i386/machdep.c 2007-12-29 03:59:05.000000000 -0600 @@ -3110,3 +3110,33 @@ } #endif /* KDB */ + +/* kenv strings used to identify various VM environments */ + +static char *vm_strings[] = { + "hint.acpi.0.oem", "QEMU", + "hint.acpi.0.oem", "VBOX", /* VirtualBox */ + "smbios.system.maker", "VMware, Inc.", + "smbios.bios.vendor", "Parallels Software International Inc.", + NULL + }; + +int +detect_virtualmachine(void) +{ + char *envptr; + int i; + for (i = 0; ; i += 2) { + if (vm_strings[i] == NULL) + break; + envptr = getenv(vm_strings[i]); + if (envptr) { + if (strncmp(envptr, vm_strings[i+1], strlen(vm_strings[i+1])) == 0) { + freeenv(envptr); + return 1; + } + freeenv(envptr); + } + } + return 0; +} diff -u -r /usr/src/sys.old/ia64/ia64/machdep.c /usr/src/sys/ia64/ia64/machdep.c --- /usr/src/sys.old/ia64/ia64/machdep.c 2007-12-29 03:01:29.000000000 -0600 +++ /usr/src/sys/ia64/ia64/machdep.c 2007-12-29 19:02:23.000000000 -0600 @@ -1531,3 +1531,9 @@ { return (ENODEV); } + +int +detect_virtualmachine(void) +{ + return 0; +} diff -u -r /usr/src/sys.old/kern/subr_param.c /usr/src/sys/kern/subr_param.c --- /usr/src/sys.old/kern/subr_param.c 2007-12-29 03:01:29.000000000 -0600 +++ /usr/src/sys/kern/subr_param.c 2007-12-29 03:14:23.000000000 -0600 @@ -58,6 +58,9 @@ # define HZ 100 # endif #endif +#ifndef VIRTUAL_HZ +# define VIRTUAL_HZ 100 +#endif #define NPROC (20 + 16 * maxusers) #ifndef NBUF #define NBUF 0 @@ -109,7 +112,16 @@ init_param1(void) { - hz = HZ; + /* Virtualization environments can't keep up with a + * 1000hz tick rate, leading to highly inaccurate + * timekeeping by FreeBSD guests. To fix this problem, + * drop back to 100hz when we detect that we are running + * inside a virtual machine. + */ + if (detect_virtualmachine()) + hz = VIRTUAL_HZ; + else + hz = HZ; TUNABLE_INT_FETCH("kern.hz", &hz); tick = 1000000 / hz; diff -u -r /usr/src/sys.old/pc98/pc98/machdep.c /usr/src/sys/pc98/pc98/machdep.c --- /usr/src/sys.old/pc98/pc98/machdep.c 2007-12-29 03:01:34.000000000 -0600 +++ /usr/src/sys/pc98/pc98/machdep.c 2007-12-29 19:01:49.000000000 -0600 @@ -2791,3 +2791,9 @@ } #endif /* KDB */ + +int +detect_virtualmachine(void) +{ + return 0; +} diff -u -r /usr/src/sys.old/powerpc/powerpc/intr_machdep.c /usr/src/sys/powerpc/powerpc/intr_machdep.c --- /usr/src/sys.old/powerpc/powerpc/intr_machdep.c 2007-12-29 03:01:34.000000000 -0600 +++ /usr/src/sys/powerpc/powerpc/intr_machdep.c 2007-12-29 18:59:36.000000000 -0600 @@ -304,3 +304,9 @@ if (i != NULL) PIC_MASK(pic, i->irq); } + +int +detect_virtualmachine(void) +{ + return 0; +} diff -u -r /usr/src/sys.old/sparc64/sparc64/machdep.c /usr/src/sys/sparc64/sparc64/machdep.c --- /usr/src/sys.old/sparc64/sparc64/machdep.c 2007-12-29 03:01:35.000000000 -0600 +++ /usr/src/sys/sparc64/sparc64/machdep.c 2007-12-29 19:01:33.000000000 -0600 @@ -910,3 +910,9 @@ mtx_pool_unlock(mtxpool_sleep, ut); return (ut); } + +int +detect_virtualmachine(void) +{ + return 0; +} diff -u -r /usr/src/sys.old/sun4v/sun4v/machdep.c /usr/src/sys/sun4v/sun4v/machdep.c --- /usr/src/sys.old/sun4v/sun4v/machdep.c 2007-12-29 03:01:01.000000000 -0600 +++ /usr/src/sys/sun4v/sun4v/machdep.c 2007-12-29 18:58:49.000000000 -0600 @@ -999,3 +999,9 @@ if (rdpr(pil) < PIL_TICK) hv_cpu_yield(); } + +int +detect_virtualmachine(void) +{ + return 0; +} diff -u -r /usr/src/sys.old/sys/systm.h /usr/src/sys/sys/systm.h --- /usr/src/sys.old/sys/systm.h 2007-12-29 03:01:35.000000000 -0600 +++ /usr/src/sys/sys/systm.h 2007-12-29 03:50:59.000000000 -0600 @@ -245,6 +245,8 @@ int unsetenv(const char *name); int testenv(const char *name); +int detect_virtualmachine(void); + typedef uint64_t (cpu_tick_f)(void); void set_cputicker(cpu_tick_f *func, uint64_t freq, unsigned var); extern cpu_tick_f *cpu_ticks;