Module Name:    src
Committed By:   mgorny
Date:           Sat Oct 24 07:14:30 UTC 2020

Modified Files:
        src/sys/arch/x86/include: cpufunc.h fpu.h
        src/sys/arch/x86/x86: fpu.c
        src/sys/dev/nvmm/x86: nvmm_x86_svm.c nvmm_x86_vmx.c
        src/tests/lib/libc/sys: t_ptrace_x86_wait.h

Log Message:
Issue 64-bit versions of *XSAVE* for 64-bit amd64 programs

When calling FXSAVE, XSAVE, FXRSTOR, ... for 64-bit programs on amd64
use the 64-suffixed variant in order to include the complete FIP/FDP
registers in the x87 area.

The difference between the two variants is that the FXSAVE64 (new)
variant represents FIP/FDP as 64-bit fields (union fp_addr.fa_64),
while the legacy FXSAVE variant uses split fields: 32-bit offset,
16-bit segment and 16-bit reserved field (union fp_addr.fa_32).
The latter implies that the actual addresses are truncated to 32 bits
which is insufficient in modern programs.

The change is applied only to 64-bit programs on amd64.  Plain i386
and compat32 continue using plain FXSAVE.  Similarly, NVMM is not
changed as I am not familiar with that code.

This is a potentially breaking change.  However, I don't think it likely
to actually break anything because the data provided by the old variant
were not meaningful (because of the truncated pointer).


To generate a diff of this commit:
cvs rdiff -u -r1.41 -r1.42 src/sys/arch/x86/include/cpufunc.h
cvs rdiff -u -r1.22 -r1.23 src/sys/arch/x86/include/fpu.h
cvs rdiff -u -r1.75 -r1.76 src/sys/arch/x86/x86/fpu.c
cvs rdiff -u -r1.81 -r1.82 src/sys/dev/nvmm/x86/nvmm_x86_svm.c
cvs rdiff -u -r1.80 -r1.81 src/sys/dev/nvmm/x86/nvmm_x86_vmx.c
cvs rdiff -u -r1.29 -r1.30 src/tests/lib/libc/sys/t_ptrace_x86_wait.h

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/cpufunc.h
diff -u src/sys/arch/x86/include/cpufunc.h:1.41 src/sys/arch/x86/include/cpufunc.h:1.42
--- src/sys/arch/x86/include/cpufunc.h:1.41	Mon Jun 15 09:09:23 2020
+++ src/sys/arch/x86/include/cpufunc.h	Sat Oct 24 07:14:29 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpufunc.h,v 1.41 2020/06/15 09:09:23 msaitoh Exp $	*/
+/*	$NetBSD: cpufunc.h,v 1.42 2020/10/24 07:14:29 mgorny Exp $	*/
 
 /*
  * Copyright (c) 1998, 2007, 2019 The NetBSD Foundation, Inc.
@@ -485,6 +485,82 @@ xrstor(const void *addr, uint64_t mask)
 	);
 }
 
+#ifdef __x86_64__
+static inline void
+fxsave64(void *addr)
+{
+	uint8_t *area = addr;
+
+	__asm volatile (
+		"fxsave64	%[area]"
+		: [area] "=m" (*area)
+		:
+		: "memory"
+	);
+}
+
+static inline void
+fxrstor64(const void *addr)
+{
+	const uint8_t *area = addr;
+
+	__asm volatile (
+		"fxrstor64 %[area]"
+		:
+		: [area] "m" (*area)
+		: "memory"
+	);
+}
+
+static inline void
+xsave64(void *addr, uint64_t mask)
+{
+	uint8_t *area = addr;
+	uint32_t low, high;
+
+	low = mask;
+	high = mask >> 32;
+	__asm volatile (
+		"xsave64	%[area]"
+		: [area] "=m" (*area)
+		: "a" (low), "d" (high)
+		: "memory"
+	);
+}
+
+static inline void
+xsaveopt64(void *addr, uint64_t mask)
+{
+	uint8_t *area = addr;
+	uint32_t low, high;
+
+	low = mask;
+	high = mask >> 32;
+	__asm volatile (
+		"xsaveopt64 %[area]"
+		: [area] "=m" (*area)
+		: "a" (low), "d" (high)
+		: "memory"
+	);
+}
+
+static inline void
+xrstor64(const void *addr, uint64_t mask)
+{
+	const uint8_t *area = addr;
+	uint32_t low, high;
+
+	low = mask;
+	high = mask >> 32;
+	__asm volatile (
+		"xrstor64 %[area]"
+		:
+		: [area] "m" (*area), "a" (low), "d" (high)
+		: "memory"
+	);
+}
+#endif
+
 /* -------------------------------------------------------------------------- */
 
 #ifdef XENPV

