Index: sys/amd64/amd64/exec_machdep.c =================================================================== --- sys/amd64/amd64/exec_machdep.c +++ sys/amd64/amd64/exec_machdep.c @@ -95,11 +95,6 @@ #include #include -static void get_fpcontext(struct thread *td, mcontext_t *mcp, - char **xfpusave, size_t *xfpusave_len); -static int set_fpcontext(struct thread *td, mcontext_t *mcp, - char *xfpustate, size_t xfpustate_len); - /* * Send an interrupt to process. * @@ -714,7 +709,7 @@ return (0); } -static void +void get_fpcontext(struct thread *td, mcontext_t *mcp, char **xfpusave, size_t *xfpusave_len) { @@ -735,7 +730,7 @@ } } -static int +int set_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpustate, size_t xfpustate_len) { Index: sys/amd64/include/md_var.h =================================================================== --- sys/amd64/include/md_var.h +++ sys/amd64/include/md_var.h @@ -54,6 +54,7 @@ extern bool efi_boot; +struct __mcontext; struct savefpu; struct sysentvec; @@ -88,5 +89,9 @@ struct savefpu *get_pcb_user_save_td(struct thread *td); struct savefpu *get_pcb_user_save_pcb(struct pcb *pcb); void pci_early_quirks(void); +void get_fpcontext(struct thread *td, struct __mcontext *mcp, + char **xfpusave, size_t *xfpusave_len); +int set_fpcontext(struct thread *td, struct __mcontext *mcp, + char *xfpustate, size_t xfpustate_len); #endif /* !_MACHINE_MD_VAR_H_ */ Index: sys/amd64/linux/linux.h =================================================================== --- sys/amd64/linux/linux.h +++ sys/amd64/linux/linux.h @@ -227,12 +227,15 @@ l_ulong sc_reserved1[8]; }; +#define LINUX_UC_FLAGS_XSTATE 0x1 + struct l_ucontext { l_ulong uc_flags; l_uintptr_t uc_link; 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 @@ -518,9 +518,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) @@ -529,8 +527,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; @@ -578,6 +578,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); @@ -610,7 +638,7 @@ } /* - * copied from amd64/amd64/machdep.c + * Based on amd64/amd64/exec_machdep.c * * Send an interrupt to process. */ @@ -623,6 +651,8 @@ struct sigacts *psp; caddr_t sp; struct trapframe *regs; + mcontext_t mcontext; + const struct savefpu *savefpu; int sig, code; int oonstack; @@ -672,13 +702,33 @@ 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)); + + sf.sf_sc.uc_mcontext.sc_fpstate= (struct l_fpstate *)&sf.sf_sc.uc_fpregs; // XXX: Should be user addr + } + /* Allocate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { - sp = (caddr_t)td->td_sigstk.ss_sp + td->td_sigstk.ss_size - - sizeof(struct l_rt_sigframe); + sp = (caddr_t)td->td_sigstk.ss_sp + td->td_sigstk.ss_size; } else - sp = (caddr_t)regs->tf_rsp - sizeof(struct l_rt_sigframe) - 128; + sp = (caddr_t)regs->tf_rsp - 128; + sp -= sizeof(struct l_rt_sigframe); /* Align to 16 bytes. */ sfp = (struct l_rt_sigframe *)((unsigned long)sp & ~0xFul); @@ -700,6 +750,8 @@ /* 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", + p->p_pid, p->p_comm); PROC_LOCK(p); sigexit(td, SIGILL); }