Module Name:    src
Committed By:   dsl
Date:           Sat Feb 15 22:20:42 UTC 2014

Modified Files:
        src/sys/arch/amd64/amd64: machdep.c netbsd32_machdep.c
            process_machdep.c
        src/sys/arch/amd64/include: mcontext.h
        src/sys/arch/i386/i386: machdep.c process_machdep.c
        src/sys/arch/i386/include: mcontext.h
        src/sys/arch/x86/include: fpu.h
        src/sys/arch/x86/x86: convert_xmm_s87.c fpu.c

Log Message:
Load and save the fpu registers (for copies to/from userspace) using
  helper functions in arch/x86/x86/fpu.c
They (hopefully) ensure that we write to the entire buffer and don't load
  values that might cause faults in kernel.
Also zero out the 'pad' field of the i386 mcontext fp area that I think
  once contained the registers of any Weitek fpu.
  Dunno why it wasn't pasrt of the union.
Some of these copies could be removed if the code directly copied the save
  area to/from userspace addresses.


To generate a diff of this commit:
cvs rdiff -u -r1.204 -r1.205 src/sys/arch/amd64/amd64/machdep.c
cvs rdiff -u -r1.91 -r1.92 src/sys/arch/amd64/amd64/netbsd32_machdep.c
cvs rdiff -u -r1.28 -r1.29 src/sys/arch/amd64/amd64/process_machdep.c
cvs rdiff -u -r1.16 -r1.17 src/sys/arch/amd64/include/mcontext.h
cvs rdiff -u -r1.747 -r1.748 src/sys/arch/i386/i386/machdep.c
cvs rdiff -u -r1.83 -r1.84 src/sys/arch/i386/i386/process_machdep.c
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/i386/include/mcontext.h
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/x86/include/fpu.h
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/x86/x86/convert_xmm_s87.c
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/x86/x86/fpu.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/amd64/amd64/machdep.c
diff -u src/sys/arch/amd64/amd64/machdep.c:1.204 src/sys/arch/amd64/amd64/machdep.c:1.205
--- src/sys/arch/amd64/amd64/machdep.c:1.204	Sat Feb 15 10:11:14 2014
+++ src/sys/arch/amd64/amd64/machdep.c	Sat Feb 15 22:20:41 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: machdep.c,v 1.204 2014/02/15 10:11:14 dsl Exp $	*/
+/*	$NetBSD: machdep.c,v 1.205 2014/02/15 22:20:41 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007, 2008, 2011
@@ -111,7 +111,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.204 2014/02/15 10:11:14 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.205 2014/02/15 22:20:41 dsl Exp $");
 
 /* #define XENDEBUG_LOW  */
 