Index: src/sys/arch/x86/include/fpu.h
diff -u src/sys/arch/x86/include/fpu.h:1.22 src/sys/arch/x86/include/fpu.h:1.23
--- src/sys/arch/x86/include/fpu.h:1.22	Thu Oct 15 17:40:14 2020
+++ src/sys/arch/x86/include/fpu.h	Sat Oct 24 07:14:29 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu.h,v 1.22 2020/10/15 17:40:14 mgorny Exp $	*/
+/*	$NetBSD: fpu.h,v 1.23 2020/10/24 07:14:29 mgorny 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 *, uint64_t);
-void fpu_area_restore(const void *, uint64_t);
+void fpu_area_save(void *, uint64_t, bool);
+void fpu_area_restore(const void *, uint64_t, bool);
 
 void fpu_save(void);
 

Index: src/sys/arch/x86/x86/fpu.c
diff -u src/sys/arch/x86/x86/fpu.c:1.75 src/sys/arch/x86/x86/fpu.c:1.76
--- src/sys/arch/x86/x86/fpu.c:1.75	Thu Oct 15 17:40:14 2020
+++ src/sys/arch/x86/x86/fpu.c	Sat Oct 24 07:14:30 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu.c,v 1.75 2020/10/15 17:40:14 mgorny Exp $	*/
+/*	$NetBSD: fpu.c,v 1.76 2020/10/24 07:14:30 mgorny Exp $	*/
 
 /*
  * Copyright (c) 2008, 2019 The NetBSD Foundation, Inc.  All
@@ -96,7 +96,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.75 2020/10/15 17:40:14 mgorny Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.76 2020/10/24 07:14:30 mgorny Exp $");
 
 #include "opt_multiprocessor.h"
 
@@ -156,7 +156,7 @@ fpu_save_lwp(struct lwp *l)
 	s = splvm();
 	if (l->l_md.md_flags & MDL_FPU_IN_CPU) {
 		KASSERT((l->l_flag & LW_SYSTEM) == 0);
-		fpu_area_save(area, x86_xsave_features);
+		fpu_area_save(area, x86_xsave_features, !(l->l_proc->p_flag & PK_32));
 		l->l_md.md_flags &= ~MDL_FPU_IN_CPU;
 	}
 	splx(s);
@@ -246,21 +246,27 @@ fpu_errata_amd(void)
 	fldummy();
 }
 
+#ifdef __x86_64__
+#define XS64(x) (is_64bit ? x##64 : x)
+#else
+#define XS64(x) x
+#endif
+
 void
-fpu_area_save(void *area, uint64_t xsave_features)
+fpu_area_save(void *area, uint64_t xsave_features, bool is_64bit)
 {
 	switch (x86_fpu_save) {
 	case FPU_SAVE_FSAVE:
 		fnsave(area);
 		break;
 	case FPU_SAVE_FXSAVE:
-		fxsave(area);
+		XS64(fxsave)(area);
 		break;
 	case FPU_SAVE_XSAVE:
-		xsave(area, xsave_features);
+		XS64(xsave)(area, xsave_features);
 		break;
 	case FPU_SAVE_XSAVEOPT:
-		xsaveopt(area, xsave_features);
+		XS64(xsaveopt)(area, xsave_features);
 		break;
 	}
 
@@ -268,7 +274,7 @@ fpu_area_save(void *area, uint64_t xsave
 }
 
 void
-fpu_area_restore(const void *area, uint64_t xsave_features)
+fpu_area_restore(const void *area, uint64_t xsave_features, bool is_64bit)
 {
 	clts();
 
@@ -279,13 +285,13 @@ fpu_area_restore(const void *area, uint6
 	case FPU_SAVE_FXSAVE:
 		if (cpu_vendor == CPUVENDOR_AMD)
 			fpu_errata_amd();
-		fxrstor(area);
+		XS64(fxrstor)(area);
 		break;
 	case FPU_SAVE_XSAVE:
 	case FPU_SAVE_XSAVEOPT:
 		if (cpu_vendor == CPUVENDOR_AMD)
 			fpu_errata_amd();
-		xrstor(area, xsave_features);
+		XS64(xrstor)(area, xsave_features);
 		break;
 	}
 }
@@ -294,7 +300,8 @@ void
 fpu_handle_deferred(void)
 {
 	struct pcb *pcb = lwp_getpcb(curlwp);
-	fpu_area_restore(&pcb->pcb_savefpu, x86_xsave_features);
+	fpu_area_restore(&pcb->pcb_savefpu, x86_xsave_features,
+	    !(curlwp->l_proc->p_flag & PK_32));
 }
 
 void
@@ -309,7 +316,8 @@ fpu_switch(struct lwp *oldlwp, struct lw
 	if (oldlwp->l_md.md_flags & MDL_FPU_IN_CPU) {
 		KASSERT(!(oldlwp->l_flag & LW_SYSTEM));
 		pcb = lwp_getpcb(oldlwp);
-		fpu_area_save(&pcb->pcb_savefpu, x86_xsave_features);
+		fpu_area_save(&pcb->pcb_savefpu, x86_xsave_features,
+		    !(oldlwp->l_proc->p_flag & PK_32));
 		oldlwp->l_md.md_flags &= ~MDL_FPU_IN_CPU;
 	}
 	KASSERT(!(newlwp->l_md.md_flags & MDL_FPU_IN_CPU));
@@ -413,7 +421,7 @@ fpu_kern_leave(void)
 	 * through Spectre-class attacks to userland, even if there are
 	 * no bugs in fpu state management.
 	 */
