For the last few weeks, I've been working on adding support for KVM clock
in the projects/paravirt branch. Currently, a KVM VM guest will end up
selecting either the HPET or ACPI as the timecounter source. Unfortunately,
this is very costly since every timecounter fetch causes a VM exit. KVM
clock allows the guest to use the TSC instead; it is very similar to the
existing Xen timer.

The performance difference between HPET/ACPI and KVMCLOCK can be dramatic:
a simple disk benchmark goes from 10K IOPs to 100K IOPs.

The patch is attached is attached or available at [1]. I'd appreciate any
testing.

Also as a part of this, I've tried to generalized a bit of our existing
hypervisor guest code, with the eventual goal of being able to support more
invasive PV operations. The patch series is viewable in Phabricator.

https://reviews.freebsd.org/D1429 - paravirt: Generalize parts of the XEN
timer code into pvclock
https://reviews.freebsd.org/D1430 - paravirt: Add interface to calculate
the TSC frequency from pvclock
https://reviews.freebsd.org/D1431 - paravirt: Add simple hypervisor
registration and detection interface
https://reviews.freebsd.org/D1432 - paravirt: Add detection of bhyve using
new hypervisor interface
https://reviews.freebsd.org/D1433 - paravirt: Add detection of VMware using
new hypervisor interface
https://reviews.freebsd.org/D1434 - paravirt: Add detection of KVM using
new hypervisor interface
https://reviews.freebsd.org/D1435 - paravirt: Add KVM clock timecounter
support

My current plan is to MFC this series to 10-STABLE, and commit a
self-contained KVM clock to the other stable branches.

[1] - https://people.freebsd.org/~bryanv/patches/kvm_clock-1.patch
diff --git a/sys/amd64/include/pvclock.h b/sys/amd64/include/pvclock.h
new file mode 100644
index 0000000..f01fac6
--- /dev/null
+++ b/sys/amd64/include/pvclock.h
@@ -0,0 +1,6 @@
+/*-
+ * This file is in the public domain.
+ */
+/* $FreeBSD$ */
+
+#include <x86/pvclock.h>
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index bbbe827..7d85742 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -555,13 +555,17 @@ x86/isa/nmi.c			standard
 x86/isa/orm.c			optional	isa
 x86/pci/pci_bus.c		optional	pci
 x86/pci/qpi.c			optional	pci
+x86/x86/bhyve.c			standard
 x86/x86/busdma_bounce.c		standard
 x86/x86/busdma_machdep.c	standard
 x86/x86/dump_machdep.c		standard
 x86/x86/fdt_machdep.c		optional	fdt
+x86/x86/hypervisor.c		standard
 x86/x86/identcpu.c		standard
 x86/x86/intr_machdep.c		standard
 x86/x86/io_apic.c		standard
+x86/x86/kvm.c			standard
+x86/x86/kvm_clock.c		standard
 x86/x86/legacy.c		standard
 x86/x86/local_apic.c		standard
 x86/x86/mca.c			standard
@@ -569,8 +573,10 @@ x86/x86/mptable.c		optional	mptable
 x86/x86/mptable_pci.c		optional	mptable pci
 x86/x86/msi.c			optional	pci
 x86/x86/nexus.c			standard
+x86/x86/pvclock.c		standard
 x86/x86/tsc.c			standard
 x86/x86/delay.c			standard
+x86/x86/vmware.c		standard
 x86/xen/hvm.c			optional	xenhvm
 x86/xen/xen_intr.c		optional	xen | xenhvm
 x86/xen/pv.c			optional	xenhvm
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index 96879b8..ca83c4c 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -573,13 +573,17 @@ x86/isa/nmi.c			standard
 x86/isa/orm.c			optional isa
 x86/pci/pci_bus.c		optional pci
 x86/pci/qpi.c			optional pci
+x86/x86/bhyve.c			standard
 x86/x86/busdma_bounce.c		standard
 x86/x86/busdma_machdep.c	standard
 x86/x86/dump_machdep.c		standard
 x86/x86/fdt_machdep.c		optional fdt
+x86/x86/hypervisor.c		standard
 x86/x86/identcpu.c		standard
 x86/x86/intr_machdep.c		standard
 x86/x86/io_apic.c		optional apic
+x86/x86/kvm.c			standard
+x86/x86/kvm_clock.c		standard
 x86/x86/legacy.c		optional native
 x86/x86/local_apic.c		optional apic
 x86/x86/mca.c			standard
@@ -588,7 +592,9 @@ x86/x86/mptable_pci.c		optional apic native pci
 x86/x86/msi.c			optional apic pci
 x86/x86/nexus.c			standard
 x86/x86/tsc.c			standard
