Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 14 Aug 2018 17:29:41 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r337785 - head/sys/amd64/vmm/intel
Message-ID:  <201808141729.w7EHTfrd017107@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Tue Aug 14 17:29:41 2018
New Revision: 337785
URL: https://svnweb.freebsd.org/changeset/base/337785

Log:
  Provide part of the mitigation for L1TF-VMM.
  
  On the guest entry in bhyve, flush L1 data cache, using either L1D
  flush command MSR if available, or by reading enough uninteresting
  data to fill whole cache.
  
  Flush is automatically enabled on CPUs which do not report RDCL_NO,
  and can be disabled with the hw.vmm.l1d_flush tunable/kenv.
  
  Security:	CVE-2018-3646
  Reviewed by:	emaste. jhb, Tony Luck <tony.luck@intel.com>
  Sponsored by:	The FreeBSD Foundation

Modified:
  head/sys/amd64/vmm/intel/vmx.c
  head/sys/amd64/vmm/intel/vmx_genassym.c
  head/sys/amd64/vmm/intel/vmx_support.S

Modified: head/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- head/sys/amd64/vmm/intel/vmx.c	Tue Aug 14 17:29:22 2018	(r337784)
+++ head/sys/amd64/vmm/intel/vmx.c	Tue Aug 14 17:29:41 2018	(r337785)
@@ -188,6 +188,12 @@ static u_int vpid_alloc_failed;
 SYSCTL_UINT(_hw_vmm_vmx, OID_AUTO, vpid_alloc_failed, CTLFLAG_RD,
 	    &vpid_alloc_failed, 0, NULL);
 
+static int guest_l1d_flush;
+SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, l1d_flush, CTLFLAG_RD,
+    &guest_l1d_flush, 0, NULL);
+
+uint64_t vmx_msr_flush_cmd;
+
 /*
  * The definitions of SDT probes for VMX.
  */
@@ -798,6 +804,12 @@ vmx_init(int ipinum)
 		printf("vmx_init: ept initialization failed (%d)\n", error);
 		return (error);
 	}
+
+	guest_l1d_flush = (cpu_ia32_arch_caps & IA32_ARCH_CAP_RDCL_NO) == 0;
+	TUNABLE_INT_FETCH("hw.vmm.l1d_flush", &guest_l1d_flush);
+	if (guest_l1d_flush &&
+	    (cpu_stdext_feature3 & CPUID_STDEXT3_L1D_FLUSH) != 0)
+		vmx_msr_flush_cmd = IA32_FLUSH_CMD_L1D;
 
 	/*
 	 * Stash the cr0 and cr4 bits that must be fixed to 0 or 1

Modified: head/sys/amd64/vmm/intel/vmx_genassym.c
==============================================================================
--- head/sys/amd64/vmm/intel/vmx_genassym.c	Tue Aug 14 17:29:22 2018	(r337784)
+++ head/sys/amd64/vmm/intel/vmx_genassym.c	Tue Aug 14 17:29:41 2018	(r337785)
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
+#include <vm/vm_param.h>
 
 #include <machine/vmm.h>
 #include "vmx_cpufunc.h"
@@ -88,3 +89,6 @@ ASSYM(PM_EPTGEN, offsetof(struct pmap, pm_eptgen));
 
 ASSYM(KERNEL_SS, GSEL(GDATA_SEL, SEL_KPL));
 ASSYM(KERNEL_CS, GSEL(GCODE_SEL, SEL_KPL));
+
+ASSYM(PAGE_SIZE, PAGE_SIZE);
+ASSYM(KERNBASE, KERNBASE);

Modified: head/sys/amd64/vmm/intel/vmx_support.S
==============================================================================
--- head/sys/amd64/vmm/intel/vmx_support.S	Tue Aug 14 17:29:22 2018	(r337784)
+++ head/sys/amd64/vmm/intel/vmx_support.S	Tue Aug 14 17:29:41 2018	(r337785)
@@ -30,6 +30,7 @@
  */
 
 #include <machine/asmacros.h>
+#include <machine/specialreg.h>
 
 #include "vmx_assym.h"
 
@@ -175,9 +176,47 @@ ENTRY(vmx_enter_guest)
 	jbe	invept_error		/* Check invept instruction error */
 
 guest_restore:
-	cmpl	$0, %edx
-	je	do_launch
 
+	/*
+	 * Flush L1D cache if requested.  Use IA32_FLUSH_CMD MSR if available,
+	 * otherwise load enough of the data from the zero_region to flush
+	 * existing L1D content.
+	 */
+#define	L1D_FLUSH_SIZE	(64 * 1024)
+	movl	%edx, %r8d
+	cmpb	$0, guest_l1d_flush(%rip)
+	je	after_l1d
+	movq	vmx_msr_flush_cmd(%rip), %rax
+	testq	%rax, %rax
+	jz	1f
+	movq	%rax, %rdx
+	shrq	$32, %rdx
+	movl	$MSR_IA32_FLUSH_CMD, %ecx
+	wrmsr
+	jmp	after_l1d
+1:	movq	$KERNBASE, %r9
+	movq	$-L1D_FLUSH_SIZE, %rcx
+	/*
+	 * pass 1: Preload TLB.
+	 * Kernel text is mapped using superpages.  TLB preload is
+	 * done for the benefit of older CPUs which split 2M page
+	 * into 4k TLB entries.
+	 */
+2:	movb	L1D_FLUSH_SIZE(%r9, %rcx), %al
+	addq	$PAGE_SIZE, %rcx
+	jne	2b
+	xorl	%eax, %eax
+	cpuid
+	movq	$-L1D_FLUSH_SIZE, %rcx
+	/* pass 2: Read each cache line */
+3:	movb	L1D_FLUSH_SIZE(%r9, %rcx), %al
+	addq	$64, %rcx
+	jne	3b
+	lfence
+#undef	L1D_FLUSH_SIZE
+after_l1d:
+	cmpl	$0, %r8d
+	je	do_launch
 	VMX_GUEST_RESTORE
 	vmresume
 	/*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201808141729.w7EHTfrd017107>