From d276c3c782fe9d16f460f77c407d125ae75c9dde Mon Sep 17 00:00:00 2001
From: Venkatesh Srinivas <me@endeavour.zapto.org>
Date: Fri, 18 May 2012 21:28:44 -0700
Subject: [PATCH] kernel -- vmm_guest & CLFLUSH

* Introduce 'vmm_guest', to indicate the kernel in running in a virtualized
  environment of some sort, either a vkernel, or in KVM/QEMU. Use the CPUID
  flag 'VMM' to detect a VM.

* Implement wrappers for CLFLUSH instruction

* Store CLFLUSH cache line size in cpu_clflush_line_size

* Disable CLFLUSH on VMMs by masking it out in cpu feature flags.

Originally-from: David Shao, FreeBSD
---
 sys/cpu/i386/include/cpufunc.h         |    6 ++++++
 sys/cpu/x86_64/include/cpufunc.h       |    6 ++++++
 sys/kern/subr_param.c                  |    1 +
 sys/platform/pc32/i386/initcpu.c       |   15 ++++++++++++++-
 sys/platform/pc32/i386/machdep.c       |    4 ++--
 sys/platform/pc32/include/md_var.h     |    1 +
 sys/platform/pc64/include/md_var.h     |    1 +
 sys/platform/pc64/x86_64/initcpu.c     |   13 +++++++++++++
 sys/platform/pc64/x86_64/machdep.c     |    4 ++--
 sys/platform/vkernel/platform/init.c   |    2 ++
 sys/platform/vkernel64/platform/init.c |    2 ++
 sys/sys/kernel.h                       |    1 +
 12 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/sys/cpu/i386/include/cpufunc.h b/sys/cpu/i386/include/cpufunc.h
index d51d474..f1a61eb 100644
--- a/sys/cpu/i386/include/cpufunc.h
+++ b/sys/cpu/i386/include/cpufunc.h
@@ -142,6 +142,12 @@ btrl(u_int *mask, int bit)
 }
 
 static __inline void