+x86/x86/pvclock.c		standard
 x86/x86/delay.c			standard
+x86/x86/vmware.c		standard
 x86/xen/hvm.c			optional xenhvm
 x86/xen/xen_intr.c		optional xen | xenhvm
 x86/xen/xen_apic.c		optional xenhvm
diff --git a/sys/dev/xen/timer/timer.c b/sys/dev/xen/timer/timer.c
index 5743076..53aff0a 100644
--- a/sys/dev/xen/timer/timer.c
+++ b/sys/dev/xen/timer/timer.c
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/clock.h>
 #include <machine/_inttypes.h>
 #include <machine/smp.h>
+#include <machine/pvclock.h>
 
 #include <dev/xen/timer/timer.h>
 
@@ -95,9 +96,6 @@ struct xentimer_softc {
 	struct eventtimer et;
 };
 
-/* Last time; this guarantees a monotonically increasing clock. */
-volatile uint64_t xen_timer_last_time = 0;
-
 static void
 xentimer_identify(driver_t *driver, device_t parent)
 {
@@ -148,128 +146,20 @@ xentimer_probe(device_t dev)
 	return (BUS_PROBE_NOWILDCARD);
 }
 
-/*
- * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
- * yielding a 64-bit result.
- */
-static inline uint64_t
-scale_delta(uint64_t delta, uint32_t mul_frac, int shift)
-{
-	uint64_t product;
-
-	if (shift < 0)
-		delta >>= -shift;
-	else
-		delta <<= shift;
-
-#if defined(__i386__)
-	{
-		uint32_t tmp1, tmp2;
-
-		/**
-		 * For i386, the formula looks like:
-		 *
-		 *   lower = (mul_frac * (delta & UINT_MAX)) >> 32
-		 *   upper = mul_frac * (delta >> 32)
-		 *   product = lower + upper
-		 */
-		__asm__ (
-			"mul  %5       ; "
-			"mov  %4,%%eax ; "
-			"mov  %%edx,%4 ; "
-			"mul  %5       ; "
-			"xor  %5,%5    ; "
-			"add  %4,%%eax ; "
-			"adc  %5,%%edx ; "
-			: "=A" (product), "=r" (tmp1), "=r" (tmp2)
-			: "a" ((uint32_t)delta), "1" ((uint32_t)(delta >> 32)),
-			  "2" (mul_frac) );
-	}
-#elif defined(__amd64__)
-	{
-		unsigned long tmp;
-
-		__asm__ (
-			"mulq %[mul_frac] ; shrd $32, %[hi], %[lo]"
-			: [lo]"=a" (product), [hi]"=d" (tmp)
-			: "0" (delta), [mul_frac]"rm"((uint64_t)mul_frac));
-	}
-#else
-#error "xentimer: unsupported architecture"
-#endif
-
-	return (product);
-}
-
-static uint64_t
-get_nsec_offset(struct vcpu_time_info *tinfo)
-{
-
-	return (scale_delta(rdtsc() - tinfo->tsc_timestamp,
-	    tinfo->tsc_to_system_mul, tinfo->tsc_shift));
-}
-
-/*
- * Read the current hypervisor system uptime value from Xen.
- * See <xen/interface/xen.h> for a description of how this works.
- */
-static uint32_t
-xen_fetch_vcpu_tinfo(struct vcpu_time_info *dst, struct vcpu_time_info *src)
-{
-
-	do {
-		dst->version = src->version;
-		rmb();
-		dst->tsc_timestamp = src->tsc_timestamp;
-		dst->system_time = src->system_time;
-		dst->tsc_to_system_mul = src->tsc_to_system_mul;
-		dst->tsc_shift = src->tsc_shift;
-		rmb();
-	} while ((src->version & 1) | (dst->version ^ src->version));
-
-	return (dst->version);
-}
-
 /**
  * \brief Get the current time, in nanoseconds, since the hypervisor booted.
  *
  * \param vcpu		vcpu_info structure to fetch the time from.
  *
- * \note This function returns the current CPU's idea of this value, unless
- *       it happens to be less than another CPU's previously determined value.
  */
 static uint64_t
 xen_fetch_vcpu_time(struct vcpu_info *vcpu)
 {
-	struct vcpu_time_info dst;
-	struct vcpu_time_info *src;
-	uint32_t pre_version;
-	uint64_t now;
-	volatile uint64_t last;
-
-	src = &vcpu->time;
-
-	do {
-		pre_version = xen_fetch_vcpu_tinfo(&dst, src);
-		barrier();
-		now = dst.system_time + get_nsec_offset(&dst);
-		barrier();
-	} while (pre_version != src->version);
+	struct pvclock_vcpu_time_info *time;
 
-	/*
-	 * Enforce a monotonically increasing clock time across all
-	 * VCPUs.  If our time is too old, use the last time and return.
-	 * Otherwise, try to update the last time.
-	 */
-	do {
-		last = xen_timer_last_time;
-		if (last > now) {
-			now = last;
-			break;
-		}
-	} while (!atomic_cmpset_64(&xen_timer_last_time, last, now));
+	time = (struct pvclock_vcpu_time_info *) &vcpu->time;
 
-	return (now);
+	return (pvclock_get_timecount(time));
 }
 
 static uint32_t
