/* * Save the fpu, extended register state to the user signal frame. * * 'buf_fx' is the 64-byte aligned pointer at which the [f|fx|x]save * state is copied. * 'buf' points to the 'buf_fx' or to the fsave header followed by 'buf_fx'. * * buf == buf_fx for 64-bit frames and 32-bit fsave frame. * buf != buf_fx for 32-bit frames with fxstate. * * If the fpu, extended register state is live, save the state directly * to the user frame pointed by the aligned pointer 'buf_fx'. Otherwise, * copy the thread's fpu state to the user frame starting at 'buf_fx'. * * If this is a 32-bit frame with fxstate, put a fsave header before * the aligned state at 'buf_fx'. * * For [f]xsave state, update the SW reserved fields in the [f]xsave frame * indicating the absence/presence of the extended state to the user. */ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) { struct xregs_state *xsave = ¤t->thread.fpu.state.xsave; struct task_struct *tsk = current; int ia32_fxstate = (buf != buf_fx); ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) || IS_ENABLED(CONFIG_IA32_EMULATION)); if (!access_ok(VERIFY_WRITE, buf, size)) return -EACCES; if (!static_cpu_has(X86_FEATURE_FPU)) return fpregs_soft_get(current, NULL, 0, sizeof(struct user_i387_ia32_struct), NULL, (struct _fpstate_32 __user *) buf) ? -1 : 1; if (fpregs_active() || using_compacted_format()) { /* Save the live register state to the user directly. */ if (copy_fpregs_to_sigframe(buf_fx)) return -1; /* Update the thread's fxstate to save the fsave header. */ if (ia32_fxstate) copy_fxregs_to_kernel(&tsk->thread.fpu); } else { /* * It is a *bug* if kernel uses compacted-format for xsave * area and we copy it out directly to a signal frame. It * should have been handled above by saving the registers * directly. */ if (boot_cpu_has(X86_FEATURE_XSAVES)) { WARN_ONCE(1, "x86/fpu: saving compacted-format xsave area to a signal frame!\n"); return -1; } fpstate_sanitize_xstate(&tsk->thread.fpu); if (__copy_to_user(buf_fx, xsave, fpu_user_xstate_size)) return -1; } /* Save the fsave header for the 32-bit frames. */ if ((ia32_fxstate || !use_fxsr()) && save_fsave_header(tsk, buf)) return -1; if (use_fxsr() && save_xstate_epilog(buf_fx, ia32_fxstate)) return -1; return 0; }
/* * Save the fpu, extended register state to the user signal frame. * * 'buf_fx' is the 64-byte aligned pointer at which the [f|fx|x]save * state is copied. * 'buf' points to the 'buf_fx' or to the fsave header followed by 'buf_fx'. * * buf == buf_fx for 64-bit frames and 32-bit fsave frame. * buf != buf_fx for 32-bit frames with fxstate. * * If the fpu, extended register state is live, save the state directly * to the user frame pointed by the aligned pointer 'buf_fx'. Otherwise, * copy the thread's fpu state to the user frame starting at 'buf_fx'. * * If this is a 32-bit frame with fxstate, put a fsave header before * the aligned state at 'buf_fx'. * * For [f]xsave state, update the SW reserved fields in the [f]xsave frame * indicating the absence/presence of the extended state to the user. */ int save_xstate_sig(void __user *buf, void __user *buf_fx, int size) { struct xsave_struct *xsave = ¤t->thread.fpu.state->xsave; struct task_struct *tsk = current; int ia32_fxstate = (buf != buf_fx); ia32_fxstate &= (config_enabled(CONFIG_X86_32) || config_enabled(CONFIG_IA32_EMULATION)); if (!access_ok(VERIFY_WRITE, buf, size)) return -EACCES; if (!static_cpu_has(X86_FEATURE_FPU)) return fpregs_soft_get(current, NULL, 0, sizeof(struct user_i387_ia32_struct), NULL, (struct _fpstate_ia32 __user *) buf) ? -1 : 1; if (!config_enabled(CONFIG_L4) && user_has_fpu()) { /* Save the live register state to the user directly. */ if (save_user_xstate(buf_fx)) return -1; /* Update the thread's fxstate to save the fsave header. */ if (ia32_fxstate) fpu_fxsave(&tsk->thread.fpu); } else { if (config_enabled(CONFIG_L4) && user_has_fpu()) unlazy_fpu(tsk); sanitize_i387_state(tsk); if (__copy_to_user(buf_fx, xsave, xstate_size)) return -1; } /* Save the fsave header for the 32-bit frames. */ if ((ia32_fxstate || !use_fxsr()) && save_fsave_header(tsk, buf)) return -1; if (use_fxsr() && save_xstate_epilog(buf_fx, ia32_fxstate)) return -1; drop_init_fpu(tsk); /* trigger finit */ return 0; }