From: H. Peter Anvin Date: Sat, 22 Sep 2012 00:18:44 +0000 (-0700) Subject: Merge branch 'x86/fpu' into x86/smap X-Git-Tag: v3.7-rc2~9^2~10 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=49b8c695e331c9685e6ffdbf34872509d77c8459;p=platform%2Fkernel%2Flinux-exynos.git Merge branch 'x86/fpu' into x86/smap Reason for merge: x86/fpu changed the structure of some of the code that x86/smap changes; mostly fpu-internal.h but also minor changes to the signal code. Signed-off-by: H. Peter Anvin Resolved Conflicts: arch/x86/ia32/ia32_signal.c arch/x86/include/asm/fpu-internal.h arch/x86/kernel/signal.c --- 49b8c695e331c9685e6ffdbf34872509d77c8459 diff --cc arch/x86/ia32/ia32_signal.c index 05e62a3,8c77c64..efc6a95 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@@ -32,6 -32,6 +32,7 @@@ #include #include #include ++#include #define FIX_EFLAGS __FIX_EFLAGS @@@ -254,8 -256,6 +256,8 @@@ static int ia32_restore_sigcontext(stru get_user_ex(*pax, &sc->ax); } get_user_catch(err); - err |= restore_i387_xstate_ia32(buf); ++ err |= restore_xstate_sig(buf, 1); + return err; } @@@ -526,14 -533,9 +531,14 @@@ int ia32_setup_rt_frame(int sig, struc * Not actually used anymore, but left because some gdb * versions need it. */ - put_user_ex(*((u64 *)&code), (u64 *)frame->retcode); + put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode); } put_user_catch(err); + err |= copy_siginfo_to_user32(&frame->info, info); + 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) return -EFAULT; diff --cc arch/x86/include/asm/fpu-internal.h index 0fe1358,92f3c6e..409b9cc --- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h @@@ -20,9 -21,24 +21,25 @@@ #include #include #include ++#include - extern unsigned int sig_xstate_size; + #ifdef CONFIG_X86_64 + # include + # include + int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + compat_sigset_t *set, struct pt_regs *regs); + int ia32_setup_frame(int sig, struct k_sigaction *ka, + compat_sigset_t *set, struct pt_regs *regs); + #else + # define user_i387_ia32_struct user_i387_struct + # define user32_fxsr_struct user_fxsr_struct + # define ia32_setup_frame __setup_frame + # define ia32_setup_rt_frame __setup_rt_frame + #endif + + extern unsigned int mxcsr_feature_mask; extern void fpu_init(void); + extern void eager_fpu_init(void); DECLARE_PER_CPU(struct task_struct *, fpu_owner_task); @@@ -81,123 -121,52 +122,68 @@@ static inline void sanitize_i387_state( __sanitize_i387_state(tsk); } - #ifdef CONFIG_X86_64 - static inline int fxrstor_checking(struct i387_fxsave_struct *fx) - { - int err; - - /* See comment in fxsave() below. */ - #ifdef CONFIG_AS_FXSAVEQ - asm volatile("1: fxrstorq %[fx]\n\t" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl $-1,%[err]\n" - " jmp 2b\n" - ".previous\n" - _ASM_EXTABLE(1b, 3b) - : [err] "=r" (err) - : [fx] "m" (*fx), "0" (0)); - #else - asm volatile("1: rex64/fxrstor (%[fx])\n\t" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl $-1,%[err]\n" - " jmp 2b\n" - ".previous\n" - _ASM_EXTABLE(1b, 3b) - : [err] "=r" (err) - : [fx] "R" (fx), "m" (*fx), "0" (0)); - #endif - return err; ++#define user_insn(insn, output, input...) \ ++({ \ ++ int err; \ ++ asm volatile(ASM_STAC "\n" \ ++ "1:" #insn "\n\t" \ ++ "2: " ASM_CLAC "\n" \ ++ ".section .fixup,\"ax\"\n" \ ++ "3: movl $-1,%[err]\n" \ ++ " jmp 2b\n" \ ++ ".previous\n" \ ++ _ASM_EXTABLE(1b, 3b) \ ++ : [err] "=r" (err), output \ ++ : "0"(0), input); \ ++ err; \ ++}) ++ + #define check_insn(insn, output, input...) \ + ({ \ + int err; \ + asm volatile("1:" #insn "\n\t" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl $-1,%[err]\n" \ + " jmp 2b\n" \ + ".previous\n" \ + _ASM_EXTABLE(1b, 3b) \ + : [err] "=r" (err), output \ + : "0"(0), input); \ + err; \ + }) + + static inline int fsave_user(struct i387_fsave_struct __user *fx) + { - return check_insn(fnsave %[fx]; fwait, [fx] "=m" (*fx), "m" (*fx)); ++ return user_insn(fnsave %[fx]; fwait, [fx] "=m" (*fx), "m" (*fx)); } static inline int fxsave_user(struct i387_fxsave_struct __user *fx) { - int err; + if (config_enabled(CONFIG_X86_32)) - return check_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx)); ++ return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx)); + else if (config_enabled(CONFIG_AS_FXSAVEQ)) - return check_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx)); ++ return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx)); - /* - * Clear the bytes not touched by the fxsave and reserved - * for the SW usage. - */ - err = __clear_user(&fx->sw_reserved, - sizeof(struct _fpx_sw_bytes)); - if (unlikely(err)) - return -EFAULT; - - /* See comment in fxsave() below. */ - #ifdef CONFIG_AS_FXSAVEQ - asm volatile(ASM_STAC "\n" - "1: fxsaveq %[fx]\n\t" - "2: " ASM_CLAC "\n" - ".section .fixup,\"ax\"\n" - "3: movl $-1,%[err]\n" - " jmp 2b\n" - ".previous\n" - _ASM_EXTABLE(1b, 3b) - : [err] "=r" (err), [fx] "=m" (*fx) - : "0" (0)); - #else - asm volatile(ASM_STAC "\n" - "1: rex64/fxsave (%[fx])\n\t" - "2: " ASM_CLAC "\n" - ".section .fixup,\"ax\"\n" - "3: movl $-1,%[err]\n" - " jmp 2b\n" - ".previous\n" - _ASM_EXTABLE(1b, 3b) - : [err] "=r" (err), "=m" (*fx) - : [fx] "R" (fx), "0" (0)); - #endif - if (unlikely(err) && - __clear_user(fx, sizeof(struct i387_fxsave_struct))) - err = -EFAULT; - /* No need to clear here because the caller clears USED_MATH */ - return err; + /* See comment in fpu_fxsave() below. */ - return check_insn(rex64/fxsave (%[fx]), "=m" (*fx), [fx] "R" (fx)); ++ return user_insn(rex64/fxsave (%[fx]), "=m" (*fx), [fx] "R" (fx)); } - static inline void fpu_fxsave(struct fpu *fpu) + static inline int fxrstor_checking(struct i387_fxsave_struct *fx) { - /* Using "rex64; fxsave %0" is broken because, if the memory operand - uses any extended registers for addressing, a second REX prefix - will be generated (to the assembler, rex64 followed by semicolon - is a separate instruction), and hence the 64-bitness is lost. */ + if (config_enabled(CONFIG_X86_32)) + return check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); + else if (config_enabled(CONFIG_AS_FXSAVEQ)) + return check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); - #ifdef CONFIG_AS_FXSAVEQ - /* Using "fxsaveq %0" would be the ideal choice, but is only supported - starting with gas 2.16. */ - __asm__ __volatile__("fxsaveq %0" - : "=m" (fpu->state->fxsave)); - #else - /* Using, as a workaround, the properly prefixed form below isn't - accepted by any binutils version so far released, complaining that - the same type of prefix is used twice if an extended register is - needed for addressing (fix submitted to mainline 2005-11-21). - asm volatile("rex64/fxsave %0" - : "=m" (fpu->state->fxsave)); - This, however, we can work around by forcing the compiler to select - an addressing mode that doesn't require extended registers. */ - asm volatile("rex64/fxsave (%[fx])" - : "=m" (fpu->state->fxsave) - : [fx] "R" (&fpu->state->fxsave)); - #endif + /* See comment in fpu_fxsave() below. */ + return check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx), + "m" (*fx)); } - #else /* CONFIG_X86_32 */ - - /* perform fxrstor iff the processor has extended states, otherwise frstor */ - static inline int fxrstor_checking(struct i387_fxsave_struct *fx) + static inline int frstor_checking(struct i387_fsave_struct *fx) { - /* - * The "nop" is needed to make the instructions the same - * length. - */ - alternative_input( - "nop ; frstor %1", - "fxrstor %1", - X86_FEATURE_FXSR, - "m" (*fx)); - - return 0; + return check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); } static inline void fpu_fxsave(struct fpu *fpu) diff --cc arch/x86/kernel/signal.c index 9326128,e10f96a..036bddb --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@@ -118,8 -119,6 +118,8 @@@ int restore_sigcontext(struct pt_regs * get_user_ex(*pax, &sc->ax); } get_user_catch(err); - err |= restore_i387_xstate(buf); ++ err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32)); + return err; } @@@ -385,11 -386,6 +383,11 @@@ static int __setup_rt_frame(int sig, st */ put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode); } put_user_catch(err); - ++ + err |= copy_siginfo_to_user(&frame->info, info); + err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, + regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) return -EFAULT; @@@ -477,6 -472,74 +475,75 @@@ static int __setup_rt_frame(int sig, st } #endif /* CONFIG_X86_32 */ + static int x32_setup_rt_frame(int sig, struct k_sigaction *ka, + siginfo_t *info, compat_sigset_t *set, + struct pt_regs *regs) + { + #ifdef CONFIG_X86_X32_ABI + struct rt_sigframe_x32 __user *frame; + void __user *restorer; + int err = 0; + void __user *fpstate = NULL; + + frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + return -EFAULT; + + if (ka->sa.sa_flags & SA_SIGINFO) { + if (copy_siginfo_to_user32(&frame->info, info)) + return -EFAULT; + } + + put_user_try { + /* Create the ucontext. */ + if (cpu_has_xsave) + put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); + else + put_user_ex(0, &frame->uc.uc_flags); + put_user_ex(0, &frame->uc.uc_link); + put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + put_user_ex(sas_ss_flags(regs->sp), + &frame->uc.uc_stack.ss_flags); + put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + put_user_ex(0, &frame->uc.uc__pad0); - err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, - regs, set->sig[0]); - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + if (ka->sa.sa_flags & SA_RESTORER) { + restorer = ka->sa.sa_restorer; + } else { + /* could use a vstub here */ + restorer = NULL; + err |= -EFAULT; + } + put_user_ex(restorer, &frame->pretcode); + } put_user_catch(err); + ++ err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, ++ regs, set->sig[0]); ++ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); ++ + if (err) + return -EFAULT; + + /* Set up registers for signal handler */ + regs->sp = (unsigned long) frame; + regs->ip = (unsigned long) ka->sa.sa_handler; + + /* We use the x32 calling convention here... */ + regs->di = sig; + regs->si = (unsigned long) &frame->info; + regs->dx = (unsigned long) &frame->uc; + + loadsegment(ds, __USER_DS); + loadsegment(es, __USER_DS); + + regs->cs = __USER_CS; + regs->ss = __USER_DS; + #endif /* CONFIG_X86_X32_ABI */ + + return 0; + } + #ifdef CONFIG_X86_32 /* * Atomically swap in the new signal mask, and wait for a signal.