@@ -302,15 +192,11 @@ static void
 xen_fetch_wallclock(struct timespec *ts)
 {
 	shared_info_t *src = HYPERVISOR_shared_info;
-	uint32_t version = 0;
+	struct pvclock_wall_clock *wc;
 
-	do {
-		version = src->wc_version;
-		rmb();
-		ts->tv_sec = src->wc_sec;
-		ts->tv_nsec = src->wc_nsec;
-		rmb();
-	} while ((src->wc_version & 1) | (version ^ src->wc_version));
+	wc = (struct pvclock_wall_clock *) &src->wc_version;
+
+	pvclock_get_wallclock(wc, ts);
 }
 
 static void
@@ -574,7 +460,7 @@ xentimer_resume(device_t dev)
 	}
 
 	/* Reset the last uptime value */
-	xen_timer_last_time = 0;
+	pvclock_resume();
 
 	/* Reset the RTC clock */
 	inittodr(time_second);
diff --git a/sys/i386/include/pvclock.h b/sys/i386/include/pvclock.h
new file mode 100644
index 0000000..f01fac6
--- /dev/null
+++ b/sys/i386/include/pvclock.h
@@ -0,0 +1,6 @@
+/*-
+ * This file is in the public domain.
+ */
+/* $FreeBSD$ */
+
+#include <x86/pvclock.h>
diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c
index 95f3250..5332055 100644
--- a/sys/kern/subr_param.c
+++ b/sys/kern/subr_param.c
@@ -159,6 +159,8 @@ static const char *const vm_guest_sysctl_names[] = {
 	"xen",
 	"hv",
 	"vmware",
+	"bhyve",
+	"kvm",
 	NULL
 };
 CTASSERT(nitems(vm_guest_sysctl_names) - 1 == VM_LAST);
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index d3833d0..50a49d2 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -73,7 +73,7 @@ extern int vm_guest;		/* Running as virtual machine guest? */
  * Keep in sync with vm_guest_sysctl_names[].
  */
 enum VM_GUEST { VM_GUEST_NO = 0, VM_GUEST_VM, VM_GUEST_XEN, VM_GUEST_HV,
-		VM_GUEST_VMWARE, VM_LAST };
+		VM_GUEST_VMWARE, VM_GUEST_BHYVE, VM_GUEST_KVM, VM_LAST };
 
 #if defined(WITNESS) || defined(INVARIANTS)
 void	kassert_panic(const char *fmt, ...)  __printflike(1, 2);
