x86, xsave: reorganization of signal save/restore fpstate code layout
move 64bit routines that saves/restores fpstate in/from user stack from signal_64.c to xsave.c restore_i387_xstate() now handles the condition when user passes NULL fpstate. Other misc changes for prepartion of xsave/xrstor sigcontext support. Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
committed by
Ingo Molnar
parent
3c1c7f1014
commit
ab5137015f
@@ -216,7 +216,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
|
|||||||
unsigned int *peax)
|
unsigned int *peax)
|
||||||
{
|
{
|
||||||
unsigned int tmpflags, gs, oldgs, err = 0;
|
unsigned int tmpflags, gs, oldgs, err = 0;
|
||||||
struct _fpstate_ia32 __user *buf;
|
void __user *buf;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
/* Always make any pending restarted system calls return -EINTR */
|
/* Always make any pending restarted system calls return -EINTR */
|
||||||
@@ -260,26 +260,12 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
|
|||||||
|
|
||||||
err |= __get_user(tmp, &sc->fpstate);
|
err |= __get_user(tmp, &sc->fpstate);
|
||||||
buf = compat_ptr(tmp);
|
buf = compat_ptr(tmp);
|
||||||
if (buf) {
|
err |= restore_i387_xstate_ia32(buf);
|
||||||
if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
|
|
||||||
goto badframe;
|
|
||||||
err |= restore_i387_ia32(buf);
|
|
||||||
} else {
|
|
||||||
struct task_struct *me = current;
|
|
||||||
|
|
||||||
if (used_math()) {
|
|
||||||
clear_fpu(me);
|
|
||||||
clear_used_math();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err |= __get_user(tmp, &sc->ax);
|
err |= __get_user(tmp, &sc->ax);
|
||||||
*peax = tmp;
|
*peax = tmp;
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
badframe:
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys32_sigreturn(struct pt_regs *regs)
|
asmlinkage long sys32_sigreturn(struct pt_regs *regs)
|
||||||
@@ -351,7 +337,7 @@ badframe:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
|
static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
|
||||||
struct _fpstate_ia32 __user *fpstate,
|
void __user *fpstate,
|
||||||
struct pt_regs *regs, unsigned int mask)
|
struct pt_regs *regs, unsigned int mask)
|
||||||
{
|
{
|
||||||
int tmp, err = 0;
|
int tmp, err = 0;
|
||||||
@@ -382,7 +368,7 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
|
|||||||
err |= __put_user((u32)regs->flags, &sc->flags);
|
err |= __put_user((u32)regs->flags, &sc->flags);
|
||||||
err |= __put_user((u32)regs->sp, &sc->sp_at_signal);
|
err |= __put_user((u32)regs->sp, &sc->sp_at_signal);
|
||||||
|
|
||||||
tmp = save_i387_ia32(fpstate);
|
tmp = save_i387_xstate_ia32(fpstate);
|
||||||
if (tmp < 0)
|
if (tmp < 0)
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
else {
|
else {
|
||||||
@@ -404,7 +390,7 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
|
|||||||
*/
|
*/
|
||||||
static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
|
static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
|
||||||
size_t frame_size,
|
size_t frame_size,
|
||||||
struct _fpstate_ia32 **fpstate)
|
void **fpstate)
|
||||||
{
|
{
|
||||||
unsigned long sp;
|
unsigned long sp;
|
||||||
|
|
||||||
@@ -441,7 +427,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
|
|||||||
struct sigframe __user *frame;
|
struct sigframe __user *frame;
|
||||||
void __user *restorer;
|
void __user *restorer;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct _fpstate_ia32 __user *fpstate = NULL;
|
void __user *fpstate = NULL;
|
||||||
|
|
||||||
/* copy_to_user optimizes that into a single 8 byte store */
|
/* copy_to_user optimizes that into a single 8 byte store */
|
||||||
static const struct {
|
static const struct {
|
||||||
@@ -529,7 +515,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
struct rt_sigframe __user *frame;
|
struct rt_sigframe __user *frame;
|
||||||
void __user *restorer;
|
void __user *restorer;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct _fpstate_ia32 __user *fpstate = NULL;
|
void __user *fpstate = NULL;
|
||||||
|
|
||||||
/* __copy_to_user optimizes that into a single 8 byte store */
|
/* __copy_to_user optimizes that into a single 8 byte store */
|
||||||
static const struct {
|
static const struct {
|
||||||
|
@@ -21,9 +21,10 @@
|
|||||||
# include <asm/sigcontext32.h>
|
# include <asm/sigcontext32.h>
|
||||||
# include <asm/user32.h>
|
# include <asm/user32.h>
|
||||||
#else
|
#else
|
||||||
# define save_i387_ia32 save_i387
|
# define save_i387_xstate_ia32 save_i387_xstate
|
||||||
# define restore_i387_ia32 restore_i387
|
# define restore_i387_xstate_ia32 restore_i387_xstate
|
||||||
# define _fpstate_ia32 _fpstate
|
# define _fpstate_ia32 _fpstate
|
||||||
|
# define _xstate_ia32 _xstate
|
||||||
# define sig_xstate_ia32_size sig_xstate_size
|
# define sig_xstate_ia32_size sig_xstate_size
|
||||||
# define user_i387_ia32_struct user_i387_struct
|
# define user_i387_ia32_struct user_i387_struct
|
||||||
# define user32_fxsr_struct user_fxsr_struct
|
# define user32_fxsr_struct user_fxsr_struct
|
||||||
@@ -424,7 +425,6 @@ static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf)
|
|||||||
struct task_struct *tsk = current;
|
struct task_struct *tsk = current;
|
||||||
struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave;
|
struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave;
|
||||||
|
|
||||||
unlazy_fpu(tsk);
|
|
||||||
fp->status = fp->swd;
|
fp->status = fp->swd;
|
||||||
if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct)))
|
if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct)))
|
||||||
return -1;
|
return -1;
|
||||||
@@ -438,8 +438,6 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
|
|||||||
struct user_i387_ia32_struct env;
|
struct user_i387_ia32_struct env;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
unlazy_fpu(tsk);
|
|
||||||
|
|
||||||
convert_from_fxsr(&env, tsk);
|
convert_from_fxsr(&env, tsk);
|
||||||
if (__copy_to_user(buf, &env, sizeof(env)))
|
if (__copy_to_user(buf, &env, sizeof(env)))
|
||||||
return -1;
|
return -1;
|
||||||
@@ -455,10 +453,16 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int save_i387_ia32(struct _fpstate_ia32 __user *buf)
|
int save_i387_xstate_ia32(void __user *buf)
|
||||||
{
|
{
|
||||||
|
struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
|
||||||
|
struct task_struct *tsk = current;
|
||||||
|
|
||||||
if (!used_math())
|
if (!used_math())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_WRITE, buf, sig_xstate_ia32_size))
|
||||||
|
return -EACCES;
|
||||||
/*
|
/*
|
||||||
* This will cause a "finit" to be triggered by the next
|
* This will cause a "finit" to be triggered by the next
|
||||||
* attempted FPU operation by the 'current' process.
|
* attempted FPU operation by the 'current' process.
|
||||||
@@ -468,13 +472,15 @@ int save_i387_ia32(struct _fpstate_ia32 __user *buf)
|
|||||||
if (!HAVE_HWFP) {
|
if (!HAVE_HWFP) {
|
||||||
return fpregs_soft_get(current, NULL,
|
return fpregs_soft_get(current, NULL,
|
||||||
0, sizeof(struct user_i387_ia32_struct),
|
0, sizeof(struct user_i387_ia32_struct),
|
||||||
NULL, buf) ? -1 : 1;
|
NULL, fp) ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unlazy_fpu(tsk);
|
||||||
|
|
||||||
if (cpu_has_fxsr)
|
if (cpu_has_fxsr)
|
||||||
return save_i387_fxsave(buf);
|
return save_i387_fxsave(fp);
|
||||||
else
|
else
|
||||||
return save_i387_fsave(buf);
|
return save_i387_fsave(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
|
static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
|
||||||
@@ -502,14 +508,26 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int restore_i387_ia32(struct _fpstate_ia32 __user *buf)
|
int restore_i387_xstate_ia32(void __user *buf)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct task_struct *tsk = current;
|
struct task_struct *tsk = current;
|
||||||
|
struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
|
||||||
|
|
||||||
if (HAVE_HWFP)
|
if (HAVE_HWFP)
|
||||||
clear_fpu(tsk);
|
clear_fpu(tsk);
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
if (used_math()) {
|
||||||
|
clear_fpu(tsk);
|
||||||
|
clear_used_math();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
if (!access_ok(VERIFY_READ, buf, sig_xstate_ia32_size))
|
||||||
|
return -EACCES;
|
||||||
|
|
||||||
if (!used_math()) {
|
if (!used_math()) {
|
||||||
err = init_fpu(tsk);
|
err = init_fpu(tsk);
|
||||||
if (err)
|
if (err)
|
||||||
@@ -518,13 +536,13 @@ int restore_i387_ia32(struct _fpstate_ia32 __user *buf)
|
|||||||
|
|
||||||
if (HAVE_HWFP) {
|
if (HAVE_HWFP) {
|
||||||
if (cpu_has_fxsr)
|
if (cpu_has_fxsr)
|
||||||
err = restore_i387_fxsave(buf);
|
err = restore_i387_fxsave(fp);
|
||||||
else
|
else
|
||||||
err = restore_i387_fsave(buf);
|
err = restore_i387_fsave(fp);
|
||||||
} else {
|
} else {
|
||||||
err = fpregs_soft_set(current, NULL,
|
err = fpregs_soft_set(current, NULL,
|
||||||
0, sizeof(struct user_i387_ia32_struct),
|
0, sizeof(struct user_i387_ia32_struct),
|
||||||
NULL, buf) != 0;
|
NULL, fp) != 0;
|
||||||
}
|
}
|
||||||
set_used_math();
|
set_used_math();
|
||||||
|
|
||||||
|
@@ -159,28 +159,14 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
struct _fpstate __user *buf;
|
void __user *buf;
|
||||||
|
|
||||||
err |= __get_user(buf, &sc->fpstate);
|
err |= __get_user(buf, &sc->fpstate);
|
||||||
if (buf) {
|
err |= restore_i387_xstate(buf);
|
||||||
if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
|
|
||||||
goto badframe;
|
|
||||||
err |= restore_i387(buf);
|
|
||||||
} else {
|
|
||||||
struct task_struct *me = current;
|
|
||||||
|
|
||||||
if (used_math()) {
|
|
||||||
clear_fpu(me);
|
|
||||||
clear_used_math();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err |= __get_user(*pax, &sc->ax);
|
err |= __get_user(*pax, &sc->ax);
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
badframe:
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage unsigned long sys_sigreturn(unsigned long __unused)
|
asmlinkage unsigned long sys_sigreturn(unsigned long __unused)
|
||||||
@@ -262,7 +248,7 @@ badframe:
|
|||||||
* Set up a signal frame.
|
* Set up a signal frame.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
|
setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
|
||||||
struct pt_regs *regs, unsigned long mask)
|
struct pt_regs *regs, unsigned long mask)
|
||||||
{
|
{
|
||||||
int tmp, err = 0;
|
int tmp, err = 0;
|
||||||
@@ -289,7 +275,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
|
|||||||
err |= __put_user(regs->sp, &sc->sp_at_signal);
|
err |= __put_user(regs->sp, &sc->sp_at_signal);
|
||||||
err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
|
err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
|
||||||
|
|
||||||
tmp = save_i387(fpstate);
|
tmp = save_i387_xstate(fpstate);
|
||||||
if (tmp < 0)
|
if (tmp < 0)
|
||||||
err = 1;
|
err = 1;
|
||||||
else
|
else
|
||||||
@@ -307,7 +293,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
|
|||||||
*/
|
*/
|
||||||
static inline void __user *
|
static inline void __user *
|
||||||
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
|
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
|
||||||
struct _fpstate **fpstate)
|
void **fpstate)
|
||||||
{
|
{
|
||||||
unsigned long sp;
|
unsigned long sp;
|
||||||
|
|
||||||
@@ -356,7 +342,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
|
|||||||
void __user *restorer;
|
void __user *restorer;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int usig;
|
int usig;
|
||||||
struct _fpstate __user *fpstate = NULL;
|
void __user *fpstate = NULL;
|
||||||
|
|
||||||
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
|
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
|
||||||
|
|
||||||
@@ -434,7 +420,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
void __user *restorer;
|
void __user *restorer;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int usig;
|
int usig;
|
||||||
struct _fpstate __user *fpstate = NULL;
|
void __user *fpstate = NULL;
|
||||||
|
|
||||||
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
|
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
|
||||||
|
|
||||||
|
@@ -53,69 +53,6 @@ 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;
|
|
||||||
}
|
|
||||||
err = restore_fpu_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_fpu(tsk);
|
|
||||||
clear_used_math();
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do a signal return; undo the signal stack.
|
* Do a signal return; undo the signal stack.
|
||||||
*/
|
*/
|
||||||
@@ -160,25 +97,11 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
|||||||
{
|
{
|
||||||
struct _fpstate __user * buf;
|
struct _fpstate __user * buf;
|
||||||
err |= __get_user(buf, &sc->fpstate);
|
err |= __get_user(buf, &sc->fpstate);
|
||||||
|
err |= restore_i387_xstate(buf);
|
||||||
if (buf) {
|
|
||||||
if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
|
|
||||||
goto badframe;
|
|
||||||
err |= restore_i387(buf);
|
|
||||||
} else {
|
|
||||||
struct task_struct *me = current;
|
|
||||||
if (used_math()) {
|
|
||||||
clear_fpu(me);
|
|
||||||
clear_used_math();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err |= __get_user(*pax, &sc->ax);
|
err |= __get_user(*pax, &sc->ax);
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
badframe:
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
|
asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
|
||||||
@@ -276,7 +199,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
sigset_t *set, struct pt_regs * regs)
|
sigset_t *set, struct pt_regs * regs)
|
||||||
{
|
{
|
||||||
struct rt_sigframe __user *frame;
|
struct rt_sigframe __user *frame;
|
||||||
struct _fpstate __user *fp = NULL;
|
void __user *fp = NULL;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct task_struct *me = current;
|
struct task_struct *me = current;
|
||||||
|
|
||||||
@@ -288,7 +211,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate)))
|
if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate)))
|
||||||
goto give_sigsegv;
|
goto give_sigsegv;
|
||||||
|
|
||||||
if (save_i387(fp) < 0)
|
if (save_i387_xstate(fp) < 0)
|
||||||
err |= -1;
|
err |= -1;
|
||||||
} else
|
} else
|
||||||
frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
|
frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
|
||||||
|
@@ -12,6 +12,85 @@
|
|||||||
*/
|
*/
|
||||||
unsigned int pcntxt_hmask, pcntxt_lmask;
|
unsigned int pcntxt_hmask, pcntxt_lmask;
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
/*
|
||||||
|
* Signal frame handlers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int save_i387_xstate(void __user *buf)
|
||||||
|
{
|
||||||
|
struct task_struct *tsk = current;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
|
||||||
|
return -EACCES;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(struct user_i387_struct) !=
|
||||||
|
sizeof(tsk->thread.xstate->fxsave));
|
||||||
|
|
||||||
|
if ((unsigned long)buf % 16)
|
||||||
|
printk("save_i387_xstate: 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,
|
||||||
|
xstate_size))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This restores directly out of user space. Exceptions are handled.
|
||||||
|
*/
|
||||||
|
int restore_i387_xstate(void __user *buf)
|
||||||
|
{
|
||||||
|
struct task_struct *tsk = current;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
if (used_math()) {
|
||||||
|
clear_fpu(tsk);
|
||||||
|
clear_used_math();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(task_thread_info(current)->status & TS_USEDFPU)) {
|
||||||
|
clts();
|
||||||
|
task_thread_info(current)->status |= TS_USEDFPU;
|
||||||
|
}
|
||||||
|
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_fpu(tsk);
|
||||||
|
clear_used_math();
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Represents init state for the supported extended state.
|
* Represents init state for the supported extended state.
|
||||||
*/
|
*/
|
||||||
|
@@ -34,8 +34,9 @@ extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set;
|
|||||||
#ifdef CONFIG_IA32_EMULATION
|
#ifdef CONFIG_IA32_EMULATION
|
||||||
extern unsigned int sig_xstate_ia32_size;
|
extern unsigned int sig_xstate_ia32_size;
|
||||||
struct _fpstate_ia32;
|
struct _fpstate_ia32;
|
||||||
extern int save_i387_ia32(struct _fpstate_ia32 __user *buf);
|
struct _xstate_ia32;
|
||||||
extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf);
|
extern int save_i387_xstate_ia32(void __user *buf);
|
||||||
|
extern int restore_i387_xstate_ia32(void __user *buf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define X87_FSW_ES (1 << 7) /* Exception Summary */
|
#define X87_FSW_ES (1 << 7) /* Exception Summary */
|
||||||
@@ -249,13 +250,13 @@ end:
|
|||||||
task_thread_info(tsk)->status &= ~TS_USEDFPU;
|
task_thread_info(tsk)->status &= ~TS_USEDFPU;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_X86_64 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signal frame handlers...
|
* Signal frame handlers...
|
||||||
*/
|
*/
|
||||||
extern int save_i387(struct _fpstate __user *buf);
|
extern int save_i387_xstate(void __user *buf);
|
||||||
extern int restore_i387(struct _fpstate __user *buf);
|
extern int restore_i387_xstate(void __user *buf);
|
||||||
|
|
||||||
#endif /* CONFIG_X86_64 */
|
|
||||||
|
|
||||||
static inline void __unlazy_fpu(struct task_struct *tsk)
|
static inline void __unlazy_fpu(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user