Index: sys/amd64/linux/linux.h =================================================================== --- sys/amd64/linux/linux.h +++ sys/amd64/linux/linux.h @@ -233,6 +233,7 @@ l_stack_t uc_stack; struct l_sigcontext uc_mcontext; l_sigset_t uc_sigmask; + struct l_fpstate uc_fpregs; }; #define LINUX_SI_PREAMBLE_SIZE (4 * sizeof(int)) Index: sys/amd64/linux/linux_sysvec.c =================================================================== --- sys/amd64/linux/linux_sysvec.c +++ sys/amd64/linux/linux_sysvec.c @@ -513,9 +513,7 @@ } /* - * Copied from amd64/amd64/machdep.c - * - * XXX fpu state need? don't think so + * Based on amd64/amd64/exec_machdep.c */ int linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args) @@ -524,8 +522,10 @@ struct l_ucontext uc; struct l_sigcontext *context; struct trapframe *regs; + mcontext_t mcontext; + struct savefpu *savefpu; unsigned long rflags; - int error; + int error, ret; ksiginfo_t ksi; regs = td->td_frame; @@ -573,6 +573,34 @@ return (EINVAL); } + if (uc.uc_mcontext.sc_fpstate != NULL) { + memset(&mcontext, 0, sizeof(mcontext)); + mcontext.mc_flags |= _MC_HASFPXSTATE; + mcontext.mc_fpformat = _MC_FPFMT_XMM; + mcontext.mc_ownedfp = _MC_FPOWNED_FPU; + + savefpu = (struct savefpu *)mcontext.mc_fpstate; + savefpu->sv_env.en_cw = uc.uc_fpregs.cwd; + savefpu->sv_env.en_sw = uc.uc_fpregs.swd; + savefpu->sv_env.en_tw = uc.uc_fpregs.twd; + savefpu->sv_env.en_opcode = uc.uc_fpregs.fop; + savefpu->sv_env.en_rip = uc.uc_fpregs.rip; + savefpu->sv_env.en_rdp = uc.uc_fpregs.rdp; + savefpu->sv_env.en_mxcsr = uc.uc_fpregs.mxcsr; + savefpu->sv_env.en_mxcsr_mask = uc.uc_fpregs.mxcsr_mask; + CTASSERT(sizeof(uc.uc_fpregs.st_space) == sizeof(savefpu->sv_fp)); + memcpy(savefpu->sv_fp, uc.uc_fpregs.st_space, sizeof(savefpu->sv_fp)); + CTASSERT(sizeof(uc.uc_fpregs.xmm_space) == sizeof(savefpu->sv_xmm)); + memcpy(savefpu->sv_xmm, uc.uc_fpregs.xmm_space, sizeof(savefpu->sv_xmm)); + + ret = set_fpcontext(td, &mcontext, NULL, 0); + if (ret != 0) { + uprintf("pid %d (%s): sigreturn set_fpcontext err %d\n", + p->p_pid, td->td_name, ret); + return (ret); + } + } + PROC_LOCK(p); linux_to_bsd_sigset(&uc.uc_sigmask, &td->td_sigmask); SIG_CANTMASK(td->td_sigmask); @@ -605,7 +633,7 @@ } /* - * copied from amd64/amd64/machdep.c + * Based on amd64/amd64/exec_machdep.c * * Send an interrupt to process. */ @@ -618,6 +646,8 @@ struct sigacts *psp; caddr_t sp; struct trapframe *regs; + mcontext_t mcontext; + const struct savefpu *savefpu; int sig, code; int oonstack; @@ -667,6 +697,28 @@ sf.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); sf.sf_sc.uc_mcontext.sc_cr2 = (register_t)ksi->ksi_addr; + get_fpcontext(td, &mcontext, NULL, NULL); + if (mcontext.mc_fpformat == _MC_FPFMT_XMM) { + savefpu = (const struct savefpu *)mcontext.mc_fpstate; + + sf.sf_sc.uc_fpregs.cwd = savefpu->sv_env.en_cw; + sf.sf_sc.uc_fpregs.swd = savefpu->sv_env.en_sw; + sf.sf_sc.uc_fpregs.twd = savefpu->sv_env.en_tw; + sf.sf_sc.uc_fpregs.fop = savefpu->sv_env.en_opcode; + sf.sf_sc.uc_fpregs.rip = savefpu->sv_env.en_rip; + sf.sf_sc.uc_fpregs.rdp = savefpu->sv_env.en_rdp; + sf.sf_sc.uc_fpregs.mxcsr = savefpu->sv_env.en_mxcsr; + sf.sf_sc.uc_fpregs.mxcsr_mask = savefpu->sv_env.en_mxcsr_mask; + CTASSERT(sizeof(sf.sf_sc.uc_fpregs.st_space) == + sizeof(savefpu->sv_fp)); + memcpy(sf.sf_sc.uc_fpregs.st_space, + savefpu->sv_fp, sizeof(savefpu->sv_fp)); + CTASSERT(sizeof(sf.sf_sc.uc_fpregs.xmm_space) == + sizeof(savefpu->sv_xmm)); + memcpy(sf.sf_sc.uc_fpregs.xmm_space, + savefpu->sv_xmm, sizeof(savefpu->sv_xmm)); + } + /* Allocate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { @@ -693,6 +745,11 @@ mtx_unlock(&psp->ps_mtx); PROC_UNLOCK(p); + if (mcontext.mc_fpformat == _MC_FPFMT_XMM) { + sf.sf_sc.uc_mcontext.sc_fpstate = (void *)((char *)sfp + + ((char *)&sf.sf_sc.uc_fpregs - (char *)&sf)); + } + /* Copy the sigframe out to the user's stack. */ if (copyout(&sf, sfp, sizeof(*sfp)) != 0) { uprintf("pid %d comm %s has trashed its stack, killing\n",