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, ®s->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), ®s->fxstate, sizeof(*regs)); - return (0); + process_write_fpregs_xmm(l, ®s->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); + } +}