Module Name: src Committed By: dsl Date: Fri Feb 7 22:40:22 UTC 2014
Modified Files: src/sys/arch/amd64/amd64: fpu.c machdep.c netbsd32_machdep.c process_machdep.c src/sys/arch/amd64/conf: files.amd64 src/sys/arch/amd64/include: fpu.h netbsd32_machdep.h pcb.h reg.h src/sys/arch/i386/conf: files.i386 src/sys/arch/i386/i386: process_machdep.c src/sys/arch/i386/include: npx.h src/sys/arch/x86/include: cpu_extended_state.h src/sys/arch/xen/conf: files.xen src/sys/compat/linux/arch/amd64: linux_machdep.c linux_machdep.h src/sys/compat/linux32/arch/amd64: linux32_machdep.c Added Files: src/sys/arch/x86/x86: convert_xmm_s87.c Log Message: Convert the amd64 build to use x86/cpu_extended_state.h so that the fpu definitions match those of i386. Mostly just structure and field renames, in addition: 1) process_xmm_to_s87() and process_s87_to_xmm() moved into x86/convert_xmm_s87.c so they can be used by amd64's netbsd32 code. 2) The linux signal code simplified to use a structure copy for ths fxsave data - it matches the hardware definition and won't change. To generate a diff of this commit: cvs rdiff -u -r1.45 -r1.46 src/sys/arch/amd64/amd64/fpu.c cvs rdiff -u -r1.201 -r1.202 src/sys/arch/amd64/amd64/machdep.c cvs rdiff -u -r1.88 -r1.89 src/sys/arch/amd64/amd64/netbsd32_machdep.c cvs rdiff -u -r1.25 -r1.26 src/sys/arch/amd64/amd64/process_machdep.c cvs rdiff -u -r1.80 -r1.81 src/sys/arch/amd64/conf/files.amd64 cvs rdiff -u -r1.11 -r1.12 src/sys/arch/amd64/include/fpu.h cvs rdiff -u -r1.18 -r1.19 src/sys/arch/amd64/include/netbsd32_machdep.h cvs rdiff -u -r1.22 -r1.23 src/sys/arch/amd64/include/pcb.h cvs rdiff -u -r1.7 -r1.8 src/sys/arch/amd64/include/reg.h cvs rdiff -u -r1.372 -r1.373 src/sys/arch/i386/conf/files.i386 cvs rdiff -u -r1.81 -r1.82 src/sys/arch/i386/i386/process_machdep.c cvs rdiff -u -r1.34 -r1.35 src/sys/arch/i386/include/npx.h cvs rdiff -u -r1.1 -r1.2 src/sys/arch/x86/include/cpu_extended_state.h cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/x86/convert_xmm_s87.c cvs rdiff -u -r1.130 -r1.131 src/sys/arch/xen/conf/files.xen cvs rdiff -u -r1.44 -r1.45 src/sys/compat/linux/arch/amd64/linux_machdep.c cvs rdiff -u -r1.13 -r1.14 src/sys/compat/linux/arch/amd64/linux_machdep.h cvs rdiff -u -r1.33 -r1.34 \ src/sys/compat/linux32/arch/amd64/linux32_machdep.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/fpu.c diff -u src/sys/arch/amd64/amd64/fpu.c:1.45 src/sys/arch/amd64/amd64/fpu.c:1.46 --- src/sys/arch/amd64/amd64/fpu.c:1.45 Tue Feb 4 21:09:23 2014 +++ src/sys/arch/amd64/amd64/fpu.c Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: fpu.c,v 1.45 2014/02/04 21:09:23 dsl Exp $ */ +/* $NetBSD: fpu.c,v 1.46 2014/02/07 22:40:22 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.45 2014/02/04 21:09:23 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.46 2014/02/07 22:40:22 dsl Exp $"); #include "opt_multiprocessor.h" @@ -179,7 +179,7 @@ fputrap(struct trapframe *frame) { struct lwp *l = curlwp; struct pcb *pcb = lwp_getpcb(l); - struct savefpu *sfp = &pcb->pcb_savefpu; + union savefpu *sfp = &pcb->pcb_savefpu; uint32_t mxcsr, statbits; ksiginfo_t ksi; @@ -194,7 +194,7 @@ fputrap(struct trapframe *frame) fxsave(sfp); if (frame->tf_trapno == T_XMM) { - mxcsr = sfp->fp_fxsave.fx_mxcsr; + mxcsr = sfp->sv_xmm.fx_mxcsr; statbits = mxcsr; mxcsr &= ~0x3f; x86_ldmxcsr(&mxcsr); @@ -203,10 +203,10 @@ fputrap(struct trapframe *frame) fninit(); fwait(); - cw = sfp->fp_fxsave.fx_fcw; + cw = sfp->sv_xmm.fx_cw; fldcw(&cw); fwait(); - statbits = sfp->fp_fxsave.fx_fsw; + statbits = sfp->sv_xmm.fx_sw; } KPREEMPT_ENABLE(l); @@ -300,9 +300,9 @@ fpudna(struct cpu_info *ci) pcb->pcb_fpcpu = ci; if ((l->l_md.md_flags & MDL_USEDFPU) == 0) { fninit(); - cw = pcb->pcb_savefpu.fp_fxsave.fx_fcw; + cw = pcb->pcb_savefpu.sv_xmm.fx_cw; fldcw(&cw); - mxcsr = pcb->pcb_savefpu.fp_fxsave.fx_mxcsr; + mxcsr = pcb->pcb_savefpu.sv_xmm.fx_mxcsr; x86_ldmxcsr(&mxcsr); l->l_md.md_flags |= MDL_USEDFPU; } else { Index: src/sys/arch/amd64/amd64/machdep.c diff -u src/sys/arch/amd64/amd64/machdep.c:1.201 src/sys/arch/amd64/amd64/machdep.c:1.202 --- src/sys/arch/amd64/amd64/machdep.c:1.201 Thu Jan 9 00:57:25 2014 +++ src/sys/arch/amd64/amd64/machdep.c Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.201 2014/01/09 00:57:25 dholland Exp $ */ +/* $NetBSD: machdep.c,v 1.202 2014/02/07 22:40:22 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.201 2014/01/09 00:57:25 dholland Exp $"); +__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.202 2014/02/07 22:40:22 dsl Exp $"); /* #define XENDEBUG_LOW */ @@ -1341,11 +1341,11 @@ setregs(struct lwp *l, struct exec_packa l->l_md.md_flags &= ~MDL_USEDFPU; pcb->pcb_flags = 0; if (pack->ep_osversion >= 699002600) - pcb->pcb_savefpu.fp_fxsave.fx_fcw = __NetBSD_NPXCW__; + pcb->pcb_savefpu.sv_xmm.fx_cw = __NetBSD_NPXCW__; else - pcb->pcb_savefpu.fp_fxsave.fx_fcw = __NetBSD_COMPAT_NPXCW__; - pcb->pcb_savefpu.fp_fxsave.fx_mxcsr = __INITIAL_MXCSR__; - pcb->pcb_savefpu.fp_fxsave.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__; + pcb->pcb_savefpu.sv_xmm.fx_cw = __NetBSD_COMPAT_NPXCW__; + pcb->pcb_savefpu.sv_xmm.fx_mxcsr = __INITIAL_MXCSR__; + pcb->pcb_savefpu.sv_xmm.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__; l->l_proc->p_flag &= ~PK_32; @@ -1939,7 +1939,7 @@ cpu_getmcontext(struct lwp *l, mcontext_ if (pcb->pcb_fpcpu) { fpusave_lwp(l, true); } - memcpy(mcp->__fpregs, &pcb->pcb_savefpu.fp_fxsave, + memcpy(mcp->__fpregs, &pcb->pcb_savefpu.sv_xmm, sizeof (mcp->__fpregs)); *flags |= _UC_FPU; } @@ -1995,7 +1995,7 @@ cpu_setmcontext(struct lwp *l, const mco fpusave_lwp(l, false); if ((flags & _UC_FPU) != 0) { - memcpy(&pcb->pcb_savefpu.fp_fxsave, mcp->__fpregs, + memcpy(&pcb->pcb_savefpu.sv_xmm, mcp->__fpregs, sizeof (mcp->__fpregs)); l->l_md.md_flags |= MDL_USEDFPU; } Index: src/sys/arch/amd64/amd64/netbsd32_machdep.c diff -u src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.88 src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.89 --- src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.88 Sat Jan 25 05:09:59 2014 +++ src/sys/arch/amd64/amd64/netbsd32_machdep.c Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: netbsd32_machdep.c,v 1.88 2014/01/25 05:09:59 christos Exp $ */ +/* $NetBSD: netbsd32_machdep.c,v 1.89 2014/02/07 22:40:22 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.88 2014/01/25 05:09:59 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.89 2014/02/07 22:40:22 dsl Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" @@ -143,11 +143,11 @@ netbsd32_setregs(struct lwp *l, struct e l->l_md.md_flags |= MDL_COMPAT32; /* Force iret not sysret */ pcb->pcb_flags = PCB_COMPAT32; if (pack->ep_osversion >= 699002600) - pcb->pcb_savefpu.fp_fxsave.fx_fcw = __NetBSD_NPXCW__; + pcb->pcb_savefpu.sv_xmm.fx_cw = __NetBSD_NPXCW__; else - pcb->pcb_savefpu.fp_fxsave.fx_fcw = __NetBSD_COMPAT_NPXCW__; - pcb->pcb_savefpu.fp_fxsave.fx_mxcsr = __INITIAL_MXCSR__; - pcb->pcb_savefpu.fp_fxsave.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__; + pcb->pcb_savefpu.sv_xmm.fx_cw = __NetBSD_COMPAT_NPXCW__; + pcb->pcb_savefpu.sv_xmm.fx_mxcsr = __INITIAL_MXCSR__; + pcb->pcb_savefpu.sv_xmm.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__; p->p_flag |= PK_32; @@ -530,68 +530,12 @@ netbsd32_process_read_regs(struct lwp *l return (0); } -/* - * XXX-cube (20060311): This doesn't seem to work fine. - */ -static int -xmm_to_s87_tag(const uint8_t *fpac, int regno, uint8_t tw) -{ - static const uint8_t empty_significand[8] = { 0 }; - int tag; - uint16_t exponent; - - if (tw & (1U << regno)) { - exponent = fpac[8] | (fpac[9] << 8); - switch (exponent) { - case 0x7fff: - tag = 2; - break; - - case 0x0000: - if (memcmp(empty_significand, fpac, - sizeof(empty_significand)) == 0) - tag = 1; - else - tag = 2; - break; - - default: - if ((fpac[7] & 0x80) == 0) - tag = 2; - else - tag = 0; - break; - } - } else - tag = 3; - - return (tag); -} - int netbsd32_process_read_fpregs(struct lwp *l, struct fpreg32 *regs, size_t *sz) { struct fpreg regs64; - struct save87 *s87 = (struct save87 *)regs; + int error; size_t fp_size; - int error, i; - - union fp_addr { - uint64_t fa_64; /* Linear address for 64bit systems */ - struct { - uint32_t fa_off; /* Linear address for 32 bit */ - uint16_t fa_seg; /* Code/data (etc) segment */ - uint16_t fa_pad; - } fa_32; - } fa; - - /* - * NOTE: This 'struct fpreg32' is just char[108] and is shorter - * than 'struct save87'. - * If we write to the extra fields we trash the stack when writing - * process coredumps (see coredump_note() in core_elf32.c). - * This code must not set sv_env.en_tw or s87->sv_ex_sw. - */ /* * All that stuff makes no sense in i386 code :( @@ -601,26 +545,8 @@ netbsd32_process_read_fpregs(struct lwp error = process_read_fpregs(l, ®s64, &fp_size); if (error) return error; - - s87->sv_env.en_cw = regs64.fxstate.fx_fcw; - s87->sv_env.en_sw = regs64.fxstate.fx_fsw; - fa.fa_64 = regs64.fxstate.fx_rip; - s87->sv_env.en_fip = fa.fa_32.fa_off; - s87->sv_env.en_fcs = fa.fa_32.fa_seg; - s87->sv_env.en_opcode = regs64.fxstate.fx_fop; - fa.fa_64 = regs64.fxstate.fx_rdp; - s87->sv_env.en_foo = fa.fa_32.fa_off; - s87->sv_env.en_fos = fa.fa_32.fa_seg; - - s87->sv_env.en_tw = 0; - for (i = 0; i < 8; i++) { - s87->sv_env.en_tw |= - (xmm_to_s87_tag((uint8_t *)®s64.fxstate.fx_st[i][0], i, - regs64.fxstate.fx_ftw) << (i * 2)); - - memcpy(&s87->sv_ac[i].fp_bytes, ®s64.fxstate.fx_st[i][0], - sizeof(s87->sv_ac[i].fp_bytes)); - } + __CTASSERT(sizeof *regs == sizeof (struct save87)); + process_xmm_to_s87(®s64.fxstate, (struct save87 *)regs); return (0); } @@ -897,8 +823,8 @@ cpu_setmcontext32(struct lwp *l, const m if (pcb->pcb_fpcpu != NULL) { fpusave_lwp(l, false); } - memcpy(&pcb->pcb_savefpu.fp_fxsave, &mcp->__fpregs, - sizeof (pcb->pcb_savefpu.fp_fxsave)); + memcpy(&pcb->pcb_savefpu.sv_xmm, &mcp->__fpregs, + sizeof (pcb->pcb_savefpu.sv_xmm)); /* If not set already. */ l->l_md.md_flags |= MDL_USEDFPU; } @@ -957,8 +883,8 @@ cpu_getmcontext32(struct lwp *l, mcontex if (pcb->pcb_fpcpu) { fpusave_lwp(l, true); } - memcpy(&mcp->__fpregs, &pcb->pcb_savefpu.fp_fxsave, - sizeof (pcb->pcb_savefpu.fp_fxsave)); + memcpy(&mcp->__fpregs, &pcb->pcb_savefpu.sv_xmm, + sizeof (pcb->pcb_savefpu.sv_xmm)); *flags |= _UC_FPU; } } Index: src/sys/arch/amd64/amd64/process_machdep.c diff -u src/sys/arch/amd64/amd64/process_machdep.c:1.25 src/sys/arch/amd64/amd64/process_machdep.c:1.26 --- src/sys/arch/amd64/amd64/process_machdep.c:1.25 Sat Jan 4 00:10:02 2014 +++ src/sys/arch/amd64/amd64/process_machdep.c Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: process_machdep.c,v 1.25 2014/01/04 00:10:02 dsl Exp $ */ +/* $NetBSD: process_machdep.c,v 1.26 2014/02/07 22:40:22 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.25 2014/01/04 00:10:02 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.26 2014/02/07 22:40:22 dsl Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -69,7 +69,7 @@ __KERNEL_RCSID(0, "$NetBSD: process_mach #include <machine/fpu.h> static inline struct trapframe *process_frame(struct lwp *); -static inline struct fxsave64 *process_fpframe(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,12 +82,12 @@ process_frame(struct lwp *l) return (l->l_md.md_regs); } -static inline struct fxsave64 * +static inline struct fxsave * process_fpframe(struct lwp *l) { struct pcb *pcb = lwp_getpcb(l); - return &pcb->pcb_savefpu.fp_fxsave; + return &pcb->pcb_savefpu.sv_xmm; } int @@ -105,7 +105,7 @@ process_read_regs(struct lwp *l, struct int process_read_fpregs(struct lwp *l, struct fpreg *regs,size_t *sz) { - struct fxsave64 *frame = process_fpframe(l); + struct fxsave *frame = process_fpframe(l); if (l->l_md.md_flags & MDL_USEDFPU) { fpusave_lwp(l, true); @@ -118,13 +118,13 @@ process_read_fpregs(struct lwp *l, struc * The initial control word was already set by setregs(), so * save it temporarily. */ - cw = frame->fx_fcw; + cw = frame->fx_cw; mxcsr = frame->fx_mxcsr; mxcsr_mask = frame->fx_mxcsr_mask; memset(frame, 0, sizeof(*regs)); - frame->fx_fcw = cw; - frame->fx_fsw = 0x0000; - frame->fx_ftw = 0x00; /* abridged tag; all empty */ + frame->fx_cw = cw; + frame->fx_sw = 0x0000; + frame->fx_tw = 0x00; /* abridged tag; all empty */ frame->fx_mxcsr = mxcsr; frame->fx_mxcsr_mask = mxcsr_mask; l->l_md.md_flags |= MDL_USEDFPU; @@ -160,7 +160,7 @@ process_write_regs(struct lwp *l, const int process_write_fpregs(struct lwp *l, const struct fpreg *regs, size_t sz) { - struct fxsave64 *frame = process_fpframe(l); + struct fxsave *frame = process_fpframe(l); if (l->l_md.md_flags & MDL_USEDFPU) { fpusave_lwp(l, false); Index: src/sys/arch/amd64/conf/files.amd64 diff -u src/sys/arch/amd64/conf/files.amd64:1.80 src/sys/arch/amd64/conf/files.amd64:1.81 --- src/sys/arch/amd64/conf/files.amd64:1.80 Wed Jul 17 21:26:28 2013 +++ src/sys/arch/amd64/conf/files.amd64 Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -# $NetBSD: files.amd64,v 1.80 2013/07/17 21:26:28 soren Exp $ +# $NetBSD: files.amd64,v 1.81 2014/02/07 22:40:22 dsl Exp $ # # new style config file for amd64 architecture # @@ -133,6 +133,7 @@ attach fd at fdc # NetBSD/i386 32-bit binary compatibility (COMPAT_NETBSD32) include "compat/netbsd32/files.netbsd32" file arch/amd64/amd64/netbsd32_machdep.c compat_netbsd32 +file arch/x86/x86/convert_xmm_s87.c compat_netbsd32 file arch/amd64/amd64/netbsd32_sigcode.S compat_netbsd32 & compat_16 file arch/amd64/amd64/netbsd32_syscall.c compat_netbsd32 Index: src/sys/arch/amd64/include/fpu.h diff -u src/sys/arch/amd64/include/fpu.h:1.11 src/sys/arch/amd64/include/fpu.h:1.12 --- src/sys/arch/amd64/include/fpu.h:1.11 Wed Dec 11 22:06:51 2013 +++ src/sys/arch/amd64/include/fpu.h Fri Feb 7 22:40:22 2014 @@ -1,70 +1,9 @@ -/* $NetBSD: fpu.h,v 1.11 2013/12/11 22:06:51 dsl Exp $ */ +/* $NetBSD: fpu.h,v 1.12 2014/02/07 22:40:22 dsl Exp $ */ #ifndef _AMD64_FPU_H_ #define _AMD64_FPU_H_ -/* - * NetBSD/amd64 only uses the extended save/restore format used - * by fxsave/fsrestore, to always deal with the SSE registers, - * which are part of the ABI to pass floating point values. - * - * The memory used for the 'fsave' instruction must be 16 byte aligned, - * but the definition here isn't aligned to avoid padding elsewhere. - */ - -struct fxsave64 { - uint16_t fx_fcw; /* 0: FPU control word */ - uint16_t fx_fsw; /* 2: FPU status word */ - uint8_t fx_ftw; /* 4: Abridged FPU tag word */ - uint8_t fx_reserved1; /* 5: */ - uint16_t fx_fop; /* 6: Low 11 bits are FPU opcode */ - uint64_t fx_rip; /* 8: Address of faulting instruction */ - uint64_t fx_rdp; /* 16: Data address associated with fault */ - uint32_t fx_mxcsr; /* 24: SIMD control & status */ - uint32_t fx_mxcsr_mask; /* 28: */ - uint64_t fx_st[8][2]; /* 32: 8 normal FP regs (80 bit) */ - uint64_t fx_xmm[16][2]; /* 160: 16 SSE2 registers */ - uint8_t fx_reserved2[48]; /* 416: */ - uint8_t fx_available[48]; /* 464: could be used by kernel */ -}; - -__CTASSERT(sizeof (struct fxsave64) == 512); - -struct savefpu { - struct fxsave64 fp_fxsave; /* see above */ -}; - -/* - * The i387 defaults to Intel extended precision mode and round to nearest, - * with all exceptions masked. - */ -#define __INITIAL_NPXCW__ 0x037f -#define __INITIAL_MXCSR__ 0x1f80 -#define __INITIAL_MXCSR_MASK__ 0xffbf - -/* Modern NetBSD uses the default control word.. */ -#define __NetBSD_NPXCW__ 0x037f -/* NetBSD before 6.99.26 forced IEEE double precision. */ -#define __NetBSD_COMPAT_NPXCW__ 0x127f -/* Linux just uses the default control word. */ -#define __Linux_NPXCW__ 0x037f - -/* - * The standard control word from finit is 0x37F, giving: - * round to nearest - * 64-bit precision - * all exceptions masked. - * - * Now we want: - * affine mode (if we decide to support 287's) - * round to nearest - * 53-bit precision - * all exceptions masked. - * - * 64-bit precision often gives bad results with high level languages - * because it makes the results of calculations depend on whether - * intermediate values are stored in memory or in FPU registers. - */ +#include <x86/cpu_extended_state.h> #ifdef _KERNEL /* Index: src/sys/arch/amd64/include/netbsd32_machdep.h diff -u src/sys/arch/amd64/include/netbsd32_machdep.h:1.18 src/sys/arch/amd64/include/netbsd32_machdep.h:1.19 --- src/sys/arch/amd64/include/netbsd32_machdep.h:1.18 Sat Jan 4 00:10:02 2014 +++ src/sys/arch/amd64/include/netbsd32_machdep.h Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: netbsd32_machdep.h,v 1.18 2014/01/04 00:10:02 dsl Exp $ */ +/* $NetBSD: netbsd32_machdep.h,v 1.19 2014/02/07 22:40:22 dsl Exp $ */ #ifndef _MACHINE_NETBSD32_H_ #define _MACHINE_NETBSD32_H_ @@ -133,33 +133,6 @@ struct x86_64_set_mtrr_args32 { uint32_t n; }; -struct env87 { - int32_t en_cw; - int32_t en_sw; - int32_t en_tw; - int32_t en_fip; - uint16_t en_fcs; - uint16_t en_opcode; - int32_t en_foo; - int32_t en_fos; -} __packed; - -struct fpacc87 { - uint8_t fp_bytes[10]; -} __packed; - -struct save87 { - struct env87 sv_env; - struct fpacc87 sv_ac[8]; - /* - * The fields below are not in the 'struct fpreg32' that is - * otherwise the same as this structure (for coredumps). - */ - int32_t sv_ex_sw; - int32_t sv_ex_tw; - uint8_t sv_pad[8 * 2 - 2 * 4]; -} __packed; - #define NETBSD32_MID_MACHINE MID_I386 int netbsd32_process_read_regs(struct lwp *, struct reg32 *); Index: src/sys/arch/amd64/include/pcb.h diff -u src/sys/arch/amd64/include/pcb.h:1.22 src/sys/arch/amd64/include/pcb.h:1.23 --- src/sys/arch/amd64/include/pcb.h:1.22 Sun Jan 19 10:30:19 2014 +++ src/sys/arch/amd64/include/pcb.h Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: pcb.h,v 1.22 2014/01/19 10:30:19 dsl Exp $ */ +/* $NetBSD: pcb.h,v 1.23 2014/02/07 22:40:22 dsl Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -93,7 +93,7 @@ struct pcb { uint64_t pcb_rbp; uint64_t pcb_usersp; uint32_t pcb_unused[2]; /* unused */ - struct savefpu pcb_savefpu __aligned(16); /* floating point state */ + union savefpu pcb_savefpu __aligned(16); /* floating point state */ uint32_t pcb_unused_1[4]; /* unused */ void *pcb_onfault; /* copyin/out fault recovery */ struct cpu_info *pcb_fpcpu; /* cpu holding our fp state. */ Index: src/sys/arch/amd64/include/reg.h diff -u src/sys/arch/amd64/include/reg.h:1.7 src/sys/arch/amd64/include/reg.h:1.8 --- src/sys/arch/amd64/include/reg.h:1.7 Sun Oct 26 00:08:15 2008 +++ src/sys/arch/amd64/include/reg.h Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: reg.h,v 1.7 2008/10/26 00:08:15 mrg Exp $ */ +/* $NetBSD: reg.h,v 1.8 2014/02/07 22:40:22 dsl Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. @@ -43,12 +43,6 @@ #include <machine/mcontext.h> /* - * XXX - * The #defines aren't used in the kernel, but some user-level code still - * expects them. - */ - -/* * Registers accessible to ptrace(2) syscall for debugger use. * Same as mcontext.__gregs (except that is 'unsigned long'). * NB this structure is no longer the same as 'struct trapframe', @@ -59,20 +53,9 @@ struct reg { }; struct fpreg { - struct fxsave64 fxstate; + struct fxsave fxstate; }; -#define fp_fcw fxstate.fx_fcw -#define fp_fsw fxstate.fx_fsw -#define fp_ftw fxstate.fx_ftw -#define fp_fop fxstate.fx_fop -#define fp_rip fxstate.fx_rip -#define fp_rdp fxstate.fx_rdp -#define fp_mxcsr fxstate.fx_mxcsr -#define fp_mxcsr_mask fxstate.fx_mxcsr_mask -#define fp_st fxstate.fx_st -#define fp_xmm fxstate.fx_xmm - #else /* __x86_64__ */ #include <i386/reg.h> Index: src/sys/arch/i386/conf/files.i386 diff -u src/sys/arch/i386/conf/files.i386:1.372 src/sys/arch/i386/conf/files.i386:1.373 --- src/sys/arch/i386/conf/files.i386:1.372 Sun Jan 26 19:16:16 2014 +++ src/sys/arch/i386/conf/files.i386 Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -# $NetBSD: files.i386,v 1.372 2014/01/26 19:16:16 dsl Exp $ +# $NetBSD: files.i386,v 1.373 2014/02/07 22:40:22 dsl Exp $ # # new style config file for i386 architecture # @@ -79,6 +79,7 @@ file arch/i386/i386/machdep.c file arch/i386/i386/longrun.c file arch/i386/i386/mtrr_k6.c mtrr file arch/i386/i386/process_machdep.c +file arch/x86/x86/convert_xmm_s87.c file arch/i386/i386/trap.c file dev/cons.c file arch/i386/isa/npx.c Index: src/sys/arch/i386/i386/process_machdep.c diff -u src/sys/arch/i386/i386/process_machdep.c:1.81 src/sys/arch/i386/i386/process_machdep.c:1.82 --- src/sys/arch/i386/i386/process_machdep.c:1.81 Tue Feb 4 22:48:26 2014 +++ src/sys/arch/i386/i386/process_machdep.c Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: process_machdep.c,v 1.81 2014/02/04 22:48:26 dsl Exp $ */ +/* $NetBSD: process_machdep.c,v 1.82 2014/02/07 22:40:22 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.81 2014/02/04 22:48:26 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.82 2014/02/07 22:40:22 dsl Exp $"); #include "opt_vm86.h" #include "opt_ptrace.h" @@ -90,123 +90,6 @@ process_fpframe(struct lwp *l) return &pcb->pcb_savefpu; } -void -process_xmm_to_s87(const struct fxsave *sxmm, struct save87 *s87) -{ - unsigned int tag, ab_tag; - const struct fpaccfx *fx_reg; - struct fpacc87 *s87_reg; - int i; - - /* - * For historic reasons core dumps and ptrace all use the old save87 - * layout. Convert the important parts. - * getucontext gets what we give it. - * setucontext should return something given by getucontext, but - * we are (at the moment) willing to change it. - * - * It really isn't worth setting the 'tag' bits to 01 (zero) or - * 10 (NaN etc) since the processor will set any internal bits - * correctly when the value is loaded (the 287 believed them). - * - * Additionally the s87_tw and s87_tw are 'indexed' by the actual - * register numbers, whereas the registers themselves have ST(0) - * first. Pairing the values and tags can only be done with - * reference to the 'top of stack'. - * - * If any x87 registers are used, they will typically be from - * r7 downwards - so the high bits of the tag register indicate - * used registers. The conversions are not optimised for this. - * - * The ABI we use requires the FP stack to be empty on every - * function call. I think this means that the stack isn't expected - * to overflow - overflow doesn't drop a core in my testing. - * - * Note that this code writes to all of the 's87' structure that - * actually gets written to userspace. - */ - - /* FPU control/status */ - s87->s87_cw = sxmm->fx_cw; - s87->s87_sw = sxmm->fx_sw; - /* tag word handled below */ - s87->s87_ip = sxmm->fx_ip; - s87->s87_opcode = sxmm->fx_opcode; - s87->s87_dp = sxmm->fx_dp; - - /* FP registers (in stack order) */ - fx_reg = sxmm->fx_87_ac; - s87_reg = s87->s87_ac; - for (i = 0; i < 8; fx_reg++, s87_reg++, i++) - *s87_reg = fx_reg->r; - - /* Tag word and registers. */ - ab_tag = sxmm->fx_tw & 0xff; /* Bits set if valid */ - if (ab_tag == 0) { - /* none used */ - s87->s87_tw = 0xffff; - return; - } - - tag = 0; - /* Separate bits of abridged tag word with zeros */ - for (i = 0x80; i != 0; tag <<= 1, i >>= 1) - tag |= ab_tag & i; - /* Replicate and invert so that 0 => 0b11 and 1 => 0b00 */ - s87->s87_tw = (tag | tag >> 1) ^ 0xffff; -} - -void -process_s87_to_xmm(const struct save87 *s87, struct fxsave *sxmm) -{ - unsigned int tag, ab_tag; - struct fpaccfx *fx_reg; - const struct fpacc87 *s87_reg; - int i; - - /* - * ptrace gives us registers in the save87 format and - * we must convert them to the correct format. - * - * This code is normally used when overwriting the processes - * registers (in the pcb), so it musn't change any other fields. - * - * There is a lot of pad in 'struct fxsave', if the destination - * is written to userspace, it must be zeroed first. - */ - - /* FPU control/status */ - sxmm->fx_cw = s87->s87_cw; - sxmm->fx_sw = s87->s87_sw; - /* tag word handled below */ - sxmm->fx_ip = s87->s87_ip; - sxmm->fx_opcode = s87->s87_opcode; - sxmm->fx_dp = s87->s87_dp; - - /* Tag word */ - tag = s87->s87_tw & 0xffff; /* 0b11 => unused */ - if (tag == 0xffff) { - /* All unused - values don't matter */ - sxmm->fx_tw = 0; - return; - } - - tag ^= 0xffff; /* So 0b00 is unused */ - tag |= tag >> 1; /* Look at even bits */ - ab_tag = 0; - i = 1; - do - ab_tag |= tag & i; - while ((tag >>= 1) >= (i <<= 1)); - sxmm->fx_tw = ab_tag; - - /* FP registers (in stack order) */ - fx_reg = sxmm->fx_87_ac; - s87_reg = s87->s87_ac; - for (i = 0; i < 8; fx_reg++, s87_reg++, i++) - fx_reg->r = *s87_reg; -} - int process_read_regs(struct lwp *l, struct reg *regs) { Index: src/sys/arch/i386/include/npx.h diff -u src/sys/arch/i386/include/npx.h:1.34 src/sys/arch/i386/include/npx.h:1.35 --- src/sys/arch/i386/include/npx.h:1.34 Fri Feb 7 19:36:15 2014 +++ src/sys/arch/i386/include/npx.h Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: npx.h,v 1.34 2014/02/07 19:36:15 dsl Exp $ */ +/* $NetBSD: npx.h,v 1.35 2014/02/07 22:40:22 dsl Exp $ */ #ifndef _I386_NPX_H_ #define _I386_NPX_H_ @@ -9,8 +9,6 @@ int npx586bug1(int, int); void fpuinit(struct cpu_info *); -void process_xmm_to_s87(const struct fxsave *, struct save87 *); -void process_s87_to_xmm(const struct save87 *, struct fxsave *); struct lwp; int npxtrap(struct lwp *); Index: src/sys/arch/x86/include/cpu_extended_state.h diff -u src/sys/arch/x86/include/cpu_extended_state.h:1.1 src/sys/arch/x86/include/cpu_extended_state.h:1.2 --- src/sys/arch/x86/include/cpu_extended_state.h:1.1 Fri Feb 7 19:36:15 2014 +++ src/sys/arch/x86/include/cpu_extended_state.h Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu_extended_state.h,v 1.1 2014/02/07 19:36:15 dsl Exp $ */ +/* $NetBSD: cpu_extended_state.h,v 1.2 2014/02/07 22:40:22 dsl Exp $ */ #ifndef _X86_CPU_EXTENDED_STATE_H_ #define _X86_CPU_EXTENDED_STATE_H_ @@ -118,7 +118,7 @@ __CTASSERT_NOLINT(sizeof (struct fxsave) /* The end of the fsave buffer can be used by the operating system */ struct fxsave_os { - uint8_t fxo_fxsave[offsetof(struct fxsave, fx_kernel)]; + uint8_t fxo_fxsave[512 - 48]; /* 48 bytes available */ }; @@ -237,6 +237,12 @@ __CTASSERT(sizeof (struct xsave_ymm) == * Bits 16-31 must be zero. */ #define __INITIAL_MXCSR__ 0x1f80 +#define __INITIAL_MXCSR_MASK__ 0xffbf + +#ifdef _KERNEL +void process_xmm_to_s87(const struct fxsave *, struct save87 *); +void process_s87_to_xmm(const struct save87 *, struct fxsave *); +#endif #endif /* _X86_CPU_EXTENDED_STATE_H_ */ Index: src/sys/arch/xen/conf/files.xen diff -u src/sys/arch/xen/conf/files.xen:1.130 src/sys/arch/xen/conf/files.xen:1.131 --- src/sys/arch/xen/conf/files.xen:1.130 Sun Jan 26 19:16:17 2014 +++ src/sys/arch/xen/conf/files.xen Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -# $NetBSD: files.xen,v 1.130 2014/01/26 19:16:17 dsl Exp $ +# $NetBSD: files.xen,v 1.131 2014/02/07 22:40:22 dsl Exp $ # NetBSD: files.x86,v 1.10 2003/10/08 17:30:00 bouyer Exp # NetBSD: files.i386,v 1.254 2004/03/25 23:32:10 jmc Exp @@ -84,6 +84,7 @@ file arch/amd64/amd64/lock_stubs.S endif file kern/subr_disk_mbr.c disk +file arch/x86/x86/convert_xmm_s87.c file arch/x86/x86/db_memrw.c ddb | kgdb file arch/x86/x86/db_trace.c ddb file arch/xen/x86/hypervisor_machdep.c Index: src/sys/compat/linux/arch/amd64/linux_machdep.c diff -u src/sys/compat/linux/arch/amd64/linux_machdep.c:1.44 src/sys/compat/linux/arch/amd64/linux_machdep.c:1.45 --- src/sys/compat/linux/arch/amd64/linux_machdep.c:1.44 Sat Jan 4 00:10:03 2014 +++ src/sys/compat/linux/arch/amd64/linux_machdep.c Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: linux_machdep.c,v 1.44 2014/01/04 00:10:03 dsl Exp $ */ +/* $NetBSD: linux_machdep.c,v 1.45 2014/02/07 22:40:22 dsl Exp $ */ /*- * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved. @@ -33,7 +33,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.44 2014/01/04 00:10:03 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.45 2014/02/07 22:40:22 dsl Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -90,9 +90,9 @@ linux_setregs(struct lwp *l, struct exec l->l_md.md_flags &= ~MDL_USEDFPU; pcb->pcb_flags = 0; - pcb->pcb_savefpu.fp_fxsave.fx_fcw = __NetBSD_NPXCW__; - pcb->pcb_savefpu.fp_fxsave.fx_mxcsr = __INITIAL_MXCSR__; - pcb->pcb_savefpu.fp_fxsave.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__; + pcb->pcb_savefpu.sv_xmm.fx_cw = __NetBSD_NPXCW__; + pcb->pcb_savefpu.sv_xmm.fx_mxcsr = __INITIAL_MXCSR__; + pcb->pcb_savefpu.sv_xmm.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__; l->l_proc->p_flag &= ~PK_32; @@ -134,7 +134,7 @@ linux_sendsig(const ksiginfo_t *ksi, con int onstack, error; int sig = ksi->ksi_signo; struct linux_rt_sigframe *sfp, sigframe; - struct linux__fpstate *fpsp, fpstate; + struct linux__fpstate *fpsp; struct fpreg fpregs; struct trapframe *tf = l->l_md.md_regs; sig_t catcher = SIGACTION(p, sig).sa_handler; @@ -158,7 +158,7 @@ linux_sendsig(const ksiginfo_t *ksi, con */ if (l->l_md.md_flags & MDL_USEDFPU) { sp = (char *) - (((long)sp - sizeof(struct linux__fpstate)) & ~0xfUL); + (((long)sp - sizeof (*fpsp)) & ~0xfUL); fpsp = (struct linux__fpstate *)sp; } else fpsp = NULL; @@ -230,21 +230,9 @@ linux_sendsig(const ksiginfo_t *ksi, con */ if (fpsp != NULL) { size_t fp_size = sizeof fpregs; + /* The netbsd and linux structures both match the fxsave data */ (void)process_read_fpregs(l, &fpregs, &fp_size); - memset(&fpstate, 0, sizeof(fpstate)); - fpstate.cwd = fpregs.fp_fcw; - fpstate.swd = fpregs.fp_fsw; - fpstate.twd = fpregs.fp_ftw; - fpstate.fop = fpregs.fp_fop; - fpstate.rip = fpregs.fp_rip; - fpstate.rdp = fpregs.fp_rdp; - fpstate.mxcsr = fpregs.fp_mxcsr; - fpstate.mxcsr_mask = fpregs.fp_mxcsr_mask; - memcpy(&fpstate.st_space, &fpregs.fp_st, - sizeof(fpstate.st_space)); - memcpy(&fpstate.xmm_space, &fpregs.fp_xmm, - sizeof(fpstate.xmm_space)); - error = copyout(&fpstate, fpsp, sizeof(fpstate)); + error = copyout(&fpregs, fpsp, sizeof(*fpsp)); } if (error == 0) @@ -327,11 +315,10 @@ linux_sys_rt_sigreturn(struct lwp *l, co struct linux_ucontext *luctx; struct trapframe *tf = l->l_md.md_regs; struct linux_sigcontext *lsigctx; - struct linux__fpstate fpstate; struct linux_rt_sigframe frame, *fp; ucontext_t uctx; mcontext_t *mctx; - struct fxsave64 *fxarea; + struct fxsave *fxarea; int error; fp = (struct linux_rt_sigframe *)(tf->tf_rsp - 8); @@ -345,7 +332,7 @@ linux_sys_rt_sigreturn(struct lwp *l, co memset(&uctx, 0, sizeof(uctx)); mctx = (mcontext_t *)&uctx.uc_mcontext; - fxarea = (struct fxsave64 *)&mctx->__fpregs; + fxarea = (struct fxsave *)&mctx->__fpregs; /* * Set the flags. Linux always have CPU, stack and signal state, @@ -395,25 +382,13 @@ linux_sys_rt_sigreturn(struct lwp *l, co * FPU state */ if (lsigctx->fpstate != NULL) { - error = copyin(lsigctx->fpstate, &fpstate, sizeof(fpstate)); + /* Both structures match the fxstate data */ + error = copyin(lsigctx->fpstate, fxarea, sizeof(*fxarea)); if (error != 0) { mutex_enter(l->l_proc->p_lock); sigexit(l, SIGILL); return error; } - - fxarea->fx_fcw = fpstate.cwd; - fxarea->fx_fsw = fpstate.swd; - fxarea->fx_ftw = fpstate.twd; - fxarea->fx_fop = fpstate.fop; - fxarea->fx_rip = fpstate.rip; - fxarea->fx_rdp = fpstate.rdp; - fxarea->fx_mxcsr = fpstate.mxcsr; - fxarea->fx_mxcsr_mask = fpstate.mxcsr_mask; - memcpy(&fxarea->fx_st, &fpstate.st_space, - sizeof(fxarea->fx_st)); - memcpy(&fxarea->fx_xmm, &fpstate.xmm_space, - sizeof(fxarea->fx_xmm)); } /* Index: src/sys/compat/linux/arch/amd64/linux_machdep.h diff -u src/sys/compat/linux/arch/amd64/linux_machdep.h:1.13 src/sys/compat/linux/arch/amd64/linux_machdep.h:1.14 --- src/sys/compat/linux/arch/amd64/linux_machdep.h:1.13 Wed Jul 7 01:30:33 2010 +++ src/sys/compat/linux/arch/amd64/linux_machdep.h Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: linux_machdep.h,v 1.13 2010/07/07 01:30:33 chs Exp $ */ +/* $NetBSD: linux_machdep.h,v 1.14 2014/02/07 22:40:22 dsl Exp $ */ /*- * Copyright (c) 2005 Emmanuel Dreyfus, all rights reserved. @@ -41,6 +41,7 @@ #include <compat/linux/common/linux_siginfo.h> /* From <asm/sigcontext.h> */ +/* Matches the cpu's fxsave format */ struct linux__fpstate { u_int16_t cwd; u_int16_t swd; @@ -54,6 +55,7 @@ struct linux__fpstate { u_int32_t xmm_space[64]; u_int32_t reserved2[24]; }; +__CTASSERT(sizeof (struct linux__fpstate) == 512); /* From <asm/sigcontext.h> */ struct linux_sigcontext { Index: src/sys/compat/linux32/arch/amd64/linux32_machdep.c diff -u src/sys/compat/linux32/arch/amd64/linux32_machdep.c:1.33 src/sys/compat/linux32/arch/amd64/linux32_machdep.c:1.34 --- src/sys/compat/linux32/arch/amd64/linux32_machdep.c:1.33 Sun Dec 1 01:05:16 2013 +++ src/sys/compat/linux32/arch/amd64/linux32_machdep.c Fri Feb 7 22:40:22 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: linux32_machdep.c,v 1.33 2013/12/01 01:05:16 christos Exp $ */ +/* $NetBSD: linux32_machdep.c,v 1.34 2014/02/07 22:40:22 dsl Exp $ */ /*- * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved. @@ -31,7 +31,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: linux32_machdep.c,v 1.33 2013/12/01 01:05:16 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: linux32_machdep.c,v 1.34 2014/02/07 22:40:22 dsl Exp $"); #include <sys/param.h> #include <sys/proc.h> @@ -286,9 +286,9 @@ linux32_setregs(struct lwp *l, struct ex l->l_md.md_flags &= ~MDL_USEDFPU; l->l_md.md_flags |= MDL_COMPAT32; /* Forces iret not sysret */ pcb->pcb_flags = PCB_COMPAT32; - pcb->pcb_savefpu.fp_fxsave.fx_fcw = __Linux_NPXCW__; - pcb->pcb_savefpu.fp_fxsave.fx_mxcsr = __INITIAL_MXCSR__; - pcb->pcb_savefpu.fp_fxsave.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__; + pcb->pcb_savefpu.sv_xmm.fx_cw = __Linux_NPXCW__; + pcb->pcb_savefpu.sv_xmm.fx_mxcsr = __INITIAL_MXCSR__; + pcb->pcb_savefpu.sv_xmm.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__; p->p_flag |= PK_32; Added files: Index: src/sys/arch/x86/x86/convert_xmm_s87.c diff -u /dev/null src/sys/arch/x86/x86/convert_xmm_s87.c:1.1 --- /dev/null Fri Feb 7 22:40:23 2014 +++ src/sys/arch/x86/x86/convert_xmm_s87.c Fri Feb 7 22:40:22 2014 @@ -0,0 +1,155 @@ +/* $NetBSD: convert_xmm_s87.c,v 1.1 2014/02/07 22:40:22 dsl Exp $ */ + +/*- + * Copyright (c) 1998, 2000, 2001, 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum; by Jason R. Thorpe of Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: convert_xmm_s87.c,v 1.1 2014/02/07 22:40:22 dsl Exp $"); + + +#include <sys/param.h> +#include <sys/systm.h> +#include <x86/cpu_extended_state.h> + +void +process_xmm_to_s87(const struct fxsave *sxmm, struct save87 *s87) +{ + unsigned int tag, ab_tag; + const struct fpaccfx *fx_reg; + struct fpacc87 *s87_reg; + int i; + + /* + * For historic reasons core dumps and ptrace all use the old save87 + * layout. Convert the important parts. + * getucontext gets what we give it. + * setucontext should return something given by getucontext, but + * we are (at the moment) willing to change it. + * + * It really isn't worth setting the 'tag' bits to 01 (zero) or + * 10 (NaN etc) since the processor will set any internal bits + * correctly when the value is loaded (the 287 believed them). + * + * Additionally the s87_tw and s87_tw are 'indexed' by the actual + * register numbers, whereas the registers themselves have ST(0) + * first. Pairing the values and tags can only be done with + * reference to the 'top of stack'. + * + * If any x87 registers are used, they will typically be from + * r7 downwards - so the high bits of the tag register indicate + * used registers. The conversions are not optimised for this. + * + * The ABI we use requires the FP stack to be empty on every + * function call. I think this means that the stack isn't expected + * to overflow - overflow doesn't drop a core in my testing. + * + * Note that this code writes to all of the 's87' structure that + * actually gets written to userspace. + */ + + /* FPU control/status */ + s87->s87_cw = sxmm->fx_cw; + s87->s87_sw = sxmm->fx_sw; + /* tag word handled below */ + s87->s87_ip = sxmm->fx_ip; + s87->s87_opcode = sxmm->fx_opcode; + s87->s87_dp = sxmm->fx_dp; + + /* FP registers (in stack order) */ + fx_reg = sxmm->fx_87_ac; + s87_reg = s87->s87_ac; + for (i = 0; i < 8; fx_reg++, s87_reg++, i++) + *s87_reg = fx_reg->r; + + /* Tag word and registers. */ + ab_tag = sxmm->fx_tw & 0xff; /* Bits set if valid */ + if (ab_tag == 0) { + /* none used */ + s87->s87_tw = 0xffff; + return; + } + + tag = 0; + /* Separate bits of abridged tag word with zeros */ + for (i = 0x80; i != 0; tag <<= 1, i >>= 1) + tag |= ab_tag & i; + /* Replicate and invert so that 0 => 0b11 and 1 => 0b00 */ + s87->s87_tw = (tag | tag >> 1) ^ 0xffff; +} + +void +process_s87_to_xmm(const struct save87 *s87, struct fxsave *sxmm) +{ + unsigned int tag, ab_tag; + struct fpaccfx *fx_reg; + const struct fpacc87 *s87_reg; + int i; + + /* + * ptrace gives us registers in the save87 format and + * we must convert them to the correct format. + * + * This code is normally used when overwriting the processes + * registers (in the pcb), so it musn't change any other fields. + * + * There is a lot of pad in 'struct fxsave', if the destination + * is written to userspace, it must be zeroed first. + */ + + /* FPU control/status */ + sxmm->fx_cw = s87->s87_cw; + sxmm->fx_sw = s87->s87_sw; + /* tag word handled below */ + sxmm->fx_ip = s87->s87_ip; + sxmm->fx_opcode = s87->s87_opcode; + sxmm->fx_dp = s87->s87_dp; + + /* Tag word */ + tag = s87->s87_tw & 0xffff; /* 0b11 => unused */ + if (tag == 0xffff) { + /* All unused - values don't matter */ + sxmm->fx_tw = 0; + return; + } + + tag ^= 0xffff; /* So 0b00 is unused */ + tag |= tag >> 1; /* Look at even bits */ + ab_tag = 0; + i = 1; + do + ab_tag |= tag & i; + while ((tag >>= 1) >= (i <<= 1)); + sxmm->fx_tw = ab_tag; + + /* FP registers (in stack order) */ + fx_reg = sxmm->fx_87_ac; + s87_reg = s87->s87_ac; + for (i = 0; i < 8; fx_reg++, s87_reg++, i++) + fx_reg->r = *s87_reg; +}