summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordsl <dsl@NetBSD.org>2014-02-15 22:20:41 +0000
committerdsl <dsl@NetBSD.org>2014-02-15 22:20:41 +0000
commit7cf3d973bd0b7e7f4e55e85fff42e9cf6a793943 (patch)
treed488b402c443d70da8f4f282bcd75e5bd36ef18a
parentc41afb7d27c2754499fec13bbf805298b8c9007c (diff)
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.
-rw-r--r--sys/arch/amd64/amd64/machdep.c20
-rw-r--r--sys/arch/amd64/amd64/netbsd32_machdep.c25
-rw-r--r--sys/arch/amd64/amd64/process_machdep.c24
-rw-r--r--sys/arch/amd64/include/mcontext.h12
-rw-r--r--sys/arch/i386/i386/machdep.c66
-rw-r--r--sys/arch/i386/i386/process_machdep.c54
-rw-r--r--sys/arch/i386/include/mcontext.h4
-rw-r--r--sys/arch/x86/include/fpu.h10
-rw-r--r--sys/arch/x86/x86/convert_xmm_s87.c9
-rw-r--r--sys/arch/x86/x86/fpu.c90
10 files changed, 158 insertions, 156 deletions
diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index 42ba4a7aae2..801692f331f 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -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_t *mcp, unsigned int *flags)
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 mcontext_t *mcp, unsigned int flags)
{
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 mcontext_t *mcp, unsigned int flags)
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);
diff --git a/sys/arch/amd64/amd64/netbsd32_machdep.c b/sys/arch/amd64/amd64/netbsd32_machdep.c
index f11d26bf98f..c5a466ba668 100644
--- a/sys/arch/amd64/amd64/netbsd32_machdep.c
+++ b/sys/arch/amd64/amd64/netbsd32_machdep.c
@@ -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 mcontext32_t *mcp, unsigned int flags)
/* 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, mcontext32_t *mcp, unsigned int *flags)
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, mcontext32_t *mcp, unsigned int *flags)
*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
diff --git a/sys/arch/amd64/amd64/process_machdep.c b/sys/arch/amd64/amd64/process_machdep.c
index 561439dd52d..b84abac4ce6 100644
--- a/sys/arch/amd64/amd64/process_machdep.c
+++ b/sys/arch/amd64/amd64/process_machdep.c
@@ -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_machdep.c,v 1.28 2014/02/15 10:11:14 dsl Exp
#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
diff --git a/sys/arch/amd64/include/mcontext.h b/sys/arch/amd64/include/mcontext.h
index e58ebf60523..113f4a67b91 100644
--- a/sys/arch/amd64/include/mcontext.h
+++ b/sys/arch/amd64/include/mcontext.h
@@ -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
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index 155bca0132d..7e72a3d812a 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -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_t *mcp, unsigned int *flags)
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.
+ * 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.
*/
- 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;
+ __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 mcontext_t *mcp, unsigned int flags)
__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);
}
}
diff --git a/sys/arch/i386/i386/process_machdep.c b/sys/arch/i386/i386/process_machdep.c
index 3e276ee705a..8d311dea224 100644
--- a/sys/arch/i386/i386/process_machdep.c
+++ b/sys/arch/i386/i386/process_machdep.c
@@ -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 reg *regs)
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 struct reg *regs)
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
diff --git a/sys/arch/i386/include/mcontext.h b/sys/arch/i386/include/mcontext.h
index 4a7e01ea079..3056c9949d8 100644
--- a/sys/arch/i386/include/mcontext.h
+++ b/sys/arch/i386/include/mcontext.h
@@ -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);
diff --git a/sys/arch/x86/include/fpu.h b/sys/arch/x86/include/fpu.h
index c1345fde38c..9c94e530ecb 100644
--- a/sys/arch/x86/include/fpu.h
+++ b/sys/arch/x86/include/fpu.h
@@ -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 *, unsigned int);
/* 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_ */
diff --git a/sys/arch/x86/x86/convert_xmm_s87.c b/sys/arch/x86/x86/convert_xmm_s87.c
index 94825fa13d8..53116545769 100644
--- a/sys/arch/x86/x86/convert_xmm_s87.c
+++ b/sys/arch/x86/x86/convert_xmm_s87.c
@@ -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 *s87, struct fxsave *sxmm)
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;
}
diff --git a/sys/arch/x86/x86/fpu.c b/sys/arch/x86/x86/fpu.c
index 198a04a3cc8..0b90543385c 100644
--- a/sys/arch/x86/x86/fpu.c
+++ b/sys/arch/x86/x86/fpu.c
@@ -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 2014/02/15 10:11:15 dsl Exp $");
#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, unsigned int x87_cw)
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);
+ }
+}