diff --git a/sys/x86/include/hypervisor.h b/sys/x86/include/hypervisor.h
new file mode 100644
index 0000000..d5d30eb
--- /dev/null
+++ b/sys/x86/include/hypervisor.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2014 Bryan Venteicher <bry...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _X86_HYPERVISOR_H_
+#define _X86_HYPERVISOR_H_
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+
+typedef void hypervisor_init_func_t(void);
+
+/*
+ * The guest hypervisor support may provide paravirtualized or have special
+ * requirements for various operations. The callback functions are provided
+ * when a hypervisor is detected and registered.
+ */
+struct hypervisor_ops {
+};
+
+void	hypervisor_sysinit(void *func);
+void	hypervisor_register(const char *vendor, enum VM_GUEST guest,
+	    struct hypervisor_ops *ops);
+int	hypervisor_cpuid_base(const char *signature, int leaves,
+	    uint32_t *base, uint32_t *high);
+void	hypervisor_print_info(void);
+
+#define HYPERVISOR_SYSINIT(name, func)				\
+	SYSINIT(name ## _hypervisor_sysinit, SI_SUB_HYPERVISOR,	\
+	    SI_ORDER_FIRST, hypervisor_sysinit, func)
+
+#endif /* !_X86_HYPERVISOR_H_ */
diff --git a/sys/x86/include/kvm.h b/sys/x86/include/kvm.h
new file mode 100644
index 0000000..b539038
--- /dev/null
+++ b/sys/x86/include/kvm.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2014 Bryan Venteicher <bry...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _X86_KVM_H_
+#define _X86_KVM_H_
+
+#define KVM_CPUID_FEATURES_LEAF		0x40000001
+
+#define KVM_FEATURE_CLOCKSOURCE		0x00000001
+#define KVM_FEATURE_CLOCKSOURCE2	0x00000008
+
+/* Deprecated: for the CLOCKSOURCE feature. */
+#define KVM_MSR_WALL_CLOCK		0x11
+#define KVM_MSR_SYSTEM_TIME		0x12
+
+#define KVM_MSR_WALL_CLOCK_NEW		0x4b564d00
+#define KVM_MSR_SYSTEM_TIME_NEW		0x4b564d01
+
+int		kvm_paravirt_supported(void);
+uint32_t	kvm_get_features(void);
+
+uint64_t	kvm_clock_tsc_freq(void);
+
+#endif /* !_X86_KVM_H_ */
diff --git a/sys/x86/include/pvclock.h b/sys/x86/include/pvclock.h
new file mode 100644
index 0000000..25aba99
--- /dev/null
+++ b/sys/x86/include/pvclock.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2014, Bryan Venteicher <bry...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef X86_PVCLOCK
+#define X86_PVCLOCK
+
+struct pvclock_vcpu_time_info {
+	uint32_t	version;
+	uint32_t	pad0;
+	uint64_t	tsc_timestamp;
+	uint64_t	system_time;
+	uint32_t	tsc_to_system_mul;
+	int8_t		tsc_shift;
+	uint8_t		flags;
+	uint8_t		pad[2];
+} __packed;
+
+#define PVCLOCK_FLAG_TSC_STABLE		0x01
+#define PVCLOCK_FLAG_GUEST_PASUED	0x02
+
+struct pvclock_wall_clock {
+	uint32_t	version;
+	uint32_t	sec;
+	uint32_t	nsec;
+} __packed;
+
+void		pvclock_resume(void);
+uint64_t	pvclock_tsc_freq(struct pvclock_vcpu_time_info *ti);
+uint64_t	pvclock_get_timecount(struct pvclock_vcpu_time_info *ti);
+void		pvclock_get_wallclock(struct pvclock_wall_clock *wc,
+		    struct timespec *ts);
+
+#endif
diff --git a/sys/x86/include/vmware.h b/sys/x86/include/vmware.h
index c72f48d..89616c5 100644
--- a/sys/x86/include/vmware.h
+++ b/sys/x86/include/vmware.h
@@ -44,4 +44,6 @@ vmware_hvcall(u_int cmd, u_int *p)
 	: "memory");
 }
 
+uint64_t	vmware_tsc_freq(void);
+
 #endif /* !_X86_VMWARE_H_ */
