|
@@ -53,6 +53,59 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
|
|
return do_sigaltstack(uss, uoss, regs->sp);
|
|
return do_sigaltstack(uss, uoss, regs->sp);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Signal frame handlers.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+static inline int save_i387(struct _fpstate __user *buf)
|
|
|
|
+{
|
|
|
|
+ struct task_struct *tsk = current;
|
|
|
|
+ int err = 0;
|
|
|
|
+
|
|
|
|
+ BUILD_BUG_ON(sizeof(struct user_i387_struct) !=
|
|
|
|
+ sizeof(tsk->thread.xstate->fxsave));
|
|
|
|
+
|
|
|
|
+ if ((unsigned long)buf % 16)
|
|
|
|
+ printk("save_i387: bad fpstate %p\n", buf);
|
|
|
|
+
|
|
|
|
+ if (!used_math())
|
|
|
|
+ return 0;
|
|
|
|
+ clear_used_math(); /* trigger finit */
|
|
|
|
+ if (task_thread_info(tsk)->status & TS_USEDFPU) {
|
|
|
|
+ err = save_i387_checking((struct i387_fxsave_struct __user *)
|
|
|
|
+ buf);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+ task_thread_info(tsk)->status &= ~TS_USEDFPU;
|
|
|
|
+ stts();
|
|
|
|
+ } else {
|
|
|
|
+ if (__copy_to_user(buf, &tsk->thread.xstate->fxsave,
|
|
|
|
+ sizeof(struct i387_fxsave_struct)))
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * This restores directly out of user space. Exceptions are handled.
|
|
|
|
+ */
|
|
|
|
+static inline int restore_i387(struct _fpstate __user *buf)
|
|
|
|
+{
|
|
|
|
+ struct task_struct *tsk = current;
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ if (!used_math()) {
|
|
|
|
+ err = init_fpu(tsk);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!(task_thread_info(current)->status & TS_USEDFPU)) {
|
|
|
|
+ clts();
|
|
|
|
+ task_thread_info(current)->status |= TS_USEDFPU;
|
|
|
|
+ }
|
|
|
|
+ return restore_fpu_checking((__force struct i387_fxsave_struct *)buf);
|
|
|
|
+}
|
|
|
|
|
|
/*
|
|
/*
|
|
* Do a signal return; undo the signal stack.
|
|
* Do a signal return; undo the signal stack.
|