Module Name:    src
Committed By:   maxv
Date:           Sun Jan 20 16:55:21 UTC 2019

Modified Files:
        src/sys/arch/x86/include: fpu.h
        src/sys/arch/x86/x86: fpu.c
        src/sys/dev/nvmm/x86: nvmm_x86_svm.c

Log Message:
Improvements in NVMM

 * Handle the FPU differently, limit the states via the given mask rather
   than via XCR0. Align to 64 bytes. Provide an initial gXCR0, to be sure
   that XCR0_X87 is set. Reset XSTATE_BV when the state is modified by
   the virtualizer, to force a reload from memory.

 * Hide RDTSCP.

 * Zero-extend RBX/RCX/RDX when handling the NVMM CPUID signature.

 * Take ECX and not RCX on MSR instructions.


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/x86/include/fpu.h
cvs rdiff -u -r1.48 -r1.49 src/sys/arch/x86/x86/fpu.c
cvs rdiff -u -r1.15 -r1.16 src/sys/dev/nvmm/x86/nvmm_x86_svm.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/include/fpu.h
diff -u src/sys/arch/x86/include/fpu.h:1.13 src/sys/arch/x86/include/fpu.h:1.14
--- src/sys/arch/x86/include/fpu.h:1.13	Fri Oct  5 18:51:52 2018
+++ src/sys/arch/x86/include/fpu.h	Sun Jan 20 16:55:21 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu.h,v 1.13 2018/10/05 18:51:52 maxv Exp $	*/
+/*	$NetBSD: fpu.h,v 1.14 2019/01/20 16:55:21 maxv Exp $	*/
 
 #ifndef	_X86_FPU_H_
 #define	_X86_FPU_H_
@@ -14,8 +14,8 @@ struct trapframe;
 void fpuinit(struct cpu_info *);
 void fpuinit_mxcsr_mask(void);
 
-void fpu_area_save(void *);
-void fpu_area_restore(void *);
+void fpu_area_save(void *, uint64_t);
+void fpu_area_restore(void *, uint64_t);
 
 void fpusave_lwp(struct lwp *, bool);
 void fpusave_cpu(bool);

