Loading arch/x86/ia32/ia32_signal.c +24 −27 Original line number Diff line number Diff line Loading @@ -179,9 +179,10 @@ struct sigframe u32 pretcode; int sig; struct sigcontext_ia32 sc; struct _fpstate_ia32 fpstate; struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */ unsigned int extramask[_COMPAT_NSIG_WORDS-1]; char retcode[8]; /* fp state follows here */ }; struct rt_sigframe Loading @@ -192,8 +193,8 @@ struct rt_sigframe u32 puc; compat_siginfo_t info; struct ucontext_ia32 uc; struct _fpstate_ia32 fpstate; char retcode[8]; /* fp state follows here */ }; #define COPY(x) { \ Loading @@ -215,7 +216,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, unsigned int *peax) { unsigned int tmpflags, gs, oldgs, err = 0; struct _fpstate_ia32 __user *buf; void __user *buf; u32 tmp; /* Always make any pending restarted system calls return -EINTR */ Loading Loading @@ -259,26 +260,12 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, err |= __get_user(tmp, &sc->fpstate); buf = compat_ptr(tmp); if (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 |= restore_i387_xstate_ia32(buf); err |= __get_user(tmp, &sc->ax); *peax = tmp; return err; badframe: return 1; } asmlinkage long sys32_sigreturn(struct pt_regs *regs) Loading Loading @@ -350,7 +337,7 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) */ 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) { int tmp, err = 0; Loading Loading @@ -381,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->sp, &sc->sp_at_signal); tmp = save_i387_ia32(fpstate); tmp = save_i387_xstate_ia32(fpstate); if (tmp < 0) err = -EFAULT; else { Loading @@ -402,7 +389,8 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, * Determine which stack to use.. */ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) size_t frame_size, void **fpstate) { unsigned long sp; Loading @@ -421,6 +409,11 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, ka->sa.sa_restorer) sp = (unsigned long) ka->sa.sa_restorer; if (used_math()) { sp = sp - sig_xstate_ia32_size; *fpstate = (struct _fpstate_ia32 *) sp; } sp -= frame_size; /* Align the stack pointer according to the i386 ABI, * i.e. so that on function entry ((sp + 4) & 15) == 0. */ Loading @@ -434,6 +427,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, struct sigframe __user *frame; void __user *restorer; int err = 0; void __user *fpstate = NULL; /* copy_to_user optimizes that into a single 8 byte store */ static const struct { Loading @@ -448,7 +442,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, 0, }; frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; Loading @@ -457,8 +451,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, if (err) goto give_sigsegv; err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]); if (err) goto give_sigsegv; Loading Loading @@ -522,6 +515,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, struct rt_sigframe __user *frame; void __user *restorer; int err = 0; void __user *fpstate = NULL; /* __copy_to_user optimizes that into a single 8 byte store */ static const struct { Loading @@ -537,7 +531,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 0, }; frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; Loading @@ -550,13 +544,16 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, goto give_sigsegv; /* Create the ucontext. */ if (cpu_has_xsave) err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); else err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) Loading arch/x86/kernel/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ obj-y += tsc.o io_delay.o rtc.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-y += process.o obj-y += i387.o obj-y += i387.o xsave.o obj-y += ptrace.o obj-y += ds.o obj-$(CONFIG_X86_32) += tls.o Loading arch/x86/kernel/cpu/common.c +12 −1 Original line number Diff line number Diff line Loading @@ -739,9 +739,20 @@ void __cpuinit cpu_init(void) /* * Force FPU initialization: */ if (cpu_has_xsave) current_thread_info()->status = TS_XSAVE; else current_thread_info()->status = 0; clear_used_math(); mxcsr_feature_mask_init(); /* * Boot processor to setup the FP and extended state context info. */ if (!smp_processor_id()) init_thread_xstate(); xsave_init(); } #ifdef CONFIG_HOTPLUG_CPU Loading arch/x86/kernel/i387.c +135 −19 Original line number Diff line number Diff line Loading @@ -21,9 +21,12 @@ # include <asm/sigcontext32.h> # include <asm/user32.h> #else # define save_i387_ia32 save_i387 # define restore_i387_ia32 restore_i387 # define save_i387_xstate_ia32 save_i387_xstate # define restore_i387_xstate_ia32 restore_i387_xstate # define _fpstate_ia32 _fpstate # define _xstate_ia32 _xstate # define sig_xstate_ia32_size sig_xstate_size # define fx_sw_reserved_ia32 fx_sw_reserved # define user_i387_ia32_struct user_i387_struct # define user32_fxsr_struct user_fxsr_struct #endif Loading @@ -36,6 +39,7 @@ static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; unsigned int xstate_size; unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32); static struct i387_fxsave_struct fx_scratch __cpuinitdata; void __cpuinit mxcsr_feature_mask_init(void) Loading @@ -61,6 +65,11 @@ void __init init_thread_xstate(void) return; } if (cpu_has_xsave) { xsave_cntxt_init(); return; } if (cpu_has_fxsr) xstate_size = sizeof(struct i387_fxsave_struct); #ifdef CONFIG_X86_32 Loading @@ -83,8 +92,18 @@ void __cpuinit fpu_init(void) write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */ /* * Boot processor to setup the FP and extended state context info. */ if (!smp_processor_id()) init_thread_xstate(); xsave_init(); mxcsr_feature_mask_init(); /* clean state in init */ if (cpu_has_xsave) current_thread_info()->status = TS_XSAVE; else current_thread_info()->status = 0; clear_used_math(); } Loading Loading @@ -195,6 +214,13 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset, */ target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; /* * update the header bits in the xsave header, indicating the * presence of FP and SSE state. */ if (cpu_has_xsave) target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE; return ret; } Loading Loading @@ -395,6 +421,12 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, if (!ret) convert_to_fxsr(target, &env); /* * update the header bit in the xsave header, indicating the * presence of FP. */ if (cpu_has_xsave) target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FP; return ret; } Loading @@ -407,7 +439,6 @@ static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf) struct task_struct *tsk = current; struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave; unlazy_fpu(tsk); fp->status = fp->swd; if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct))) return -1; Loading @@ -421,8 +452,6 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf) struct user_i387_ia32_struct env; int err = 0; unlazy_fpu(tsk); convert_from_fxsr(&env, tsk); if (__copy_to_user(buf, &env, sizeof(env))) return -1; Loading @@ -432,16 +461,40 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf) if (err) return -1; if (__copy_to_user(&buf->_fxsr_env[0], fx, sizeof(struct i387_fxsave_struct))) if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size)) return -1; return 1; } static int save_i387_xsave(void __user *buf) { struct _fpstate_ia32 __user *fx = buf; int err = 0; if (save_i387_fxsave(fx) < 0) return -1; err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32, sizeof(struct _fpx_sw_bytes)); err |= __put_user(FP_XSTATE_MAGIC2, (__u32 __user *) (buf + sig_xstate_ia32_size - FP_XSTATE_MAGIC2_SIZE)); if (err) 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()) 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 * attempted FPU operation by the 'current' process. Loading @@ -451,13 +504,17 @@ int save_i387_ia32(struct _fpstate_ia32 __user *buf) if (!HAVE_HWFP) { return fpregs_soft_get(current, NULL, 0, sizeof(struct user_i387_ia32_struct), NULL, buf) ? -1 : 1; NULL, fp) ? -1 : 1; } unlazy_fpu(tsk); if (cpu_has_xsave) return save_i387_xsave(fp); if (cpu_has_fxsr) return save_i387_fxsave(buf); return save_i387_fxsave(fp); else return save_i387_fsave(buf); return save_i387_fsave(fp); } static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) Loading @@ -468,14 +525,15 @@ static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) sizeof(struct i387_fsave_struct)); } static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf) static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf, unsigned int size) { struct task_struct *tsk = current; struct user_i387_ia32_struct env; int err; err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0], sizeof(struct i387_fxsave_struct)); size); /* mxcsr reserved bits must be masked to zero for security reasons */ tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; if (err || __copy_from_user(&env, buf, sizeof(env))) Loading @@ -485,14 +543,69 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf) return 0; } int restore_i387_ia32(struct _fpstate_ia32 __user *buf) static int restore_i387_xsave(void __user *buf) { struct _fpx_sw_bytes fx_sw_user; struct _fpstate_ia32 __user *fx_user = ((struct _fpstate_ia32 __user *) buf); struct i387_fxsave_struct __user *fx = (struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0]; struct xsave_hdr_struct *xsave_hdr = ¤t->thread.xstate->xsave.xsave_hdr; u64 mask; int err; if (check_for_xstate(fx, buf, &fx_sw_user)) goto fx_only; mask = fx_sw_user.xstate_bv; err = restore_i387_fxsave(buf, fx_sw_user.xstate_size); xsave_hdr->xstate_bv &= pcntxt_mask; /* * These bits must be zero. */ xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0; /* * Init the state that is not present in the memory layout * and enabled by the OS. */ mask = ~(pcntxt_mask & ~mask); xsave_hdr->xstate_bv &= mask; return err; fx_only: /* * Couldn't find the extended state information in the memory * layout. Restore the FP/SSE and init the other extended state * enabled by the OS. */ xsave_hdr->xstate_bv = XSTATE_FPSSE; return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct)); } int restore_i387_xstate_ia32(void __user *buf) { int err; struct task_struct *tsk = current; struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf; if (HAVE_HWFP) 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()) { err = init_fpu(tsk); if (err) Loading @@ -500,14 +613,17 @@ int restore_i387_ia32(struct _fpstate_ia32 __user *buf) } if (HAVE_HWFP) { if (cpu_has_fxsr) err = restore_i387_fxsave(buf); if (cpu_has_xsave) err = restore_i387_xsave(buf); else if (cpu_has_fxsr) err = restore_i387_fxsave(fp, sizeof(struct i387_fxsave_struct)); else err = restore_i387_fsave(buf); err = restore_i387_fsave(fp); } else { err = fpregs_soft_set(current, NULL, 0, sizeof(struct user_i387_ia32_struct), NULL, buf) != 0; NULL, fp) != 0; } set_used_math(); Loading arch/x86/kernel/sigframe.h +12 −2 Original line number Diff line number Diff line Loading @@ -3,9 +3,18 @@ struct sigframe { char __user *pretcode; int sig; struct sigcontext sc; struct _fpstate fpstate; /* * fpstate is unused. fpstate is moved/allocated after * retcode[] below. This movement allows to have the FP state and the * future state extensions (xsave) stay together. * And at the same time retaining the unused fpstate, prevents changing * the offset of extramask[] in the sigframe and thus prevent any * legacy application accessing/modifying it. */ struct _fpstate fpstate_unused; unsigned long extramask[_NSIG_WORDS-1]; char retcode[8]; /* fp state follows here */ }; struct rt_sigframe { Loading @@ -15,13 +24,14 @@ struct rt_sigframe { void __user *puc; struct siginfo info; struct ucontext uc; struct _fpstate fpstate; char retcode[8]; /* fp state follows here */ }; #else struct rt_sigframe { char __user *pretcode; struct ucontext uc; struct siginfo info; /* fp state follows here */ }; #endif Loading
arch/x86/ia32/ia32_signal.c +24 −27 Original line number Diff line number Diff line Loading @@ -179,9 +179,10 @@ struct sigframe u32 pretcode; int sig; struct sigcontext_ia32 sc; struct _fpstate_ia32 fpstate; struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */ unsigned int extramask[_COMPAT_NSIG_WORDS-1]; char retcode[8]; /* fp state follows here */ }; struct rt_sigframe Loading @@ -192,8 +193,8 @@ struct rt_sigframe u32 puc; compat_siginfo_t info; struct ucontext_ia32 uc; struct _fpstate_ia32 fpstate; char retcode[8]; /* fp state follows here */ }; #define COPY(x) { \ Loading @@ -215,7 +216,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, unsigned int *peax) { unsigned int tmpflags, gs, oldgs, err = 0; struct _fpstate_ia32 __user *buf; void __user *buf; u32 tmp; /* Always make any pending restarted system calls return -EINTR */ Loading Loading @@ -259,26 +260,12 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, err |= __get_user(tmp, &sc->fpstate); buf = compat_ptr(tmp); if (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 |= restore_i387_xstate_ia32(buf); err |= __get_user(tmp, &sc->ax); *peax = tmp; return err; badframe: return 1; } asmlinkage long sys32_sigreturn(struct pt_regs *regs) Loading Loading @@ -350,7 +337,7 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) */ 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) { int tmp, err = 0; Loading Loading @@ -381,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->sp, &sc->sp_at_signal); tmp = save_i387_ia32(fpstate); tmp = save_i387_xstate_ia32(fpstate); if (tmp < 0) err = -EFAULT; else { Loading @@ -402,7 +389,8 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, * Determine which stack to use.. */ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) size_t frame_size, void **fpstate) { unsigned long sp; Loading @@ -421,6 +409,11 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, ka->sa.sa_restorer) sp = (unsigned long) ka->sa.sa_restorer; if (used_math()) { sp = sp - sig_xstate_ia32_size; *fpstate = (struct _fpstate_ia32 *) sp; } sp -= frame_size; /* Align the stack pointer according to the i386 ABI, * i.e. so that on function entry ((sp + 4) & 15) == 0. */ Loading @@ -434,6 +427,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, struct sigframe __user *frame; void __user *restorer; int err = 0; void __user *fpstate = NULL; /* copy_to_user optimizes that into a single 8 byte store */ static const struct { Loading @@ -448,7 +442,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, 0, }; frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; Loading @@ -457,8 +451,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, if (err) goto give_sigsegv; err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]); if (err) goto give_sigsegv; Loading Loading @@ -522,6 +515,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, struct rt_sigframe __user *frame; void __user *restorer; int err = 0; void __user *fpstate = NULL; /* __copy_to_user optimizes that into a single 8 byte store */ static const struct { Loading @@ -537,7 +531,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 0, }; frame = get_sigframe(ka, regs, sizeof(*frame)); frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; Loading @@ -550,13 +544,16 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, goto give_sigsegv; /* Create the ucontext. */ if (cpu_has_xsave) err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); else err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) Loading
arch/x86/kernel/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ obj-y += tsc.o io_delay.o rtc.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-y += process.o obj-y += i387.o obj-y += i387.o xsave.o obj-y += ptrace.o obj-y += ds.o obj-$(CONFIG_X86_32) += tls.o Loading
arch/x86/kernel/cpu/common.c +12 −1 Original line number Diff line number Diff line Loading @@ -739,9 +739,20 @@ void __cpuinit cpu_init(void) /* * Force FPU initialization: */ if (cpu_has_xsave) current_thread_info()->status = TS_XSAVE; else current_thread_info()->status = 0; clear_used_math(); mxcsr_feature_mask_init(); /* * Boot processor to setup the FP and extended state context info. */ if (!smp_processor_id()) init_thread_xstate(); xsave_init(); } #ifdef CONFIG_HOTPLUG_CPU Loading
arch/x86/kernel/i387.c +135 −19 Original line number Diff line number Diff line Loading @@ -21,9 +21,12 @@ # include <asm/sigcontext32.h> # include <asm/user32.h> #else # define save_i387_ia32 save_i387 # define restore_i387_ia32 restore_i387 # define save_i387_xstate_ia32 save_i387_xstate # define restore_i387_xstate_ia32 restore_i387_xstate # define _fpstate_ia32 _fpstate # define _xstate_ia32 _xstate # define sig_xstate_ia32_size sig_xstate_size # define fx_sw_reserved_ia32 fx_sw_reserved # define user_i387_ia32_struct user_i387_struct # define user32_fxsr_struct user_fxsr_struct #endif Loading @@ -36,6 +39,7 @@ static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; unsigned int xstate_size; unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32); static struct i387_fxsave_struct fx_scratch __cpuinitdata; void __cpuinit mxcsr_feature_mask_init(void) Loading @@ -61,6 +65,11 @@ void __init init_thread_xstate(void) return; } if (cpu_has_xsave) { xsave_cntxt_init(); return; } if (cpu_has_fxsr) xstate_size = sizeof(struct i387_fxsave_struct); #ifdef CONFIG_X86_32 Loading @@ -83,8 +92,18 @@ void __cpuinit fpu_init(void) write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */ /* * Boot processor to setup the FP and extended state context info. */ if (!smp_processor_id()) init_thread_xstate(); xsave_init(); mxcsr_feature_mask_init(); /* clean state in init */ if (cpu_has_xsave) current_thread_info()->status = TS_XSAVE; else current_thread_info()->status = 0; clear_used_math(); } Loading Loading @@ -195,6 +214,13 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset, */ target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; /* * update the header bits in the xsave header, indicating the * presence of FP and SSE state. */ if (cpu_has_xsave) target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE; return ret; } Loading Loading @@ -395,6 +421,12 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, if (!ret) convert_to_fxsr(target, &env); /* * update the header bit in the xsave header, indicating the * presence of FP. */ if (cpu_has_xsave) target->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FP; return ret; } Loading @@ -407,7 +439,6 @@ static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf) struct task_struct *tsk = current; struct i387_fsave_struct *fp = &tsk->thread.xstate->fsave; unlazy_fpu(tsk); fp->status = fp->swd; if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct))) return -1; Loading @@ -421,8 +452,6 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf) struct user_i387_ia32_struct env; int err = 0; unlazy_fpu(tsk); convert_from_fxsr(&env, tsk); if (__copy_to_user(buf, &env, sizeof(env))) return -1; Loading @@ -432,16 +461,40 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf) if (err) return -1; if (__copy_to_user(&buf->_fxsr_env[0], fx, sizeof(struct i387_fxsave_struct))) if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size)) return -1; return 1; } static int save_i387_xsave(void __user *buf) { struct _fpstate_ia32 __user *fx = buf; int err = 0; if (save_i387_fxsave(fx) < 0) return -1; err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32, sizeof(struct _fpx_sw_bytes)); err |= __put_user(FP_XSTATE_MAGIC2, (__u32 __user *) (buf + sig_xstate_ia32_size - FP_XSTATE_MAGIC2_SIZE)); if (err) 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()) 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 * attempted FPU operation by the 'current' process. Loading @@ -451,13 +504,17 @@ int save_i387_ia32(struct _fpstate_ia32 __user *buf) if (!HAVE_HWFP) { return fpregs_soft_get(current, NULL, 0, sizeof(struct user_i387_ia32_struct), NULL, buf) ? -1 : 1; NULL, fp) ? -1 : 1; } unlazy_fpu(tsk); if (cpu_has_xsave) return save_i387_xsave(fp); if (cpu_has_fxsr) return save_i387_fxsave(buf); return save_i387_fxsave(fp); else return save_i387_fsave(buf); return save_i387_fsave(fp); } static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) Loading @@ -468,14 +525,15 @@ static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf) sizeof(struct i387_fsave_struct)); } static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf) static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf, unsigned int size) { struct task_struct *tsk = current; struct user_i387_ia32_struct env; int err; err = __copy_from_user(&tsk->thread.xstate->fxsave, &buf->_fxsr_env[0], sizeof(struct i387_fxsave_struct)); size); /* mxcsr reserved bits must be masked to zero for security reasons */ tsk->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask; if (err || __copy_from_user(&env, buf, sizeof(env))) Loading @@ -485,14 +543,69 @@ static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf) return 0; } int restore_i387_ia32(struct _fpstate_ia32 __user *buf) static int restore_i387_xsave(void __user *buf) { struct _fpx_sw_bytes fx_sw_user; struct _fpstate_ia32 __user *fx_user = ((struct _fpstate_ia32 __user *) buf); struct i387_fxsave_struct __user *fx = (struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0]; struct xsave_hdr_struct *xsave_hdr = ¤t->thread.xstate->xsave.xsave_hdr; u64 mask; int err; if (check_for_xstate(fx, buf, &fx_sw_user)) goto fx_only; mask = fx_sw_user.xstate_bv; err = restore_i387_fxsave(buf, fx_sw_user.xstate_size); xsave_hdr->xstate_bv &= pcntxt_mask; /* * These bits must be zero. */ xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0; /* * Init the state that is not present in the memory layout * and enabled by the OS. */ mask = ~(pcntxt_mask & ~mask); xsave_hdr->xstate_bv &= mask; return err; fx_only: /* * Couldn't find the extended state information in the memory * layout. Restore the FP/SSE and init the other extended state * enabled by the OS. */ xsave_hdr->xstate_bv = XSTATE_FPSSE; return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct)); } int restore_i387_xstate_ia32(void __user *buf) { int err; struct task_struct *tsk = current; struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf; if (HAVE_HWFP) 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()) { err = init_fpu(tsk); if (err) Loading @@ -500,14 +613,17 @@ int restore_i387_ia32(struct _fpstate_ia32 __user *buf) } if (HAVE_HWFP) { if (cpu_has_fxsr) err = restore_i387_fxsave(buf); if (cpu_has_xsave) err = restore_i387_xsave(buf); else if (cpu_has_fxsr) err = restore_i387_fxsave(fp, sizeof(struct i387_fxsave_struct)); else err = restore_i387_fsave(buf); err = restore_i387_fsave(fp); } else { err = fpregs_soft_set(current, NULL, 0, sizeof(struct user_i387_ia32_struct), NULL, buf) != 0; NULL, fp) != 0; } set_used_math(); Loading
arch/x86/kernel/sigframe.h +12 −2 Original line number Diff line number Diff line Loading @@ -3,9 +3,18 @@ struct sigframe { char __user *pretcode; int sig; struct sigcontext sc; struct _fpstate fpstate; /* * fpstate is unused. fpstate is moved/allocated after * retcode[] below. This movement allows to have the FP state and the * future state extensions (xsave) stay together. * And at the same time retaining the unused fpstate, prevents changing * the offset of extramask[] in the sigframe and thus prevent any * legacy application accessing/modifying it. */ struct _fpstate fpstate_unused; unsigned long extramask[_NSIG_WORDS-1]; char retcode[8]; /* fp state follows here */ }; struct rt_sigframe { Loading @@ -15,13 +24,14 @@ struct rt_sigframe { void __user *puc; struct siginfo info; struct ucontext uc; struct _fpstate fpstate; char retcode[8]; /* fp state follows here */ }; #else struct rt_sigframe { char __user *pretcode; struct ucontext uc; struct siginfo info; /* fp state follows here */ }; #endif