@@ -1896,7 +1896,6 @@ void
 cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
 {
 	const struct trapframe *tf = l->l_md.md_regs;
-	struct pcb *pcb;
 	__greg_t ras_rip;
 
 	/* Copy general registers member by member */
@@ -1913,10 +1912,7 @@ cpu_getmcontext(struct lwp *l, mcontext_
 	mcp->_mc_tlsbase = (uintptr_t)l->l_private;;
 	*flags |= _UC_TLSBASE;
 
-	pcb = lwp_getpcb(l);
-
-	fpusave_lwp(l, true);
-	memcpy(mcp->__fpregs, &pcb->pcb_savefpu.sv_xmm, sizeof (mcp->__fpregs));
+	process_read_fpregs_xmm(l, (struct fxsave *)&mcp->__fpregs);
 	*flags |= _UC_FPU;
 }
 
@@ -1925,12 +1921,13 @@ cpu_setmcontext(struct lwp *l, const mco
 {
 	struct trapframe *tf = l->l_md.md_regs;
 	const __greg_t *gr = mcp->__gregs;
-	struct pcb *pcb = lwp_getpcb(l);
 	struct proc *p = l->l_proc;
 	int error;
 	int err, trapno;
 	int64_t rflags;
 
+	CTASSERT(sizeof (mcontext_t) == 26 * 8 + 8 + 512);
+
 	if ((flags & _UC_CPU) != 0) {
 		error = cpu_mcontext_validate(l, mcp);
 		if (error != 0)
@@ -1966,11 +1963,8 @@ cpu_setmcontext(struct lwp *l, const mco
 		l->l_md.md_flags |= MDL_IRET;
 	}
 
-	if ((flags & _UC_FPU) != 0) {
-		fpusave_lwp(l, false);
-		memcpy(&pcb->pcb_savefpu.sv_xmm, mcp->__fpregs,
-		    sizeof (mcp->__fpregs));
-	}
+	if ((flags & _UC_FPU) != 0)
+		process_write_fpregs_xmm(l, (const struct fxsave *)&mcp->__fpregs);
 
 	if ((flags & _UC_TLSBASE) != 0)
 		lwp_setprivate(l, (void *)(uintptr_t)mcp->_mc_tlsbase);

Index: src/sys/arch/amd64/amd64/netbsd32_machdep.c
diff -u src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.91 src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.92
--- src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.91	Sat Feb 15 10:11:14 2014
+++ src/sys/arch/amd64/amd64/netbsd32_machdep.c	Sat Feb 15 22:20:41 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_machdep.c,v 1.91 2014/02/15 10:11:14 dsl Exp $	*/
+/*	$NetBSD: netbsd32_machdep.c,v 1.92 2014/02/15 22:20:41 dsl Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.91 2014/02/15 10:11:14 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.92 2014/02/15 22:20:41 dsl Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd.h"
@@ -806,14 +806,9 @@ cpu_setmcontext32(struct lwp *l, const m
 
 	/* Restore floating point register context, if any. */
 	if ((flags & _UC_FPU) != 0) {
-		struct pcb *pcb = lwp_getpcb(l);
-
-		/*
-		 * If we were using the FPU, forget that we were.
-		 */
-		fpusave_lwp(l, false);
-		memcpy(&pcb->pcb_savefpu.sv_xmm, &mcp->__fpregs,
-		    sizeof (pcb->pcb_savefpu.sv_xmm));
+		/* Assume fxsave context */
+		process_write_fpregs_xmm(l, (const struct fxsave *)
+		    &mcp->__fpregs.__fp_reg_set.__fp_xmm_state);
 	}
 
 	mutex_enter(p->p_lock);
@@ -832,7 +827,6 @@ cpu_getmcontext32(struct lwp *l, mcontex
 	const struct trapframe *tf = l->l_md.md_regs;
 	__greg32_t *gr = mcp->__gregs;
 	__greg32_t ras_eip;
-	struct pcb *pcb;
 
 	/* Save register context. */
 	gr[_REG32_GS]  = tf->tf_gs;
@@ -865,11 +859,10 @@ cpu_getmcontext32(struct lwp *l, mcontex
 	*flags |= _UC_TLSBASE;
 
 	/* Save floating point register context. */
-	fpusave_lwp(l, true);
-	pcb = lwp_getpcb(l);
-	memcpy(&mcp->__fpregs, &pcb->pcb_savefpu.sv_xmm,
-	    sizeof (pcb->pcb_savefpu.sv_xmm));
-	*flags |= _UC_FPU;
+	process_read_fpregs_xmm(l, (struct fxsave *)
+	    &mcp->__fpregs.__fp_reg_set.__fp_xmm_state);
+	memset(&mcp->__fpregs.__fp_pad, 0, sizeof mcp->__fpregs.__fp_pad);
+	*flags |= _UC_FXSAVE | _UC_FPU;
 }
 
 void

Index: src/sys/arch/amd64/amd64/process_machdep.c
diff -u src/sys/arch/amd64/amd64/process_machdep.c:1.28 src/sys/arch/amd64/amd64/process_machdep.c:1.29
--- src/sys/arch/amd64/amd64/process_machdep.c:1.28	Sat Feb 15 10:11:14 2014
+++ src/sys/arch/amd64/amd64/process_machdep.c	Sat Feb 15 22:20:41 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: process_machdep.c,v 1.28 2014/02/15 10:11:14 dsl Exp $	*/
+/*	$NetBSD: process_machdep.c,v 1.29 2014/02/15 22:20:41 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -53,7 +53,7 @@
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.28 2014/02/15 10:11:14 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.29 2014/02/15 22:20:41 dsl Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -69,7 +69,6 @@ __KERNEL_RCSID(0, "$NetBSD: process_mach
 #include <x86/fpu.h>
 
 static inline struct trapframe *process_frame(struct lwp *);
-static inline struct fxsave *process_fpframe(struct lwp *);
 #if 0
 static inline int verr_gdt(struct pmap *, int sel);
 static inline int verr_ldt(struct pmap *, int sel);
@@ -82,14 +81,6 @@ process_frame(struct lwp *l)
 	return (l->l_md.md_regs);
 }
 
-static inline struct fxsave *
-process_fpframe(struct lwp *l)
-{
-	struct pcb *pcb = lwp_getpcb(l);
-
-	return &pcb->pcb_savefpu.sv_xmm;
-}
-
 int
 process_read_regs(struct lwp *l, struct reg *regs)
 {
@@ -106,10 +97,9 @@ int
 process_read_fpregs(struct lwp *l, struct fpreg *regs, size_t *sz)
 {
 
-	fpusave_lwp(l, true);
+	process_read_fpregs_xmm(l, &regs->fxstate);
 
-	regs->fxstate = *process_fpframe(l);
-	return (0);
+	return 0;
 }
 
 int
@@ -139,10 +129,8 @@ int
 process_write_fpregs(struct lwp *l, const struct fpreg *regs, size_t sz)
 {
 
-	fpusave_lwp(l, false);
-
-	memcpy(process_fpframe(l), &regs->fxstate, sizeof(*regs));
-	return (0);
+	process_write_fpregs_xmm(l, &regs->fxstate);
+	return 0;
 }
 
 int

Index: src/sys/arch/amd64/include/mcontext.h
diff -u src/sys/arch/amd64/include/mcontext.h:1.16 src/sys/arch/amd64/include/mcontext.h:1.17
--- src/sys/arch/amd64/include/mcontext.h:1.16	Sat Dec 15 22:39:04 2012
+++ src/sys/arch/amd64/include/mcontext.h	Sat Feb 15 22:20:41 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: mcontext.h,v 1.16 2012/12/15 22:39:04 dsl Exp $	*/
+/*	$NetBSD: mcontext.h,v 1.17 2014/02/15 22:20:41 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -131,18 +131,12 @@ typedef struct {
 	union {
 		struct {
 			int	__fp_state[27];	/* Environment and registers */
-			int	__fp_status;	/* Software status word */
 		} __fpchip_state;
 		struct {
-			char	__fp_emul[246];
-			char	__fp_epad[2];
-		} __fp_emul_space;
-		struct {
 			char	__fp_xmm[512];
 		} __fp_xmm_state;
-		int	__fp_fpregs[128];
 	} __fp_reg_set;
-	int	__fp_wregs[33];			/* Weitek? */
+	int	__fp_pad[33];			/* Historic padding */
 } __fpregset32_t;
 
 typedef struct {
@@ -151,6 +145,8 @@ typedef struct {
 	uint32_t	_mc_tlsbase;
 } mcontext32_t;
 
+#define _UC_FXSAVE       0x20    /* FP state is in FXSAVE format in XMM space */
+
 #define	_UC_MACHINE32_PAD	4
 #define	__UCONTEXT32_SIZE	776
 

Index: src/sys/arch/i386/i386/machdep.c
diff -u src/sys/arch/i386/i386/machdep.c:1.747 src/sys/arch/i386/i386/machdep.c:1.748
--- src/sys/arch/i386/i386/machdep.c:1.747	Sat Feb 15 10:11:15 2014
+++ src/sys/arch/i386/i386/machdep.c	Sat Feb 15 22:20:41 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: machdep.c,v 1.747 2014/02/15 10:11:15 dsl Exp $	*/
+/*	$NetBSD: machdep.c,v 1.748 2014/02/15 22:20:41 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 2000, 2004, 2006, 2008, 2009
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.747 2014/02/15 10:11:15 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.748 2014/02/15 22:20:41 dsl Exp $");
 
 #include "opt_beep.h"
 #include "opt_compat_ibcs2.h"
@@ -1621,33 +1621,21 @@ cpu_getmcontext(struct lwp *l, mcontext_
 	mcp->_mc_tlsbase = (uintptr_t)l->l_private;
 	*flags |= _UC_TLSBASE;
 
-	/* Save floating point register context. */
-	pcb = lwp_getpcb(l);
-
 	/*
-	 * If this process is the current FP owner, dump its
-	 * context to the PCB first.
-	 */
-	fpusave_lwp(l, true);
-	if (i386_use_fxsave) {
-		__CTASSERT(sizeof pcb->pcb_savefpu.sv_xmm ==
-		    sizeof mcp->__fpregs.__fp_reg_set.__fp_xmm_state);
-		memcpy(&mcp->__fpregs.__fp_reg_set.__fp_xmm_state,
-		    &pcb->pcb_savefpu.sv_xmm,
-		    sizeof (mcp->__fpregs.__fp_reg_set.__fp_xmm_state));
-		*flags |= _UC_FXSAVE;
-	} else {
-		__CTASSERT(sizeof pcb->pcb_savefpu.sv_87 ==
-		    sizeof mcp->__fpregs.__fp_reg_set.__fpchip_state);
-		memcpy(&mcp->__fpregs.__fp_reg_set.__fpchip_state,
-		    &pcb->pcb_savefpu.sv_87,
-		    sizeof (mcp->__fpregs.__fp_reg_set.__fpchip_state));
-	}
-#if 0
-	/* Apparently nothing ever touches this. */
-	ucp->mcp.mc_fp.fp_emcsts = pcb->pcb_saveemc;
-#endif
-	*flags |= _UC_FPU;
+	 * Save floating point register context.
+	 *
+	 * If the cpu doesn't support fxsave we must still write to
+	 * the entire 512 byte area - otherwise we leak kernel memory
+	 * contents to userspace.
+	 * It wouldn't matter if we were doing the copyout here.
+	 * So we might as well convert to fxsave format.
+	 */
+	__CTASSERT(sizeof pcb->pcb_savefpu.sv_xmm ==
+	    sizeof mcp->__fpregs.__fp_reg_set.__fp_xmm_state);
+	process_read_fpregs_xmm(l, (struct fxsave *)
+	    &mcp->__fpregs.__fp_reg_set.__fp_xmm_state);
+	memset(&mcp->__fpregs.__fp_pad, 0, sizeof mcp->__fpregs.__fp_pad);
+	*flags |= _UC_FXSAVE | _UC_FPU;
 }
 
 int
@@ -1730,28 +1718,12 @@ cpu_setmcontext(struct lwp *l, const mco
 		__CTASSERT(sizeof pcb->pcb_savefpu.sv_87 ==
 		    sizeof mcp->__fpregs.__fp_reg_set.__fpchip_state);
 
-		fpusave_lwp(l, false);
 		if (flags & _UC_FXSAVE) {
-			if (i386_use_fxsave) {
-				memcpy(&pcb->pcb_savefpu.sv_xmm,
-				    &mcp->__fpregs.__fp_reg_set.__fp_xmm_state,
-				    sizeof (pcb->pcb_savefpu.sv_xmm));
-			} else {
-				/* This is a weird corner case */
-				process_xmm_to_s87((const struct fxsave *)
-				    &mcp->__fpregs.__fp_reg_set.__fp_xmm_state,
-				    &pcb->pcb_savefpu.sv_87);
-			}
+			process_write_fpregs_xmm(l, (const struct fxsave *)
+				    &mcp->__fpregs.__fp_reg_set.__fp_xmm_state);
 		} else {
-			if (i386_use_fxsave) {
-				process_s87_to_xmm((const struct save87 *)
-				    &mcp->__fpregs.__fp_reg_set.__fpchip_state,
-				    &pcb->pcb_savefpu.sv_xmm);
-			} else {
-				memcpy(&pcb->pcb_savefpu.sv_87,
-				    &mcp->__fpregs.__fp_reg_set.__fpchip_state,
-				    sizeof (pcb->pcb_savefpu.sv_87));
-			}
+			process_write_fpregs_s87(l, (const struct save87 *)
+				    &mcp->__fpregs.__fp_reg_set.__fpchip_state);
 		}
 	}
 

Index: src/sys/arch/i386/i386/process_machdep.c
diff -u src/sys/arch/i386/i386/process_machdep.c:1.83 src/sys/arch/i386/i386/process_machdep.c:1.84
--- src/sys/arch/i386/i386/process_machdep.c:1.83	Sat Feb 15 10:11:15 2014
+++ src/sys/arch/i386/i386/process_machdep.c	Sat Feb 15 22:20:41 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: process_machdep.c,v 1.83 2014/02/15 10:11:15 dsl Exp $	*/
+/*	$NetBSD: process_machdep.c,v 1.84 2014/02/15 22:20:41 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -52,7 +52,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.83 2014/02/15 10:11:15 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.84 2014/02/15 22:20:41 dsl Exp $");
 
 #include "opt_vm86.h"
 #include "opt_ptrace.h"
@@ -82,14 +82,6 @@ process_frame(struct lwp *l)
 	return (l->l_md.md_regs);
 }
 
-static inline union savefpu *
-process_fpframe(struct lwp *l)
-{
-	struct pcb *pcb = lwp_getpcb(l);
-
-	return &pcb->pcb_savefpu;
-}
-
 int
 process_read_regs(struct lwp *l, struct reg *regs)
 {
@@ -129,16 +121,10 @@ process_read_regs(struct lwp *l, struct 
 int
 process_read_fpregs(struct lwp *l, struct fpreg *regs, size_t *sz)
 {
-	union savefpu *frame = process_fpframe(l);
-
-	fpusave_lwp(l, true);
 
 	__CTASSERT(sizeof *regs == sizeof (struct save87));
-	if (i386_use_fxsave) {
-		process_xmm_to_s87(&frame->sv_xmm, (struct save87 *)regs);
-	} else
-		memcpy(regs, &frame->sv_87, sizeof(*regs));
-	return (0);
+	process_read_fpregs_s87(l, (struct save87 *)regs);
+	return 0;
 }
 
 #ifdef PTRACE
@@ -200,17 +186,13 @@ process_write_regs(struct lwp *l, const 
 int
 process_write_fpregs(struct lwp *l, const struct fpreg *regs, size_t sz)
 {
-	union savefpu *frame = process_fpframe(l);
 
-	fpusave_lwp(l, false);
-
-	if (i386_use_fxsave) {
-		process_s87_to_xmm((const struct save87 *)regs, &frame->sv_xmm);
-	} else
-		memcpy(&frame->sv_87, regs, sizeof(*regs));
-	return (0);
+	__CTASSERT(sizeof *regs == sizeof (struct save87));
+	process_write_fpregs_s87(l, (const struct save87 *)regs);
+	return 0;
 }
 
+
 int
 process_sstep(struct lwp *l, int sstep)
 {
@@ -239,26 +221,18 @@ static int
 process_machdep_read_xmmregs(struct lwp *l, struct xmmregs *regs)
 {
 
-	if (i386_use_fxsave == 0)
-		return (EINVAL);
-
-	fpusave_lwp(l, true);
-
-	memcpy(regs, &process_fpframe(l)->sv_xmm, sizeof(*regs));
-	return (0);
+	__CTASSERT(sizeof *regs == sizeof (struct fxsave));
+	process_read_fpregs_xmm(l, (struct fxsave *)regs);
+	return 0;
 }
 
 static int
 process_machdep_write_xmmregs(struct lwp *l, struct xmmregs *regs)
 {
 
-	if (i386_use_fxsave == 0)
-		return (EINVAL);
-
-	fpusave_lwp(l, false);
-
-	memcpy(&process_fpframe(l)->sv_xmm, regs, sizeof(*regs));
-	return (0);
+	__CTASSERT(sizeof *regs == sizeof (struct fxsave));
+	process_write_fpregs_xmm(l, (const struct fxsave *)regs);
+	return 0;
 }
 
 int

Index: src/sys/arch/i386/include/mcontext.h
diff -u src/sys/arch/i386/include/mcontext.h:1.11 src/sys/arch/i386/include/mcontext.h:1.12
--- src/sys/arch/i386/include/mcontext.h:1.11	Tue Feb  4 22:21:35 2014
+++ src/sys/arch/i386/include/mcontext.h	Sat Feb 15 22:20:42 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: mcontext.h,v 1.11 2014/02/04 22:21:35 dsl Exp $	*/
+/*	$NetBSD: mcontext.h,v 1.12 2014/02/15 22:20:42 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -86,7 +86,7 @@ typedef struct {
 		} __fp_xmm_state;	/* x87 and xmm regs in fxsave format */
 		int	__fp_fpregs[128];
 	} __fp_reg_set;
-	long	__fp_pad[33];			/* Historic padding */
+	int 	__fp_pad[33];			/* Historic padding */
 } __fpregset_t;
 __CTASSERT(sizeof (__fpregset_t) == 512 + 33 * 4);
 