-	fpu_area_restore(&zero_fpu, x86_xsave_features);
+	fpu_area_restore(&zero_fpu, x86_xsave_features, false);
 
 	/*
 	 * Set CR0_TS again so that the kernel can't accidentally use

Index: src/sys/dev/nvmm/x86/nvmm_x86_svm.c
diff -u src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.81 src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.82
--- src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.81	Tue Sep  8 17:02:03 2020
+++ src/sys/dev/nvmm/x86/nvmm_x86_svm.c	Sat Oct 24 07:14:30 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmm_x86_svm.c,v 1.81 2020/09/08 17:02:03 maxv Exp $	*/
+/*	$NetBSD: nvmm_x86_svm.c,v 1.82 2020/10/24 07:14:30 mgorny Exp $	*/
 
 /*
  * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_svm.c,v 1.81 2020/09/08 17:02:03 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_svm.c,v 1.82 2020/10/24 07:14:30 mgorny Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -1351,7 +1351,8 @@ svm_vcpu_guest_fpu_enter(struct nvmm_cpu
 	struct svm_cpudata *cpudata = vcpu->cpudata;
 
 	fpu_kern_enter();
-	fpu_area_restore(&cpudata->gfpu, svm_xcr0_mask);
+	/* TODO: should we use *XSAVE64 here? */
+	fpu_area_restore(&cpudata->gfpu, svm_xcr0_mask, false);
 
 	if (svm_xcr0_mask != 0) {
 		cpudata->hxcr0 = rdxcr(0);
@@ -1369,7 +1370,8 @@ svm_vcpu_guest_fpu_leave(struct nvmm_cpu
 		wrxcr(0, cpudata->hxcr0);
 	}
 
-	fpu_area_save(&cpudata->gfpu, svm_xcr0_mask);
+	/* TODO: should we use *XSAVE64 here? */
+	fpu_area_save(&cpudata->gfpu, svm_xcr0_mask, false);
 	fpu_kern_leave();
 }
 

