/* * This restores directly out of user space. Exceptions are handled. */ int restore_i387_xstate(void __user *buf) { struct task_struct *tsk = current; int err = 0; if (!buf) { if (used_math()) goto clear; return 0; } else if (!access_ok(VERIFY_READ, buf, sig_xstate_size)) return -EACCES; if (!used_math()) { err = init_fpu(tsk); if (err) return err; } user_fpu_begin(); if (use_xsave()) err = restore_user_xstate(buf); else err = fxrstor_checking((__force struct i387_fxsave_struct *) buf); if (unlikely(err)) { /* * Encountered an error while doing the restore from the * user buffer, clear the fpu state. */ clear: clear_fpu(tsk); clear_used_math(); } return err; }
/* * Restore the extended state if present. Otherwise, restore the FP/SSE * state. */ static int restore_user_xstate(void __user *buf) { struct _fpx_sw_bytes fx_sw_user; u64 mask; int err; if (((unsigned long)buf % 64) || check_for_xstate(buf, buf, &fx_sw_user)) goto fx_only; mask = fx_sw_user.xstate_bv; /* * restore the state passed by the user. */ err = xrestore_user(buf, mask); if (err) return err; /* * init the state skipped by the user. */ mask = pcntxt_mask & ~mask; if (unlikely(mask)) xrstor_state(init_xstate_buf, mask); return 0; fx_only: /* * couldn't find the extended state information in the * memory layout. Restore just the FP/SSE and init all * the other extended state. */ xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE); return fxrstor_checking((struct i387_fxsave_struct __force_kernel *)buf); }
static int restore_user_xstate(void __user *buf) { struct _fpx_sw_bytes fx_sw_user; u64 mask; int err; if (((unsigned long)buf % 64) || check_for_xstate(buf, buf, &fx_sw_user)) goto fx_only; mask = fx_sw_user.xstate_bv; /* */ err = xrestore_user(buf, mask); if (err) return err; /* */ mask = pcntxt_mask & ~mask; if (unlikely(mask)) xrstor_state(init_xstate_buf, mask); return 0; fx_only: /* */ xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE); return fxrstor_checking((__force struct i387_fxsave_struct *)buf); }