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 @@ -34,6 +34,7 @@ #ifndef _MACHINE_MD_VAR_H_ #define _MACHINE_MD_VAR_H_ +#include #include extern char ctx_switch_xsave[]; @@ -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, mcontext_t *mcp, + char **xfpusave, size_t *xfpusave_len); +int set_fpcontext(struct thread *td, mcontext_t *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 @@ -33,6 +33,7 @@ #define _AMD64_LINUX_H_ #include +#include #include #include @@ -233,6 +234,7 @@ l_stack_t uc_stack; struct l_sigcontext uc_mcontext; l_sigset_t uc_sigmask; + mcontext_t uc_fpcontext; }; #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; + char *xfpustate; + size_t xfpustate_len; unsigned long rflags; - int error; + int error, ret; ksiginfo_t ksi; regs = td->td_frame; @@ -578,6 +578,36 @@ return (EINVAL); } + if ((uc.uc_fpcontext.mc_flags & _MC_HASFPXSTATE) != 0) { + xfpustate_len = uc.uc_fpcontext.mc_xfpustate_len; + if (xfpustate_len > cpu_max_ext_state_size - + sizeof(struct savefpu)) { + uprintf("pid %d (%s): sigreturn xfpusave_len = 0x%zx\n", + p->p_pid, td->td_name, xfpustate_len); + return (EINVAL); + } + xfpustate = (char *)fpu_save_area_alloc(); + error = copyin((const void *)uc.uc_fpcontext.mc_xfpustate, + xfpustate, xfpustate_len); + if (error != 0) { + fpu_save_area_free((struct savefpu *)xfpustate); + uprintf( + "pid %d (%s): sigreturn copying xfpustate failed\n", + p->p_pid, td->td_name); + return (error); + } + } else { + xfpustate = NULL; + xfpustate_len = 0; + } + ret = set_fpcontext(td, &uc.uc_fpcontext, xfpustate, xfpustate_len); + fpu_save_area_free((struct savefpu *)xfpustate); + 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 +640,7 @@ } /* - * copied from amd64/amd64/machdep.c + * Based on amd64/amd64/exec_machdep.c * * Send an interrupt to process. */ @@ -623,6 +653,8 @@ struct sigacts *psp; caddr_t sp; struct trapframe *regs; + char *xfpusave; + size_t xfpusave_len; int sig, code; int oonstack; @@ -672,13 +704,20 @@ 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, &sf.sf_sc.uc_fpcontext, &xfpusave, &xfpusave_len); + /* 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; + if (xfpusave != NULL) { + sp -= xfpusave_len; + sp = (char *)((unsigned long)sp & ~0x3Ful); + sf.sf_sc.uc_fpcontext.mc_xfpustate = (register_t)sp; + } + sp -= sizeof(struct l_rt_sigframe); /* Align to 16 bytes. */ sfp = (struct l_rt_sigframe *)((unsigned long)sp & ~0xFul); @@ -699,7 +738,12 @@ PROC_UNLOCK(p); /* Copy the sigframe out to the user's stack. */ - if (copyout(&sf, sfp, sizeof(*sfp)) != 0) { + if (copyout(&sf, sfp, sizeof(*sfp)) != 0 || + (xfpusave != NULL && copyout(xfpusave, + (void *)sf.sf_sc.uc_fpcontext.mc_xfpustate, xfpusave_len) + != 0)) { + linux_msg(td, "pid %d comm %s has trashed its stack, killing\n", + p->p_pid, p->p_comm); PROC_LOCK(p); sigexit(td, SIGILL); }