Index: src/sys/dev/nvmm/x86/nvmm_x86_vmx.c
diff -u src/sys/dev/nvmm/x86/nvmm_x86_vmx.c:1.80 src/sys/dev/nvmm/x86/nvmm_x86_vmx.c:1.81
--- src/sys/dev/nvmm/x86/nvmm_x86_vmx.c:1.80	Tue Sep  8 17:02:03 2020
+++ src/sys/dev/nvmm/x86/nvmm_x86_vmx.c	Sat Oct 24 07:14:30 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmm_x86_vmx.c,v 1.80 2020/09/08 17:02:03 maxv Exp $	*/
+/*	$NetBSD: nvmm_x86_vmx.c,v 1.81 2020/10/24 07:14:30 mgorny Exp $	*/
 
 /*
  * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_vmx.c,v 1.80 2020/09/08 17:02:03 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_vmx.c,v 1.81 2020/10/24 07:14:30 mgorny Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -2014,7 +2014,8 @@ vmx_vcpu_guest_fpu_enter(struct nvmm_cpu
 	struct vmx_cpudata *cpudata = vcpu->cpudata;
 
 	fpu_kern_enter();
-	fpu_area_restore(&cpudata->gfpu, vmx_xcr0_mask);
+	/* TODO: should we use *XSAVE64 here? */
+	fpu_area_restore(&cpudata->gfpu, vmx_xcr0_mask, false);
 
 	if (vmx_xcr0_mask != 0) {
 		cpudata->hxcr0 = rdxcr(0);
@@ -2032,7 +2033,8 @@ vmx_vcpu_guest_fpu_leave(struct nvmm_cpu
 		wrxcr(0, cpudata->hxcr0);
 	}
 
-	fpu_area_save(&cpudata->gfpu, vmx_xcr0_mask);
+	/* TODO: should we use *XSAVE64 here? */
+	fpu_area_save(&cpudata->gfpu, vmx_xcr0_mask, false);
 	fpu_kern_leave();
 }
 

Index: src/tests/lib/libc/sys/t_ptrace_x86_wait.h
diff -u src/tests/lib/libc/sys/t_ptrace_x86_wait.h:1.29 src/tests/lib/libc/sys/t_ptrace_x86_wait.h:1.30
--- src/tests/lib/libc/sys/t_ptrace_x86_wait.h:1.29	Fri Oct 16 08:51:12 2020
+++ src/tests/lib/libc/sys/t_ptrace_x86_wait.h	Sat Oct 24 07:14:30 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: t_ptrace_x86_wait.h,v 1.29 2020/10/16 08:51:12 mgorny Exp $	*/
+/*	$NetBSD: t_ptrace_x86_wait.h,v 1.30 2020/10/24 07:14:30 mgorny Exp $	*/
 
 /*-
  * Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
@@ -3387,12 +3387,10 @@ x86_register_test(enum x86_test_regset r
 				ATF_CHECK_EQ(fxs->fx_opcode,
 				    expected_fpu.opcode);
 #if defined(__x86_64__)
-#if 0 /* TODO: kernel needs patching to call *XSAVE64 */
 				ATF_CHECK_EQ(fxs->fx_ip.fa_64,
 				    ((uint64_t)gpr.regs[_REG_RIP]) - 3);
 				ATF_CHECK_EQ(fxs->fx_dp.fa_64,
 				    (uint64_t)&x86_test_zero);
-#endif
 #else
 				ATF_CHECK_EQ(fxs->fx_ip.fa_32.fa_off,
 				    (uint32_t)gpr.r_eip - 3);

Reply via email to