diff --git a/sys/x86/x86/bhyve.c b/sys/x86/x86/bhyve.c
new file mode 100644
index 0000000..d21e808
--- /dev/null
+++ b/sys/x86/x86/bhyve.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2014 Bryan Venteicher <bry...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <x86/hypervisor.h>
+
+static uint32_t bhyve_cpuid_base = -1;
+static uint32_t bhyve_cpuid_high = -1;
+
+static int
+bhyve_cpuid_identify(void)
+{
+
+	if (bhyve_cpuid_base == -1) {
+		hypervisor_cpuid_base("bhyve bhyve", 0, &bhyve_cpuid_base,
+		    &bhyve_cpuid_high);
+	}
+
+	return (bhyve_cpuid_base > 0);
+}
+
+static void
+bhyve_init(void)
+{
+
+	if (bhyve_cpuid_identify() != 0)
+		hypervisor_register("bhyve", VM_GUEST_BHYVE, NULL);
+}
+
+HYPERVISOR_SYSINIT(bhyve, bhyve_init);
diff --git a/sys/x86/x86/hypervisor.c b/sys/x86/x86/hypervisor.c
new file mode 100644
index 0000000..30c70df
--- /dev/null
+++ b/sys/x86/x86/hypervisor.c
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 2014 Bryan Venteicher <bry...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <machine/cpufunc.h>
+#include <machine/cpu.h>
+#include <machine/md_var.h>
+#include <machine/specialreg.h>
+
+#include <x86/hypervisor.h>
+
+char hv_vendor[16];
+SYSCTL_STRING(_hw, OID_AUTO, hv_vendor, CTLFLAG_RD, hv_vendor, 0,
+    "Hypervisor vendor");
+
+void
+hypervisor_sysinit(void *func)
+{
+	hypervisor_init_func_t *init;
+
+	init = func;
+
+	/*
+	 * Call the init function if we have not already identified the
+	 * hypervisor yet. We assume the detectable hypervisors will
+	 * announce its presence via the CPUID bit.
+	 */
+	if (vm_guest == VM_GUEST_VM && cpu_feature2 & CPUID2_HV)
+		(*init)();
+}
+
+void
+hypervisor_register(const char *vendor, enum VM_GUEST guest,
+    struct hypervisor_ops *ops)
+{
+
+	strlcpy(hv_vendor, vendor, sizeof(hv_vendor));
+	vm_guest = guest;
+}
+
+/*
+ * [RFC] CPUID usage for interaction between Hypervisors and Linux.
+ * http://lkml.org/lkml/2008/10/1/246
+ */
+int
+hypervisor_cpuid_base(const char *signature, int leaves, uint32_t *base,
+    uint32_t *high)
+{
+	uint32_t leaf, regs[4];
+
+	for (leaf = 0x40000000; leaf < 0x40010000; leaf += 0x100) {
+		do_cpuid(leaf, regs);
+		if (!memcmp(signature, &regs[1], 12) &&
+		    (leaves == 0 || (regs[0] - leaf >= leaves))) {
+			*base = leaf;
+			*high = regs[0];
+			return (0);
+		}
+	}
+
+	return (1);
+}
+
+void
+hypervisor_print_info(void)
+{
+
+	if (*hv_vendor)
+		printf("Hypervisor: Origin = \"%s\"\n", hv_vendor);
+}
diff --git a/sys/x86/x86/identcpu.c b/sys/x86/x86/identcpu.c
index bae430a..c28390c 100644
--- a/sys/x86/x86/identcpu.c
+++ b/sys/x86/x86/identcpu.c
@@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$");
 
 #include <amd64/vmm/intel/vmx_controls.h>
 #include <x86/isa/icu.h>
+#include <x86/hypervisor.h>
 #include <x86/vmware.h>
 
 #ifdef __i386__
@@ -78,7 +79,6 @@ static u_int find_cpu_vendor_id(void);
 static void print_AMD_info(void);
 static void print_INTEL_info(void);
 static void print_INTEL_TLB(u_int data);
-static void print_hypervisor_info(void);
 static void print_svm_info(void);
 static void print_via_padlock_info(void);
 static void print_vmx_info(void);
@@ -123,11 +123,6 @@ static int hw_clockrate;
 SYSCTL_INT(_hw, OID_AUTO, clockrate, CTLFLAG_RD,
     &hw_clockrate, 0, "CPU instruction clock rate");
 
-u_int hv_high;
-char hv_vendor[16];
-SYSCTL_STRING(_hw, OID_AUTO, hv_vendor, CTLFLAG_RD, hv_vendor, 0,
-    "Hypervisor vendor");
-
 static eventhandler_tag tsc_post_tag;
 
 static char cpu_brand[48];
@@ -985,7 +980,7 @@ printcpuinfo(void)
 #endif
 	}
 
-	print_hypervisor_info();
+	hypervisor_print_info();
 }
 
 void
@@ -1218,25 +1213,12 @@ identify_hypervisor(void)
 	int i;
 
 	/*
-	 * [RFC] CPUID usage for interaction between Hypervisors and Linux.
-	 * http://lkml.org/lkml/2008/10/1/246
-	 *
-	 * KB1009458: Mechanisms to determine if software is running in
-	 * a VMware virtual machine
-	 * http://kb.vmware.com/kb/1009458
+	 * Modern hypervisors set the HV present feature bit and are then
+	 * identifiable through a special CPUID leaf. Hypervisors we know
+	 * about are later detected via the SI_SUB_HYPERVISOR SYSINIT().
 	 */
 	if (cpu_feature2 & CPUID2_HV) {
 		vm_guest = VM_GUEST_VM;
-		do_cpuid(0x40000000, regs);
-		if (regs[0] >= 0x40000000) {
-			hv_high = regs[0];
-			((u_int *)&hv_vendor)[0] = regs[1];
-			((u_int *)&hv_vendor)[1] = regs[2];
-			((u_int *)&hv_vendor)[2] = regs[3];
-			hv_vendor[12] = '\0';
-			if (strcmp(hv_vendor, "VMwareVMware") == 0)
-				vm_guest = VM_GUEST_VMWARE;
-		}
 		return;
 	}
 
@@ -2150,11 +2132,3 @@ print_vmx_info(void)
 		);
 	}
 }