Index: src/sys/arch/x86/x86/fpu.c
diff -u src/sys/arch/x86/x86/fpu.c:1.48 src/sys/arch/x86/x86/fpu.c:1.49
--- src/sys/arch/x86/x86/fpu.c:1.48	Fri Oct  5 18:51:52 2018
+++ src/sys/arch/x86/x86/fpu.c	Sun Jan 20 16:55:21 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu.c,v 1.48 2018/10/05 18:51:52 maxv Exp $	*/
+/*	$NetBSD: fpu.c,v 1.49 2019/01/20 16:55:21 maxv Exp $	*/
 
 /*
  * Copyright (c) 2008 The NetBSD Foundation, Inc.  All
@@ -96,7 +96,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.48 2018/10/05 18:51:52 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.49 2019/01/20 16:55:21 maxv Exp $");
 
 #include "opt_multiprocessor.h"
 
@@ -209,7 +209,7 @@ fpu_clear_amd(void)
 }
 
 void
-fpu_area_save(void *area)
+fpu_area_save(void *area, uint64_t xsave_features)
 {
 	clts();
 
@@ -221,16 +221,16 @@ fpu_area_save(void *area)
 		fxsave(area);
 		break;
 	case FPU_SAVE_XSAVE:
-		xsave(area, x86_xsave_features);
+		xsave(area, xsave_features);
 		break;
 	case FPU_SAVE_XSAVEOPT:
-		xsaveopt(area, x86_xsave_features);
+		xsaveopt(area, xsave_features);
 		break;
 	}
 }
 
 void
-fpu_area_restore(void *area)
+fpu_area_restore(void *area, uint64_t xsave_features)
 {
 	clts();
 
@@ -247,7 +247,7 @@ fpu_area_restore(void *area)
 	case FPU_SAVE_XSAVEOPT:
 		if (cpu_vendor == CPUVENDOR_AMD)
 			fpu_clear_amd();
-		xrstor(area, x86_xsave_features);
+		xrstor(area, xsave_features);
 		break;
 	}
 }
@@ -262,7 +262,7 @@ fpu_lwp_install(struct lwp *l)
 	KASSERT(pcb->pcb_fpcpu == NULL);
 	ci->ci_fpcurlwp = l;
 	pcb->pcb_fpcpu = ci;
-	fpu_area_restore(&pcb->pcb_savefpu);
+	fpu_area_restore(&pcb->pcb_savefpu, x86_xsave_features);
 }
 
 void
@@ -532,7 +532,7 @@ fpusave_cpu(bool save)
 	pcb = lwp_getpcb(l);
 
 	if (save) {
-		fpu_area_save(&pcb->pcb_savefpu);
+		fpu_area_save(&pcb->pcb_savefpu, x86_xsave_features);
 	}
 
 	stts();

Index: src/sys/dev/nvmm/x86/nvmm_x86_svm.c
diff -u src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.15 src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.16
--- src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.15	Sun Jan 13 10:07:50 2019
+++ src/sys/dev/nvmm/x86/nvmm_x86_svm.c	Sun Jan 20 16:55:21 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmm_x86_svm.c,v 1.15 2019/01/13 10:07:50 maxv Exp $	*/
+/*	$NetBSD: nvmm_x86_svm.c,v 1.16 2019/01/20 16:55:21 maxv Exp $	*/
 
 /*
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_svm.c,v 1.15 2019/01/13 10:07:50 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_svm.c,v 1.16 2019/01/20 16:55:21 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -524,7 +524,7 @@ struct svm_cpudata {
 	uint64_t fsbase;
 	uint64_t kernelgsbase;
 	bool ts_set;
-	struct xsave_header hfpu __aligned(16);
+	struct xsave_header hfpu __aligned(64);
 
 	/* Event state */
 	bool int_window_exit;
@@ -535,7 +535,7 @@ struct svm_cpudata {
 	uint64_t gprs[NVMM_X64_NGPR];
 	uint64_t drs[NVMM_X64_NDR];
 	uint64_t tsc_offset;
-	struct xsave_header gfpu __aligned(16);
+	struct xsave_header gfpu __aligned(64);
 };
 
 static void
