* buf == buf_fx for 64-bit frames and 32-bit fsave frame.
* buf != buf_fx for 32-bit frames with fxstate.
*
- * Save the state to task's fpu->state and then copy it to the user frame
- * pointed to by the aligned pointer 'buf_fx'.
+ * Try to save it directly to the user frame with disabled page fault handler.
+ * If this fails then do the slow path where the FPU state is first saved to
+ * task's fpu->state and then copy it to the user frame pointed to by the
+ * aligned pointer 'buf_fx'.
*
* If this is a 32-bit frame with fxstate, put a fsave header before
* the aligned state at 'buf_fx'.
struct xregs_state *xsave = &fpu->state.xsave;
struct task_struct *tsk = current;
int ia32_fxstate = (buf != buf_fx);
+ int ret = -EFAULT;
ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) ||
IS_ENABLED(CONFIG_IA32_EMULATION));
/*
* If we do not need to load the FPU registers at return to userspace
- * then the CPU has the current state and we need to save it. Otherwise,
- * it has already been done and we can skip it.
+ * then the CPU has the current state. Try to save it directly to
+ * userland's stack frame if it does not cause a pagefault. If it does,
+ * try the slowpath.
*/
fpregs_lock();
if (!test_thread_flag(TIF_NEED_FPU_LOAD)) {
- copy_fpregs_to_fpstate(fpu);
+ pagefault_disable();
+ ret = copy_fpregs_to_sigframe(buf_fx);
+ pagefault_enable();
+ if (ret)
+ copy_fpregs_to_fpstate(fpu);
set_thread_flag(TIF_NEED_FPU_LOAD);
}
fpregs_unlock();
- if (using_compacted_format()) {
- if (copy_xstate_to_user(buf_fx, xsave, 0, size))
- return -1;
- } else {
- fpstate_sanitize_xstate(fpu);
- if (__copy_to_user(buf_fx, xsave, fpu_user_xstate_size))
- return -1;
+ if (ret) {
+ if (using_compacted_format()) {
+ if (copy_xstate_to_user(buf_fx, xsave, 0, size))
+ return -1;
+ } else {
+ fpstate_sanitize_xstate(fpu);
+ if (__copy_to_user(buf_fx, xsave, fpu_user_xstate_size))
+ return -1;
+ }
}
/* Save the fsave header for the 32-bit frames. */