diff options
Diffstat (limited to 'arch/x86/ia32/ia32_signal.c')
| -rw-r--r-- | arch/x86/ia32/ia32_signal.c | 138 | 
1 files changed, 60 insertions, 78 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 20af4c79579..4bc02b23674 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -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 @@ -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)		{ 		\ @@ -206,7 +207,7 @@ struct rt_sigframe  	{ unsigned int cur;						\  	  unsigned short pre;						\  	  err |= __get_user(pre, &sc->seg);				\ -	  asm volatile("movl %%" #seg ",%0" : "=r" (cur));		\ +	  savesegment(seg, cur);					\  	  pre |= mask;							\  	  if (pre != cur) loadsegment(seg, pre); } @@ -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 */ @@ -235,7 +236,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,  	 */  	err |= __get_user(gs, &sc->gs);  	gs |= 3; -	asm("movl %%gs,%0" : "=r" (oldgs)); +	savesegment(gs, oldgs);  	if (gs != oldgs)  		load_gs_index(gs); @@ -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) @@ -350,46 +337,42 @@ badframe:   */  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; -	tmp = 0; -	__asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); +	savesegment(gs, tmp);  	err |= __put_user(tmp, (unsigned int __user *)&sc->gs); -	__asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp)); +	savesegment(fs, tmp);  	err |= __put_user(tmp, (unsigned int __user *)&sc->fs); -	__asm__("movl %%ds,%0" : "=r"(tmp): "0"(tmp)); +	savesegment(ds, tmp);  	err |= __put_user(tmp, (unsigned int __user *)&sc->ds); -	__asm__("movl %%es,%0" : "=r"(tmp): "0"(tmp)); +	savesegment(es, tmp);  	err |= __put_user(tmp, (unsigned int __user *)&sc->es); -	err |= __put_user((u32)regs->di, &sc->di); -	err |= __put_user((u32)regs->si, &sc->si); -	err |= __put_user((u32)regs->bp, &sc->bp); -	err |= __put_user((u32)regs->sp, &sc->sp); -	err |= __put_user((u32)regs->bx, &sc->bx); -	err |= __put_user((u32)regs->dx, &sc->dx); -	err |= __put_user((u32)regs->cx, &sc->cx); -	err |= __put_user((u32)regs->ax, &sc->ax); -	err |= __put_user((u32)regs->cs, &sc->cs); -	err |= __put_user((u32)regs->ss, &sc->ss); +	err |= __put_user(regs->di, &sc->di); +	err |= __put_user(regs->si, &sc->si); +	err |= __put_user(regs->bp, &sc->bp); +	err |= __put_user(regs->sp, &sc->sp); +	err |= __put_user(regs->bx, &sc->bx); +	err |= __put_user(regs->dx, &sc->dx); +	err |= __put_user(regs->cx, &sc->cx); +	err |= __put_user(regs->ax, &sc->ax); +	err |= __put_user(regs->cs, &sc->cs); +	err |= __put_user(regs->ss, &sc->ss);  	err |= __put_user(current->thread.trap_no, &sc->trapno);  	err |= __put_user(current->thread.error_code, &sc->err); -	err |= __put_user((u32)regs->ip, &sc->ip); -	err |= __put_user((u32)regs->flags, &sc->flags); -	err |= __put_user((u32)regs->sp, &sc->sp_at_signal); +	err |= __put_user(regs->ip, &sc->ip); +	err |= __put_user(regs->flags, &sc->flags); +	err |= __put_user(regs->sp, &sc->sp_at_signal); -	tmp = save_i387_ia32(fpstate); +	tmp = save_i387_xstate_ia32(fpstate);  	if (tmp < 0)  		err = -EFAULT; -	else { -		clear_used_math(); -		stts(); +	else  		err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),  					&sc->fpstate); -	}  	/* non-iBCS2 extensions.. */  	err |= __put_user(mask, &sc->oldmask); @@ -402,7 +385,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; @@ -421,6 +405,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. */ @@ -434,6 +423,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 { @@ -448,25 +438,21 @@ 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; +		return -EFAULT; -	err |= __put_user(sig, &frame->sig); -	if (err) -		goto give_sigsegv; +	if (__put_user(sig, &frame->sig)) +		return -EFAULT; -	err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs, -					set->sig[0]); -	if (err) -		goto give_sigsegv; +	if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0])) +		return -EFAULT;  	if (_COMPAT_NSIG_WORDS > 1) { -		err |= __copy_to_user(frame->extramask, &set->sig[1], -				      sizeof(frame->extramask)); -		if (err) -			goto give_sigsegv; +		if (__copy_to_user(frame->extramask, &set->sig[1], +				   sizeof(frame->extramask))) +			return -EFAULT;  	}  	if (ka->sa.sa_flags & SA_RESTORER) { @@ -487,7 +473,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,  	 */  	err |= __copy_to_user(frame->retcode, &code, 8);  	if (err) -		goto give_sigsegv; +		return -EFAULT;  	/* Set up registers for signal handler */  	regs->sp = (unsigned long) frame; @@ -498,8 +484,8 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,  	regs->dx = 0;  	regs->cx = 0; -	asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); -	asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); +	loadsegment(ds, __USER32_DS); +	loadsegment(es, __USER32_DS);  	regs->cs = __USER32_CS;  	regs->ss = __USER32_DS; @@ -510,10 +496,6 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,  #endif  	return 0; - -give_sigsegv: -	force_sigsegv(sig, current); -	return -EFAULT;  }  int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, @@ -522,6 +504,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 { @@ -537,30 +520,33 @@ 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; +		return -EFAULT;  	err |= __put_user(sig, &frame->sig);  	err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo);  	err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc);  	err |= copy_siginfo_to_user32(&frame->info, info);  	if (err) -		goto give_sigsegv; +		return -EFAULT;  	/* Create the ucontext.  */ -	err |= __put_user(0, &frame->uc.uc_flags); +	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) -		goto give_sigsegv; +		return -EFAULT;  	if (ka->sa.sa_flags & SA_RESTORER)  		restorer = ka->sa.sa_restorer; @@ -575,7 +561,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	 */  	err |= __copy_to_user(frame->retcode, &code, 8);  	if (err) -		goto give_sigsegv; +		return -EFAULT;  	/* Set up registers for signal handler */  	regs->sp = (unsigned long) frame; @@ -591,8 +577,8 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	regs->dx = (unsigned long) &frame->info;  	regs->cx = (unsigned long) &frame->uc; -	asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); -	asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); +	loadsegment(ds, __USER32_DS); +	loadsegment(es, __USER32_DS);  	regs->cs = __USER32_CS;  	regs->ss = __USER32_DS; @@ -603,8 +589,4 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  #endif  	return 0; - -give_sigsegv: -	force_sigsegv(sig, current); -	return -EFAULT;  }  | 