-
-static void
-print_hypervisor_info(void)
-{
-
-	if (*hv_vendor)
-		printf("Hypervisor: Origin = \"%s\"\n", hv_vendor);
-}
diff --git a/sys/x86/x86/kvm.c b/sys/x86/x86/kvm.c
new file mode 100644
index 0000000..b47eb76
--- /dev/null
+++ b/sys/x86/x86/kvm.c
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2014 Bryan Venteicher <bry...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <machine/cpufunc.h>
+
+#include <x86/hypervisor.h>
+#include <x86/kvm.h>
+
+static int		kvm_cpuid_identify(void);
+
+static uint32_t kvm_cpuid_base = -1;
+static uint32_t kvm_cpuid_high = -1;
+
+static int
+kvm_cpuid_identify(void)
+{
+
+	if (kvm_cpuid_base == -1) {
+		hypervisor_cpuid_base("KVMKVMKVM\0\0", 0, &kvm_cpuid_base,
+		    &kvm_cpuid_high);
+	}
+
+	return (kvm_cpuid_base > 0);
+}
+
+int
+kvm_paravirt_supported(void)
+{
+
+	return (kvm_cpuid_base > 0);
+}
+
+uint32_t
+kvm_get_features(void)
+{
+	u_int regs[4];
+
+	if (kvm_paravirt_supported())
+		do_cpuid(kvm_cpuid_base | KVM_CPUID_FEATURES_LEAF, regs);
+	else
+		regs[0] = 0;
+
+	return (regs[0]);
+}
+
+static void
+kvm_init(void)
+{
+
+	if (kvm_cpuid_identify() != 0)
+		hypervisor_register("KVM", VM_GUEST_KVM, NULL);
+}
+
+HYPERVISOR_SYSINIT(kvm, kvm_init);
diff --git a/sys/x86/x86/kvm_clock.c b/sys/x86/x86/kvm_clock.c
new file mode 100644
index 0000000..7da6363
--- /dev/null
+++ b/sys/x86/x86/kvm_clock.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 2014 Bryan Venteicher <bry...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/systm.h>
+#include <sys/pcpu.h>
+#include <sys/smp.h>
+#include <sys/timetc.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/pvclock.h>
+#include <x86/kvm.h>
+
+static u_int	kvm_clock_get_timecounter(struct timecounter *);
+static void	kvm_clock_pcpu_system_time(void *);
+
+DPCPU_DEFINE(struct pvclock_vcpu_time_info, kvm_clock_vcpu_time_info);
+
+static struct timecounter kvm_clock_timecounter = {
+	kvm_clock_get_timecounter,
+	NULL,
+	~0u,
+	1000000000ULL,
+	"KVMCLOCK",
+	1000,
+};
+
+static int		kvm_clock_registered;
+static uint32_t		kvm_clock_wall_clock_msr;
+static uint32_t		kvm_clock_system_time_msr;
+
+uint64_t
+kvm_clock_tsc_freq(void)
+{
+	struct pvclock_vcpu_time_info *ti;
+	uint64_t freq;
+
+	critical_enter();
+	ti = DPCPU_PTR(kvm_clock_vcpu_time_info);
+	freq = pvclock_tsc_freq(ti);
+	critical_exit();
+
+	return (freq);
+}
+
+static u_int
+kvm_clock_get_timecounter(struct timecounter *tc)
+{
+	struct pvclock_vcpu_time_info *ti;
+	uint64_t time;
+
+	critical_enter();
+	ti = DPCPU_PTR(kvm_clock_vcpu_time_info);
+	time = pvclock_get_timecount(ti);
+	critical_exit();
+
+	return (time & UINT_MAX);
+}
+
+static void
+kvm_clock_pcpu_system_time(void *arg)
+{
+	uint64_t data;
+	int enable;
+
+	enable = *(int *) arg;
+
+	if (enable != 0)
+		data = vtophys(DPCPU_PTR(kvm_clock_vcpu_time_info)) | 1;
+	else
+		data = 0;
+
+	wrmsr(kvm_clock_system_time_msr, data);
+}
+
+static void
+kvm_clock_init(void)
+{
+	uint32_t features;
+
+	if (vm_guest != VM_GUEST_KVM || !kvm_paravirt_supported())
+		return;
+
+	features = kvm_get_features();
+
+	if (features & KVM_FEATURE_CLOCKSOURCE2) {
+		kvm_clock_wall_clock_msr = KVM_MSR_WALL_CLOCK_NEW;
+		kvm_clock_system_time_msr = KVM_MSR_SYSTEM_TIME_NEW;
+	} else if (features & KVM_FEATURE_CLOCKSOURCE) {
+		kvm_clock_wall_clock_msr = KVM_MSR_WALL_CLOCK;
+		kvm_clock_system_time_msr = KVM_MSR_SYSTEM_TIME;
+	} else
+		return;
+
+	kvm_clock_registered = 1;
+	smp_rendezvous(smp_no_rendevous_barrier, kvm_clock_pcpu_system_time,
+	    smp_no_rendevous_barrier, &kvm_clock_registered);
+
+	tc_init(&kvm_clock_timecounter);
+}
+
+SYSINIT(kvm_clock, SI_SUB_SMP, SI_ORDER_ANY, kvm_clock_init, NULL);
diff --git a/sys/x86/x86/pvclock.c b/sys/x86/x86/pvclock.c
new file mode 100644
index 0000000..d0eef185
--- /dev/null
+++ b/sys/x86/x86/pvclock.c
@@ -0,0 +1,197 @@
+/*-
+ * Copyright (c) 2009 Adrian Chadd
+ * Copyright (c) 2012 Spectra Logic Corporation
+ * Copyright (c) 2014 Bryan Venteicher
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+
+#include <machine/cpufunc.h>
+#include <machine/cpu.h>
+#include <machine/atomic.h>
+#include <machine/pvclock.h>
+
+/*
+ * Last time; this guarantees a monotonically increasing clock for when
+ * a stable TSC is not provided.
+ */
+static volatile uint64_t pvclock_last_cycles;
+
+void
+pvclock_resume(void)
+{
+
+	atomic_store_rel_64(&pvclock_last_cycles, 0);
+}
+
+uint64_t
+pvclock_tsc_freq(struct pvclock_vcpu_time_info *ti)
+{
+	uint64_t freq;
+
+	freq = (1000000000ULL << 32) / ti->tsc_to_system_mul;
+
+	if (ti->tsc_shift < 0)
+		freq <<= -ti->tsc_shift;
+	else
+		freq >>= ti->tsc_shift;
+
+	return (freq);
+}
+
+/*
+ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
+ * yielding a 64-bit result.
+ */
+static inline uint64_t
+pvclock_scale_delta(uint64_t delta, uint32_t mul_frac, int shift)
+{
+	uint64_t product;
+
+	if (shift < 0)
+		delta >>= -shift;
+	else
+		delta <<= shift;
+
+#if defined(__i386__)
+	{
+		uint32_t tmp1, tmp2;
+
+		/**
+		 * For i386, the formula looks like:
+		 *
+		 *   lower = (mul_frac * (delta & UINT_MAX)) >> 32
+		 *   upper = mul_frac * (delta >> 32)
+		 *   product = lower + upper
+		 */
+		__asm__ (
+			"mul  %5       ; "
+			"mov  %4,%%eax ; "
+			"mov  %%edx,%4 ; "
+			"mul  %5       ; "
+			"xor  %5,%5    ; "
+			"add  %4,%%eax ; "
+			"adc  %5,%%edx ; "
+			: "=A" (product), "=r" (tmp1), "=r" (tmp2)
+			: "a" ((uint32_t)delta), "1" ((uint32_t)(delta >> 32)),
+			  "2" (mul_frac) );
+	}
+#elif defined(__amd64__)
+	{
+		unsigned long tmp;
+
+		__asm__ (
+			"mulq %[mul_frac] ; shrd $32, %[hi], %[lo]"
+			: [lo]"=a" (product), [hi]"=d" (tmp)
+			: "0" (delta), [mul_frac]"rm"((uint64_t)mul_frac));
+	}
+#else
+#error "pvclock: unsupported x86 architecture?"
+#endif
+
+	return (product);
+}
+
+static uint64_t
+pvclock_get_nsec_offset(struct pvclock_vcpu_time_info *ti)
+{
+	uint64_t delta;
+
+	delta = rdtsc() - ti->tsc_timestamp;
+
+	return (pvclock_scale_delta(delta, ti->tsc_to_system_mul,
+	    ti->tsc_shift));
+}
+
+static void
+pvclock_read_time_info(struct pvclock_vcpu_time_info *ti,
+    uint64_t *cycles, uint8_t *flags)
+{
+	uint32_t version;
+
+	do {
+		version = ti->version;
+		rmb();
+		*cycles = ti->system_time + pvclock_get_nsec_offset(ti);
+		*flags = ti->flags;
+		rmb();
+	} while ((ti->version & 1) != 0 || ti->version != version);
+}
+
+static void
+pvclock_read_wall_clock(struct pvclock_wall_clock *wc, uint32_t *sec,
+    uint32_t *nsec)
+{
+	uint32_t version;
+
+	do {
+		version = wc->version;
+		rmb();
+		*sec = wc->sec;
+		*nsec = wc->nsec;
+		rmb();
+	} while ((wc->version & 1) != 0 || wc->version != version);
+}
+
+uint64_t
+pvclock_get_timecount(struct pvclock_vcpu_time_info *ti)
+{
+	uint64_t now;
+	uint8_t flags;
+	volatile uint64_t last;
+
+	pvclock_read_time_info(ti, &now, &flags);
+
+	if (flags & PVCLOCK_FLAG_TSC_STABLE)
+		return (now);
+
+	/*
+	 * Enforce a monotonically increasing clock time across all VCPUs.
+	 * If our time is too old, use the last time and return. Otherwise,
+	 * try to update the last time.
+	 */
+	do {
+		last = atomic_load_acq_64(&pvclock_last_cycles);
+		if (last > now)
+			return (last);
+	} while (!atomic_cmpset_64(&pvclock_last_cycles, last, now));
+
+	return (now);
+}
+
+void
+pvclock_get_wallclock(struct pvclock_wall_clock *wc, struct timespec *ts)
+{
+	uint32_t sec, nsec;
+
+	pvclock_read_wall_clock(wc, &sec, &nsec);
+	ts->tv_sec = sec;
+	ts->tv_nsec = nsec;
+}
diff --git a/sys/x86/x86/tsc.c b/sys/x86/x86/tsc.c
index 4ca574e..a834cb5 100644
--- a/sys/x86/x86/tsc.c
+++ b/sys/x86/x86/tsc.c
@@ -104,22 +104,6 @@ static struct timecounter tsc_timecounter = {
 };
 
 static void