+clflush(u_long addr)
+{
+	__asm __volatile("clflush %0" : : "m" (*(char *) addr));
+}
+
+static __inline void
 do_cpuid(u_int ax, u_int *p)
 {
 	__asm __volatile("cpuid"
diff --git a/sys/cpu/x86_64/include/cpufunc.h b/sys/cpu/x86_64/include/cpufunc.h
index 2e2af76..1163f3f 100644
--- a/sys/cpu/x86_64/include/cpufunc.h
+++ b/sys/cpu/x86_64/include/cpufunc.h
@@ -125,6 +125,12 @@ bsrq(u_long mask)
 }
 
 static __inline void
+clflush(u_long addr)
+{
+	__asm __volatile("clflush %0" : : "m" (*(char *) addr));
+}
+
+static __inline void
 do_cpuid(u_int ax, u_int *p)
 {
 	__asm __volatile("cpuid"
diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c
index f7a062f..71f7b64 100644
--- a/sys/kern/subr_param.c
+++ b/sys/kern/subr_param.c
@@ -88,6 +88,7 @@ int	nbuf;
 int	nswbuf;
 long	maxswzone;			/* max swmeta KVA storage */
 long	maxbcache;			/* max buffer cache KVA storage */
+int	vmm_guest = 0; 			/* Running as virtual machine guest? */
 u_quad_t	maxtsiz;			/* max text size */
 u_quad_t	dfldsiz;			/* initial data size limit */
 u_quad_t	maxdsiz;			/* max data size */
diff --git a/sys/platform/pc32/i386/initcpu.c b/sys/platform/pc32/i386/initcpu.c
index 8e7df82..5cb8e30 100644
--- a/sys/platform/pc32/i386/initcpu.c
+++ b/sys/platform/pc32/i386/initcpu.c
@@ -27,7 +27,6 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/initcpu.c,v 1.19.2.9 2003/04/05 13:47:19 dwmalone Exp $
- * $DragonFly: src/sys/platform/pc32/i386/initcpu.c,v 1.10 2006/12/23 00:27:03 swildner Exp $
  */
 
 #include "opt_cpu.h"
@@ -84,6 +83,7 @@ u_int	cpu_procinfo = 0;	/* HyperThreading Info / Brand Index / CLFUSH */
 u_int	cpu_procinfo2 = 0;	/* Multicore info */
 char	cpu_vendor[20] = "";	/* CPU Origin code */
 u_int	cpu_vendor_id = 0;	/* CPU vendor ID */
+u_int	cpu_clflush_line_size = 32;	/* Default CLFLUSH line size */
 
 SYSCTL_UINT(_hw, OID_AUTO, via_feature_rng, CTLFLAG_RD,
 	&via_feature_rng, 0, "VIA C3/C7 RNG feature available in CPU");
@@ -685,6 +685,19 @@ initializecpu(void)
 		break;
 	}
 	enable_sse();
+
+	if (cpu_feature2 & CPUID2_VMM)
+		vmm_guest = 1;
+
+	/* Disable CLFLUSH on VMMs */
+	if (cpu_feature & CPUID_CLFSH) {
+		if (vmm_guest)
+			cpu_feature &= ~CPUID_CLFSH;
+		else
+			cpu_clflush_line_size =
+				((cpu_procinfo >> 8) & 0xff) * 8;
+	}
+
 }
 
 #if defined(I586_CPU) && defined(CPU_WT_ALLOC)
diff --git a/sys/platform/pc32/i386/machdep.c b/sys/platform/pc32/i386/machdep.c
index 6864c51..aef97b8 100644
--- a/sys/platform/pc32/i386/machdep.c
+++ b/sys/platform/pc32/i386/machdep.c
@@ -1953,13 +1953,13 @@ init386(int first)
 	TUNABLE_INT_FETCH("hw.lapic_enable", &lapic_enable);
 
 	/*
-	 * Some of the virtaul machines do not work w/ I/O APIC
+	 * Some of the virtual machines do not work w/ I/O APIC
 	 * enabled.  If the user does not explicitly enable or
 	 * disable the I/O APIC (ioapic_enable < 0), then we
 	 * disable I/O APIC on all virtual machines.
 	 */
 	if (ioapic_enable < 0) {
-		if (cpu_feature2 & CPUID2_VMM)
+		if (vmm_guest)
 			ioapic_enable = 0;
 		else
 			ioapic_enable = 1;
diff --git a/sys/platform/pc32/include/md_var.h b/sys/platform/pc32/include/md_var.h
index 0e78241..2366dca 100644
--- a/sys/platform/pc32/include/md_var.h
+++ b/sys/platform/pc32/include/md_var.h
@@ -61,6 +61,7 @@ extern	u_int	amd_feature;
 extern	u_int	amd_feature2;
 extern	u_int	via_feature_rng;
 extern	u_int	via_feature_xcrypt;
+extern	u_int	cpu_clflush_line_size;
 extern	u_int	cpu_fxsr;
 extern	u_int	cpu_high;
 extern	u_int	cpu_id;
diff --git a/sys/platform/pc64/include/md_var.h b/sys/platform/pc64/include/md_var.h
index cffe7c9..f929264 100644
--- a/sys/platform/pc64/include/md_var.h
+++ b/sys/platform/pc64/include/md_var.h
@@ -49,6 +49,7 @@ extern	u_int	via_feature_rng;
 extern	u_int	via_feature_xcrypt;
 extern	u_int	amd_feature;
 extern	u_int	amd_feature2;
+extern	u_int	cpu_clflush_line_size;
 extern	u_int	cpu_fxsr;
 extern	u_int	cpu_high;
 extern	u_int	cpu_id;
diff --git a/sys/platform/pc64/x86_64/initcpu.c b/sys/platform/pc64/x86_64/initcpu.c
index 165173a..0caae8b 100644
--- a/sys/platform/pc64/x86_64/initcpu.c
+++ b/sys/platform/pc64/x86_64/initcpu.c
@@ -63,6 +63,7 @@ char	cpu_vendor[20];		/* CPU Origin code */
 u_int	cpu_vendor_id;		/* CPU vendor ID */
 u_int	cpu_fxsr;		/* SSE enabled */
 u_int	cpu_mxcsr_mask;		/* Valid bits in mxcsr */
+u_int	cpu_clflush_line_size = 32;	/* Default CLFLUSH line size */
 
 SYSCTL_UINT(_hw, OID_AUTO, via_feature_rng, CTLFLAG_RD,
 	&via_feature_rng, 0, "VIA C3/C7 RNG feature available in CPU");
@@ -179,4 +180,16 @@ initializecpu(void)
 	    CPUID_TO_FAMILY(cpu_id) == 0x6 &&
 	    CPUID_TO_MODEL(cpu_id) >= 0xf)
 		init_via();
+
+	if (cpu_feature2 & CPUID2_VMM)
+		vmm_guest = 1;
+
+	/* Disable CLFLUSH on VMMs */
+	if (cpu_feature & CPUID_CLFSH) {
+		if (vmm_guest)
+			cpu_feature &= ~CPUID_CLFSH;
+		else
+			cpu_clflush_line_size = 
+				((cpu_procinfo >> 8) & 0xff) * 8;
+	}
 }