Index: src/sys/arch/x86/include/fpu.h
diff -u src/sys/arch/x86/include/fpu.h:1.3 src/sys/arch/x86/include/fpu.h:1.4
--- src/sys/arch/x86/include/fpu.h:1.3	Sat Feb 15 10:11:15 2014
+++ src/sys/arch/x86/include/fpu.h	Sat Feb 15 22:20:42 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu.h,v 1.3 2014/02/15 10:11:15 dsl Exp $	*/
+/*	$NetBSD: fpu.h,v 1.4 2014/02/15 22:20:42 dsl Exp $	*/
 
 #ifndef	_X86_FPU_H_
 #define	_X86_FPU_H_
@@ -26,6 +26,14 @@ void fpu_save_area_clear(struct lwp *, u
 /* Reset control words only - for signal handlers */
 void fpu_save_area_reset(struct lwp *);
 
+/* Load FP registers with user-supplied values */
+void process_write_fpregs_xmm(struct lwp *lwp, const struct fxsave *fpregs);
+void process_write_fpregs_s87(struct lwp *lwp, const struct save87 *fpregs);
+
+/* Save FP registers for copy to userspace */
+void process_read_fpregs_xmm(struct lwp *lwp, struct fxsave *fpregs);
+void process_read_fpregs_s87(struct lwp *lwp, struct save87 *fpregs);
+
 #endif
 
 #endif /* _X86_FPU_H_ */

Index: src/sys/arch/x86/x86/convert_xmm_s87.c
diff -u src/sys/arch/x86/x86/convert_xmm_s87.c:1.2 src/sys/arch/x86/x86/convert_xmm_s87.c:1.3
--- src/sys/arch/x86/x86/convert_xmm_s87.c:1.2	Wed Feb 12 23:24:09 2014
+++ src/sys/arch/x86/x86/convert_xmm_s87.c	Sat Feb 15 22:20:42 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: convert_xmm_s87.c,v 1.2 2014/02/12 23:24:09 dsl Exp $	*/
+/*	$NetBSD: convert_xmm_s87.c,v 1.3 2014/02/15 22:20:42 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: convert_xmm_s87.c,v 1.2 2014/02/12 23:24:09 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: convert_xmm_s87.c,v 1.3 2014/02/15 22:20:42 dsl Exp $");
 
 
 #include <sys/param.h>
@@ -131,10 +131,11 @@ process_s87_to_xmm(const struct save87 *
 	sxmm->fx_dp = s87->s87_dp;
 
 	/* Tag word */
-	tag = s87->s87_tw & 0xffff;	/* 0b11 => unused */
+	tag = s87->s87_tw;	/* 0b11 => unused */
 	if (tag == 0xffff) {
-		/* All unused - values don't matter */
+		/* All unused - values don't matter, zero for safety */
 		sxmm->fx_tw = 0;
+		memset(&sxmm->fx_87_ac, 0, sizeof sxmm->fx_87_ac);
 		return;
 	}
 

Index: src/sys/arch/x86/x86/fpu.c
diff -u src/sys/arch/x86/x86/fpu.c:1.5 src/sys/arch/x86/x86/fpu.c:1.6
--- src/sys/arch/x86/x86/fpu.c:1.5	Sat Feb 15 10:11:15 2014
+++ src/sys/arch/x86/x86/fpu.c	Sat Feb 15 22:20:42 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu.c,v 1.5 2014/02/15 10:11:15 dsl Exp $	*/
+/*	$NetBSD: fpu.c,v 1.6 2014/02/15 22:20:42 dsl Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.  All
@@ -100,7 +100,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.5 2014/02/15 10:11:15 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.6 2014/02/15 22:20:42 dsl Exp $");
 
 #include "opt_multiprocessor.h"
 
@@ -129,6 +129,14 @@ __KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.5 
 #define stts() HYPERVISOR_fpu_taskswitch(1)
 #endif
 
+static inline union savefpu *
+process_fpframe(struct lwp *lwp)
+{
+	struct pcb *pcb = lwp_getpcb(lwp);
+
+	return &pcb->pcb_savefpu;
+}
+
 /*
  * We do lazy initialization and switching using the TS bit in cr0 and the
  * MDL_USEDFPU bit in mdlwp.
@@ -542,13 +550,11 @@ fpusave_lwp(struct lwp *l, bool save)
 void
 fpu_save_area_clear(struct lwp *lwp, unsigned int x87_cw)
 {
-	struct pcb *pcb;
 	union savefpu *fpu_save;
 
 	fpusave_lwp(lwp, false);
 
-	pcb = lwp_getpcb(lwp);
-	fpu_save = &pcb->pcb_savefpu;
+	fpu_save = process_fpframe(lwp);
 
 	if (i386_use_fxsave) {
 		memset(&fpu_save->sv_xmm, 0, sizeof fpu_save->sv_xmm);
@@ -567,8 +573,7 @@ fpu_save_area_clear(struct lwp *lwp, uns
 void
 fpu_save_area_reset(struct lwp *lwp)
 {
-	struct pcb *pcb = lwp_getpcb(lwp);
-	union savefpu *fpu_save = &pcb->pcb_savefpu;
+	union savefpu *fpu_save = process_fpframe(lwp);
 
 	if (i386_use_fxsave) {
 		fpu_save->sv_xmm.fx_mxcsr = __INITIAL_MXCSR__;
@@ -580,3 +585,74 @@ fpu_save_area_reset(struct lwp *lwp)
 		fpu_save->sv_87.s87_cw = fpu_save->sv_os.fxo_dflt_cw;
 	}
 }
+
+/*
+ * Write the FP registers.
+ * Buffer has usually come from userspace so should not be trusted.
+ */
+void
+process_write_fpregs_xmm(struct lwp *lwp, const struct fxsave *fpregs)
+{
+	union savefpu *fpu_save;
+
+	fpusave_lwp(lwp, false);
+	fpu_save = process_fpframe(lwp);
+
+	if (i386_use_fxsave) {
+		memcpy(&fpu_save->sv_xmm, fpregs,
+		    sizeof fpu_save->sv_xmm);
+		/* Invalid bits in the mxcsr_mask will cause faults */
+		fpu_save->sv_xmm.fx_mxcsr_mask &= __INITIAL_MXCSR_MASK__;
+	} else {
+		process_xmm_to_s87(fpregs, &fpu_save->sv_87);
+	}
+}
+
+/* We need to use x87 format for 32bit ptrace */
+void
+process_write_fpregs_s87(struct lwp *lwp, const struct save87 *fpregs)
+{
+
+	if (i386_use_fxsave) {
+		/* Save so we don't lose the xmm registers */
+		fpusave_lwp(lwp, true);
+		process_s87_to_xmm(fpregs, &process_fpframe(lwp)->sv_xmm);
+	} else {
+		fpusave_lwp(lwp, false);
+		memcpy(&process_fpframe(lwp)->sv_87, fpregs,
+		    sizeof process_fpframe(lwp)->sv_87);
+	}
+}
+
+/*
+ * Read fpu registers, the buffer is usually copied out to userspace.
+ * Ensure we write to the entire structure.
+ */
+void
+process_read_fpregs_xmm(struct lwp *lwp, struct fxsave *fpregs)
+{
+	fpusave_lwp(lwp, true);
+	if (i386_use_fxsave) {
+		memcpy(fpregs, &process_fpframe(lwp)->sv_xmm,
+		    sizeof process_fpframe(lwp)->sv_xmm);
+	} else {
+		/* This usually gets copied to userspace */
+		memset(fpregs, 0, sizeof *fpregs);
+		process_s87_to_xmm(&process_fpframe(lwp)->sv_87, fpregs);
+
+	}
+}
+
+void
+process_read_fpregs_s87(struct lwp *lwp, struct save87 *fpregs)
+{
+	fpusave_lwp(lwp, true);
+
+	if (i386_use_fxsave) {
+		memset(fpregs, 0, 12);
+		process_xmm_to_s87(&process_fpframe(lwp)->sv_xmm, fpregs);
+	} else {
+		memcpy(fpregs, &process_fpframe(lwp)->sv_87,
+		    sizeof process_fpframe(lwp)->sv_87);
+	}
+}

Reply via email to