-tsc_freq_vmware(void)
-{
-	u_int regs[4];
-
-	if (hv_high >= 0x40000010) {
-		do_cpuid(0x40000010, regs);
-		tsc_freq = regs[0] * 1000;
-	} else {
-		vmware_hvcall(VMW_HVCMD_GETHZ, regs);
-		if (regs[1] != UINT_MAX)
-			tsc_freq = regs[0] | ((uint64_t)regs[1] << 32);
-	}
-	tsc_is_invariant = 1;
-}
-
-static void
 tsc_freq_intel(void)
 {
 	char brand[48];
@@ -201,7 +185,8 @@ probe_tsc_freq(void)
 	}
 
 	if (vm_guest == VM_GUEST_VMWARE) {
-		tsc_freq_vmware();
+		tsc_freq = vmware_tsc_freq();
+		tsc_is_invariant = 1;
 		return;
 	}
 
diff --git a/sys/x86/x86/vmware.c b/sys/x86/x86/vmware.c
new file mode 100644
index 0000000..e16acbb
--- /dev/null
+++ b/sys/x86/x86/vmware.c
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 2014 Bryan Venteicher <bry...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/limits.h>
+
+#include <x86/hypervisor.h>
+#include <x86/vmware.h>
+
+static uint32_t vmware_cpuid_base = -1;
+static uint32_t vmware_cpuid_high = -1;
+
+static int
+vmware_cpuid_identify(void)
+{
+
+	/*
+	 * KB1009458: Mechanisms to determine if software is running in a
+	 * VMware virtual machine: http://kb.vmware.com/kb/1009458
+	 */
+	if (vmware_cpuid_base == -1) {
+		hypervisor_cpuid_base("VMwareVMware", 0, &vmware_cpuid_base,
+		    &vmware_cpuid_high);
+	}
+
+	return (vmware_cpuid_base > 0);
+}
+
+uint64_t
+vmware_tsc_freq(void)
+{
+	uint64_t freq;
+	u_int regs[4];
+
+	if (vmware_cpuid_high >= 0x40000010) {
+		do_cpuid(0x40000010, regs);
+		freq = regs[0] * 1000;
+	} else {
+		vmware_hvcall(VMW_HVCMD_GETHZ, regs);
+		if (regs[1] != UINT_MAX)
+			freq = regs[0] | ((uint64_t)regs[1] << 32);
+		else
+			freq = 0;
+	}
+
+	return (freq);
+}
+
+static void
+vmware_init(void)
+{
+
+	if (vmware_cpuid_identify() != 0)
+		hypervisor_register("VMware", VM_GUEST_VMWARE, NULL);
+}
+
+HYPERVISOR_SYSINIT(vmware, vmware_init);
_______________________________________________
freebsd-current@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"

Reply via email to