@@ -779,12 +779,16 @@ svm_inkernel_handle_cpuid(struct nvmm_cp
 		cpudata->gprs[NVMM_X64_GPR_RDX] = svm_xcr0_mask >> 32;
 		break;
 	case 0x40000000:
+		cpudata->gprs[NVMM_X64_GPR_RBX] = 0;
+		cpudata->gprs[NVMM_X64_GPR_RCX] = 0;
+		cpudata->gprs[NVMM_X64_GPR_RDX] = 0;
 		memcpy(&cpudata->gprs[NVMM_X64_GPR_RBX], "___ ", 4);
 		memcpy(&cpudata->gprs[NVMM_X64_GPR_RCX], "NVMM", 4);
 		memcpy(&cpudata->gprs[NVMM_X64_GPR_RDX], " ___", 4);
 		break;
-	case 0x80000001: /* No SVM in ECX. The rest is tunable. */
+	case 0x80000001: /* No SVM, no RDTSCP. The rest is tunable. */
 		cpudata->gprs[NVMM_X64_GPR_RCX] &= ~CPUID_SVM;
+		cpudata->gprs[NVMM_X64_GPR_RDX] &= ~CPUID_RDTSCP;
 		break;
 	default:
 		break;
@@ -1007,7 +1011,7 @@ svm_exit_msr(struct nvmm_machine *mach, 
 		exit->u.msr.type = NVMM_EXIT_MSR_WRMSR;
 	}
 
-	exit->u.msr.msr = cpudata->gprs[NVMM_X64_GPR_RCX];
+	exit->u.msr.msr = (cpudata->gprs[NVMM_X64_GPR_RCX] & 0xFFFFFFFF);
 
 	if (info == 1) {
 		uint64_t rdx, rax;
@@ -1092,15 +1096,15 @@ svm_vcpu_guest_fpu_enter(struct nvmm_cpu
 {
 	struct svm_cpudata *cpudata = vcpu->cpudata;
 
-	if (x86_xsave_features != 0) {
+	cpudata->ts_set = (rcr0() & CR0_TS) != 0;
+
+	fpu_area_save(&cpudata->hfpu, svm_xcr0_mask);
+	fpu_area_restore(&cpudata->gfpu, svm_xcr0_mask);
+
+	if (svm_xcr0_mask != 0) {
 		cpudata->hxcr0 = rdxcr(0);
 		wrxcr(0, cpudata->gxcr0);
 	}
-
-	cpudata->ts_set = (rcr0() & CR0_TS) != 0;
-
-	fpu_area_save(&cpudata->hfpu);
-	fpu_area_restore(&cpudata->gfpu);
 }
 
 static void
@@ -1108,17 +1112,17 @@ svm_vcpu_guest_fpu_leave(struct nvmm_cpu
 {
 	struct svm_cpudata *cpudata = vcpu->cpudata;
 
-	fpu_area_save(&cpudata->gfpu);
-	fpu_area_restore(&cpudata->hfpu);
+	if (svm_xcr0_mask != 0) {
+		cpudata->gxcr0 = rdxcr(0);
+		wrxcr(0, cpudata->hxcr0);
+	}
+
+	fpu_area_save(&cpudata->gfpu, svm_xcr0_mask);
+	fpu_area_restore(&cpudata->hfpu, svm_xcr0_mask);
 
 	if (cpudata->ts_set) {
 		stts();
 	}
-
-	if (x86_xsave_features != 0) {
-		cpudata->gxcr0 = rdxcr(0);
-		wrxcr(0, cpudata->hxcr0);
-	}
 }
 
 static void
@@ -1580,6 +1584,7 @@ svm_vcpu_init(struct nvmm_machine *mach,
 
 	/* Must always be set. */
 	vmcb->state.efer = EFER_SVME;
+	cpudata->gxcr0 = XCR0_X87;
 
 	/* Init XSAVE header. */
 	cpudata->gfpu.xsh_xstate_bv = svm_xcr0_mask;
@@ -1779,13 +1784,11 @@ svm_vcpu_setstate(struct nvmm_cpu *vcpu,
 		vmcb->ctrl.v |= __SHIFTIN(state->crs[NVMM_X64_CR_CR8],
 		    VMCB_CTRL_V_TPR);
 
-		/* Clear unsupported XCR0 bits, set mandatory X87 bit. */
 		if (svm_xcr0_mask != 0) {
+			/* Clear illegal XCR0 bits, set mandatory X87 bit. */
 			cpudata->gxcr0 = state->crs[NVMM_X64_CR_XCR0];
 			cpudata->gxcr0 &= svm_xcr0_mask;
 			cpudata->gxcr0 |= XCR0_X87;
-		} else {
-			cpudata->gxcr0 = 0;
 		}
 	}
 
@@ -1846,6 +1849,11 @@ svm_vcpu_setstate(struct nvmm_cpu *vcpu,
 		fpustate = (struct fxsave *)cpudata->gfpu.xsh_fxsave;
 		fpustate->fx_mxcsr_mask &= x86_fpu_mxcsr_mask;
 		fpustate->fx_mxcsr &= fpustate->fx_mxcsr_mask;
+
+		if (svm_xcr0_mask != 0) {
+			/* Reset XSTATE_BV, to force a reload. */
+			cpudata->gfpu.xsh_xstate_bv = svm_xcr0_mask;
+		}
 	}
 
 	svm_vmcb_cache_update(vmcb, flags);

Reply via email to