diff --git a/sys/platform/pc64/x86_64/machdep.c b/sys/platform/pc64/x86_64/machdep.c
index 204407e..bd0bacd 100644
--- a/sys/platform/pc64/x86_64/machdep.c
+++ b/sys/platform/pc64/x86_64/machdep.c
@@ -1911,7 +1911,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
 	TUNABLE_INT_FETCH("hw.lapic_enable", &lapic_enable);
 
 	/*
-	 * Some of the virtaul machines do not work w/ I/O APIC
+	 * Some of the virtual machines do not work w/ I/O APIC
 	 * enabled.  If the user does not explicitly enable or
 	 * disable the I/O APIC (ioapic_enable < 0), then we
 	 * disable I/O APIC on all virtual machines.
@@ -1921,7 +1921,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
 	 * 'cpu_feature2'
 	 */
 	if (ioapic_enable < 0) {
-		if (cpu_feature2 & CPUID2_VMM)
+		if (vmm_guest)
 			ioapic_enable = 0;
 		else
 			ioapic_enable = 1;
diff --git a/sys/platform/vkernel/platform/init.c b/sys/platform/vkernel/platform/init.c
index fc5a910..5b649ed 100644
--- a/sys/platform/vkernel/platform/init.c
+++ b/sys/platform/vkernel/platform/init.c
@@ -351,6 +351,8 @@ main(int ac, char **av)
 	setrealcpu();
 	init_kqueue();
 
+	vmm_guest = 1;
+
 	/*
 	 * Check TSC
 	 */
diff --git a/sys/platform/vkernel64/platform/init.c b/sys/platform/vkernel64/platform/init.c
index c6d2c09..7be297a 100644
--- a/sys/platform/vkernel64/platform/init.c
+++ b/sys/platform/vkernel64/platform/init.c
@@ -348,6 +348,8 @@ main(int ac, char **av)
 	setrealcpu();
 	init_kqueue();
 
+	vmm_guest = 1;
+
 	/*
 	 * Check TSC
 	 */
diff --git a/sys/sys/kernel.h b/sys/sys/kernel.h
index ea39332..acada19 100644
--- a/sys/sys/kernel.h
+++ b/sys/sys/kernel.h
@@ -86,6 +86,7 @@ extern int profhz;			/* profiling clock's frequency */
 extern int ticks;
 extern int lbolt;			/* once a second sleep address */
 extern void *lbolt_syncer;		/* approx 1 hz but may be sped up */
+extern int vmm_guest; 			/* Running as virtual machine guest? */
 
 /*
  * Enumerated types for known system startup interfaces.
-- 
1.7.7.2

