diff options
Diffstat (limited to 'arch/powerpc/kernel/signal_32.c')
| -rw-r--r-- | arch/powerpc/kernel/signal_32.c | 729 | 
1 files changed, 484 insertions, 245 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 804e323c139..95068bf569a 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -43,6 +43,7 @@  #include <asm/sigcontext.h>  #include <asm/vdso.h>  #include <asm/switch_to.h> +#include <asm/tm.h>  #ifdef CONFIG_PPC64  #include "ppc32.h"  #include <asm/unistd.h> @@ -56,10 +57,7 @@  #undef DEBUG_SIG  #ifdef CONFIG_PPC64 -#define sys_sigsuspend	compat_sys_sigsuspend -#define sys_rt_sigsuspend	compat_sys_rt_sigsuspend  #define sys_rt_sigreturn	compat_sys_rt_sigreturn -#define sys_sigaction	compat_sys_sigaction  #define sys_swapcontext	compat_sys_swapcontext  #define sys_sigreturn	compat_sys_sigreturn @@ -68,6 +66,8 @@  #define mcontext	mcontext32  #define ucontext	ucontext32 +#define __save_altstack __compat_save_altstack +  /*   * Userspace code may pass a ucontext which doesn't include VSX added   * at the end.  We need to check for this case. @@ -130,23 +130,6 @@ static inline int get_sigset_t(sigset_t *set,  	return 0;  } -static inline int get_old_sigaction(struct k_sigaction *new_ka, -		struct old_sigaction __user *act) -{ -	compat_old_sigset_t mask; -	compat_uptr_t handler, restorer; - -	if (get_user(handler, &act->sa_handler) || -	    __get_user(restorer, &act->sa_restorer) || -	    __get_user(new_ka->sa.sa_flags, &act->sa_flags) || -	    __get_user(mask, &act->sa_mask)) -		return -EFAULT; -	new_ka->sa.sa_handler = compat_ptr(handler); -	new_ka->sa.sa_restorer = compat_ptr(restorer); -	siginitset(&new_ka->sa.sa_mask, mask); -	return 0; -} -  #define to_user_ptr(p)		ptr_to_compat(p)  #define from_user_ptr(p)	compat_ptr(p) @@ -196,21 +179,6 @@ static inline int get_sigset_t(sigset_t *set, const sigset_t __user *uset)  	return copy_from_user(set, uset, sizeof(*uset));  } -static inline int get_old_sigaction(struct k_sigaction *new_ka, -		struct old_sigaction __user *act) -{ -	old_sigset_t mask; - -	if (!access_ok(VERIFY_READ, act, sizeof(*act)) || -			__get_user(new_ka->sa.sa_handler, &act->sa_handler) || -			__get_user(new_ka->sa.sa_restorer, &act->sa_restorer) || -			__get_user(new_ka->sa.sa_flags, &act->sa_flags) || -			__get_user(mask, &act->sa_mask)) -		return -EFAULT; -	siginitset(&new_ka->sa.sa_mask, mask); -	return 0; -} -  #define to_user_ptr(p)		((unsigned long)(p))  #define from_user_ptr(p)	((void __user *)(p)) @@ -234,50 +202,8 @@ static inline int restore_general_regs(struct pt_regs *regs,  		return -EFAULT;  	return 0;  } - -#endif /* CONFIG_PPC64 */ - -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -long sys_sigsuspend(old_sigset_t mask) -{ -	sigset_t blocked; -	siginitset(&blocked, mask); -	return sigsuspend(&blocked); -} - -long sys_sigaction(int sig, struct old_sigaction __user *act, -		struct old_sigaction __user *oact) -{ -	struct k_sigaction new_ka, old_ka; -	int ret; - -#ifdef CONFIG_PPC64 -	if (sig < 0) -		sig = -sig;  #endif -	if (act) { -		if (get_old_sigaction(&new_ka, act)) -			return -EFAULT; -	} - -	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); -	if (!ret && oact) { -		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || -		    __put_user(to_user_ptr(old_ka.sa.sa_handler), -			    &oact->sa_handler) || -		    __put_user(to_user_ptr(old_ka.sa.sa_restorer), -			    &oact->sa_restorer) || -		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || -		    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) -			return -EFAULT; -	} - -	return ret; -} -  /*   * When we have signals to deliver, we set up on the   * user stack, going down from the original stack pointer: @@ -293,6 +219,10 @@ long sys_sigaction(int sig, struct old_sigaction __user *act,  struct sigframe {  	struct sigcontext sctx;		/* the sigcontext */  	struct mcontext	mctx;		/* all the register values */ +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +	struct sigcontext sctx_transact; +	struct mcontext	mctx_transact; +#endif  	/*  	 * Programs using the rs6000/xcoff abi can save up to 19 gp  	 * regs and 18 fp regs below sp before decrementing it. @@ -321,6 +251,9 @@ struct rt_sigframe {  	struct siginfo info;  #endif  	struct ucontext	uc; +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +	struct ucontext	uc_transact; +#endif  	/*  	 * Programs using the rs6000/xcoff abi can save up to 19 gp  	 * regs and 18 fp regs below sp before decrementing it. @@ -381,6 +314,61 @@ unsigned long copy_vsx_from_user(struct task_struct *task,  		task->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];  	return 0;  } + +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +unsigned long copy_transact_fpr_to_user(void __user *to, +				  struct task_struct *task) +{ +	double buf[ELF_NFPREG]; +	int i; + +	/* save FPR copy to local buffer then write to the thread_struct */ +	for (i = 0; i < (ELF_NFPREG - 1) ; i++) +		buf[i] = task->thread.TS_TRANS_FPR(i); +	memcpy(&buf[i], &task->thread.transact_fpscr, sizeof(double)); +	return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double)); +} + +unsigned long copy_transact_fpr_from_user(struct task_struct *task, +					  void __user *from) +{ +	double buf[ELF_NFPREG]; +	int i; + +	if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double))) +		return 1; +	for (i = 0; i < (ELF_NFPREG - 1) ; i++) +		task->thread.TS_TRANS_FPR(i) = buf[i]; +	memcpy(&task->thread.transact_fpscr, &buf[i], sizeof(double)); + +	return 0; +} + +unsigned long copy_transact_vsx_to_user(void __user *to, +				  struct task_struct *task) +{ +	double buf[ELF_NVSRHALFREG]; +	int i; + +	/* save FPR copy to local buffer then write to the thread_struct */ +	for (i = 0; i < ELF_NVSRHALFREG; i++) +		buf[i] = task->thread.transact_fpr[i][TS_VSRLOWOFFSET]; +	return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double)); +} + +unsigned long copy_transact_vsx_from_user(struct task_struct *task, +					  void __user *from) +{ +	double buf[ELF_NVSRHALFREG]; +	int i; + +	if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double))) +		return 1; +	for (i = 0; i < ELF_NVSRHALFREG ; i++) +		task->thread.transact_fpr[i][TS_VSRLOWOFFSET] = buf[i]; +	return 0; +} +#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */  #else  inline unsigned long copy_fpr_to_user(void __user *to,  				      struct task_struct *task) @@ -395,6 +383,22 @@ inline unsigned long copy_fpr_from_user(struct task_struct *task,  	return __copy_from_user(task->thread.fpr, from,  			      ELF_NFPREG * sizeof(double));  } + +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +inline unsigned long copy_transact_fpr_to_user(void __user *to, +					 struct task_struct *task) +{ +	return __copy_to_user(to, task->thread.transact_fpr, +			      ELF_NFPREG * sizeof(double)); +} + +inline unsigned long copy_transact_fpr_from_user(struct task_struct *task, +						 void __user *from) +{ +	return __copy_from_user(task->thread.transact_fpr, from, +				ELF_NFPREG * sizeof(double)); +} +#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */  #endif  /* @@ -483,6 +487,156 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,  	return 0;  } +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +/* + * Save the current user registers on the user stack. + * We only save the altivec/spe registers if the process has used + * altivec/spe instructions at some point. + * We also save the transactional registers to a second ucontext in the + * frame. + * + * See save_user_regs() and signal_64.c:setup_tm_sigcontexts(). + */ +static int save_tm_user_regs(struct pt_regs *regs, +			     struct mcontext __user *frame, +			     struct mcontext __user *tm_frame, int sigret) +{ +	unsigned long msr = regs->msr; + +	/* tm_reclaim rolls back all reg states, updating thread.ckpt_regs, +	 * thread.transact_fpr[], thread.transact_vr[], etc. +	 */ +	tm_enable(); +	tm_reclaim(¤t->thread, msr, TM_CAUSE_SIGNAL); + +	/* Make sure floating point registers are stored in regs */ +	flush_fp_to_thread(current); + +	/* Save both sets of general registers */ +	if (save_general_regs(¤t->thread.ckpt_regs, frame) +	    || save_general_regs(regs, tm_frame)) +		return 1; + +	/* Stash the top half of the 64bit MSR into the 32bit MSR word +	 * of the transactional mcontext.  This way we have a backward-compatible +	 * MSR in the 'normal' (checkpointed) mcontext and additionally one can +	 * also look at what type of transaction (T or S) was active at the +	 * time of the signal. +	 */ +	if (__put_user((msr >> 32), &tm_frame->mc_gregs[PT_MSR])) +		return 1; + +#ifdef CONFIG_ALTIVEC +	/* save altivec registers */ +	if (current->thread.used_vr) { +		flush_altivec_to_thread(current); +		if (__copy_to_user(&frame->mc_vregs, current->thread.vr, +				   ELF_NVRREG * sizeof(vector128))) +			return 1; +		if (msr & MSR_VEC) { +			if (__copy_to_user(&tm_frame->mc_vregs, +					   current->thread.transact_vr, +					   ELF_NVRREG * sizeof(vector128))) +				return 1; +		} else { +			if (__copy_to_user(&tm_frame->mc_vregs, +					   current->thread.vr, +					   ELF_NVRREG * sizeof(vector128))) +				return 1; +		} + +		/* set MSR_VEC in the saved MSR value to indicate that +		 * frame->mc_vregs contains valid data +		 */ +		msr |= MSR_VEC; +	} + +	/* We always copy to/from vrsave, it's 0 if we don't have or don't +	 * use altivec. Since VSCR only contains 32 bits saved in the least +	 * significant bits of a vector, we "cheat" and stuff VRSAVE in the +	 * most significant bits of that same vector. --BenH +	 */ +	if (__put_user(current->thread.vrsave, +		       (u32 __user *)&frame->mc_vregs[32])) +		return 1; +	if (msr & MSR_VEC) { +		if (__put_user(current->thread.transact_vrsave, +			       (u32 __user *)&tm_frame->mc_vregs[32])) +			return 1; +	} else { +		if (__put_user(current->thread.vrsave, +			       (u32 __user *)&tm_frame->mc_vregs[32])) +			return 1; +	} +#endif /* CONFIG_ALTIVEC */ + +	if (copy_fpr_to_user(&frame->mc_fregs, current)) +		return 1; +	if (msr & MSR_FP) { +		if (copy_transact_fpr_to_user(&tm_frame->mc_fregs, current)) +			return 1; +	} else { +		if (copy_fpr_to_user(&tm_frame->mc_fregs, current)) +			return 1; +	} + +#ifdef CONFIG_VSX +	/* +	 * Copy VSR 0-31 upper half from thread_struct to local +	 * buffer, then write that to userspace.  Also set MSR_VSX in +	 * the saved MSR value to indicate that frame->mc_vregs +	 * contains valid data +	 */ +	if (current->thread.used_vsr) { +		__giveup_vsx(current); +		if (copy_vsx_to_user(&frame->mc_vsregs, current)) +			return 1; +		if (msr & MSR_VSX) { +			if (copy_transact_vsx_to_user(&tm_frame->mc_vsregs, +						      current)) +				return 1; +		} else { +			if (copy_vsx_to_user(&tm_frame->mc_vsregs, current)) +				return 1; +		} + +		msr |= MSR_VSX; +	} +#endif /* CONFIG_VSX */ +#ifdef CONFIG_SPE +	/* SPE regs are not checkpointed with TM, so this section is +	 * simply the same as in save_user_regs(). +	 */ +	if (current->thread.used_spe) { +		flush_spe_to_thread(current); +		if (__copy_to_user(&frame->mc_vregs, current->thread.evr, +				   ELF_NEVRREG * sizeof(u32))) +			return 1; +		/* set MSR_SPE in the saved MSR value to indicate that +		 * frame->mc_vregs contains valid data */ +		msr |= MSR_SPE; +	} + +	/* We always copy to/from spefscr */ +	if (__put_user(current->thread.spefscr, (u32 __user *)&frame->mc_vregs + ELF_NEVRREG)) +		return 1; +#endif /* CONFIG_SPE */ + +	if (__put_user(msr, &frame->mc_gregs[PT_MSR])) +		return 1; +	if (sigret) { +		/* Set up the sigreturn trampoline: li r0,sigret; sc */ +		if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) +		    || __put_user(0x44000002UL, &frame->tramp[1])) +			return 1; +		flush_icache_range((unsigned long) &frame->tramp[0], +				   (unsigned long) &frame->tramp[2]); +	} + +	return 0; +} +#endif +  /*   * Restore the current user register values from the user stack,   * (except for MSR). @@ -588,90 +742,142 @@ static long restore_user_regs(struct pt_regs *regs,  	return 0;  } -#ifdef CONFIG_PPC64 -long compat_sys_rt_sigaction(int sig, const struct sigaction32 __user *act, -		struct sigaction32 __user *oact, size_t sigsetsize) +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +/* + * Restore the current user register values from the user stack, except for + * MSR, and recheckpoint the original checkpointed register state for processes + * in transactions. + */ +static long restore_tm_user_regs(struct pt_regs *regs, +				 struct mcontext __user *sr, +				 struct mcontext __user *tm_sr)  { -	struct k_sigaction new_ka, old_ka; -	int ret; +	long err; +	unsigned long msr; +#ifdef CONFIG_VSX +	int i; +#endif -	/* XXX: Don't preclude handling different sized sigset_t's.  */ -	if (sigsetsize != sizeof(compat_sigset_t)) -		return -EINVAL; +	/* +	 * restore general registers but not including MSR or SOFTE. Also +	 * take care of keeping r2 (TLS) intact if not a signal. +	 * See comment in signal_64.c:restore_tm_sigcontexts(); +	 * TFHAR is restored from the checkpointed NIP; TEXASR and TFIAR +	 * were set by the signal delivery. +	 */ +	err = restore_general_regs(regs, tm_sr); +	err |= restore_general_regs(¤t->thread.ckpt_regs, sr); -	if (act) { -		compat_uptr_t handler; +	err |= __get_user(current->thread.tm_tfhar, &sr->mc_gregs[PT_NIP]); -		ret = get_user(handler, &act->sa_handler); -		new_ka.sa.sa_handler = compat_ptr(handler); -		ret |= get_sigset_t(&new_ka.sa.sa_mask, &act->sa_mask); -		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); -		if (ret) -			return -EFAULT; -	} +	err |= __get_user(msr, &sr->mc_gregs[PT_MSR]); +	if (err) +		return 1; -	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); -	if (!ret && oact) { -		ret = put_user(to_user_ptr(old_ka.sa.sa_handler), &oact->sa_handler); -		ret |= put_sigset_t(&oact->sa_mask, &old_ka.sa.sa_mask); -		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); -	} -	return ret; -} +	/* Restore the previous little-endian mode */ +	regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE); -/* - * Note: it is necessary to treat how as an unsigned int, with the - * corresponding cast to a signed int to insure that the proper - * conversion (sign extension) between the register representation - * of a signed int (msr in 32-bit mode) and the register representation - * of a signed int (msr in 64-bit mode) is performed. - */ -long compat_sys_rt_sigprocmask(u32 how, compat_sigset_t __user *set, -		compat_sigset_t __user *oset, size_t sigsetsize) -{ -	sigset_t s; -	sigset_t __user *up; -	int ret; -	mm_segment_t old_fs = get_fs(); +	/* +	 * Do this before updating the thread state in +	 * current->thread.fpr/vr/evr.  That way, if we get preempted +	 * and another task grabs the FPU/Altivec/SPE, it won't be +	 * tempted to save the current CPU state into the thread_struct +	 * and corrupt what we are writing there. +	 */ +	discard_lazy_cpu_state(); -	if (set) { -		if (get_sigset_t(&s, set)) -			return -EFAULT; +#ifdef CONFIG_ALTIVEC +	regs->msr &= ~MSR_VEC; +	if (msr & MSR_VEC) { +		/* restore altivec registers from the stack */ +		if (__copy_from_user(current->thread.vr, &sr->mc_vregs, +				     sizeof(sr->mc_vregs)) || +		    __copy_from_user(current->thread.transact_vr, +				     &tm_sr->mc_vregs, +				     sizeof(sr->mc_vregs))) +			return 1; +	} else if (current->thread.used_vr) { +		memset(current->thread.vr, 0, ELF_NVRREG * sizeof(vector128)); +		memset(current->thread.transact_vr, 0, +		       ELF_NVRREG * sizeof(vector128));  	} -	set_fs(KERNEL_DS); -	/* This is valid because of the set_fs() */ -	up = (sigset_t __user *) &s; -	ret = sys_rt_sigprocmask((int)how, set ? up : NULL, oset ? up : NULL, -				 sigsetsize); -	set_fs(old_fs); -	if (ret) -		return ret; -	if (oset) { -		if (put_sigset_t(oset, &s)) -			return -EFAULT; -	} -	return 0; -} +	/* Always get VRSAVE back */ +	if (__get_user(current->thread.vrsave, +		       (u32 __user *)&sr->mc_vregs[32]) || +	    __get_user(current->thread.transact_vrsave, +		       (u32 __user *)&tm_sr->mc_vregs[32])) +		return 1; +#endif /* CONFIG_ALTIVEC */ -long compat_sys_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize) -{ -	sigset_t s; -	int ret; -	mm_segment_t old_fs = get_fs(); +	regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1); -	set_fs(KERNEL_DS); -	/* The __user pointer cast is valid because of the set_fs() */ -	ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize); -	set_fs(old_fs); -	if (!ret) { -		if (put_sigset_t(set, &s)) -			return -EFAULT; +	if (copy_fpr_from_user(current, &sr->mc_fregs) || +	    copy_transact_fpr_from_user(current, &tm_sr->mc_fregs)) +		return 1; + +#ifdef CONFIG_VSX +	regs->msr &= ~MSR_VSX; +	if (msr & MSR_VSX) { +		/* +		 * Restore altivec registers from the stack to a local +		 * buffer, then write this out to the thread_struct +		 */ +		if (copy_vsx_from_user(current, &sr->mc_vsregs) || +		    copy_transact_vsx_from_user(current, &tm_sr->mc_vsregs)) +			return 1; +	} else if (current->thread.used_vsr) +		for (i = 0; i < 32 ; i++) { +			current->thread.fpr[i][TS_VSRLOWOFFSET] = 0; +			current->thread.transact_fpr[i][TS_VSRLOWOFFSET] = 0; +		} +#endif /* CONFIG_VSX */ + +#ifdef CONFIG_SPE +	/* SPE regs are not checkpointed with TM, so this section is +	 * simply the same as in restore_user_regs(). +	 */ +	regs->msr &= ~MSR_SPE; +	if (msr & MSR_SPE) { +		if (__copy_from_user(current->thread.evr, &sr->mc_vregs, +				     ELF_NEVRREG * sizeof(u32))) +			return 1; +	} else if (current->thread.used_spe) +		memset(current->thread.evr, 0, ELF_NEVRREG * sizeof(u32)); + +	/* Always get SPEFSCR back */ +	if (__get_user(current->thread.spefscr, (u32 __user *)&sr->mc_vregs +		       + ELF_NEVRREG)) +		return 1; +#endif /* CONFIG_SPE */ + +	/* Now, recheckpoint.  This loads up all of the checkpointed (older) +	 * registers, including FP and V[S]Rs.  After recheckpointing, the +	 * transactional versions should be loaded. +	 */ +	tm_enable(); +	/* This loads the checkpointed FP/VEC state, if used */ +	tm_recheckpoint(¤t->thread, msr); +	/* The task has moved into TM state S, so ensure MSR reflects this */ +	regs->msr = (regs->msr & ~MSR_TS_MASK) | MSR_TS_S; + +	/* This loads the speculative FP/VEC state, if used */ +	if (msr & MSR_FP) { +		do_load_up_transact_fpu(¤t->thread); +		regs->msr |= (MSR_FP | current->thread.fpexc_mode);  	} -	return ret; -} +#ifdef CONFIG_ALTIVEC +	if (msr & MSR_VEC) { +		do_load_up_transact_altivec(¤t->thread); +		regs->msr |= MSR_VEC; +	} +#endif +	return 0; +} +#endif +#ifdef CONFIG_PPC64  int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s)  {  	int err; @@ -740,79 +946,6 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)  	return 0;  } - -/* - * Note: it is necessary to treat pid and sig as unsigned ints, with the - * corresponding cast to a signed int to insure that the proper conversion - * (sign extension) between the register representation of a signed int - * (msr in 32-bit mode) and the register representation of a signed int - * (msr in 64-bit mode) is performed. - */ -long compat_sys_rt_sigqueueinfo(u32 pid, u32 sig, compat_siginfo_t __user *uinfo) -{ -	siginfo_t info; -	int ret; -	mm_segment_t old_fs = get_fs(); - -	ret = copy_siginfo_from_user32(&info, uinfo); -	if (unlikely(ret)) -		return ret; - -	set_fs (KERNEL_DS); -	/* The __user pointer cast is valid becasuse of the set_fs() */ -	ret = sys_rt_sigqueueinfo((int)pid, (int)sig, (siginfo_t __user *) &info); -	set_fs (old_fs); -	return ret; -} -/* - *  Start Alternate signal stack support - * - *  System Calls - *       sigaltatck               compat_sys_sigaltstack - */ - -int compat_sys_sigaltstack(u32 __new, u32 __old, int r5, -		      int r6, int r7, int r8, struct pt_regs *regs) -{ -	stack_32_t __user * newstack = compat_ptr(__new); -	stack_32_t __user * oldstack = compat_ptr(__old); -	stack_t uss, uoss; -	int ret; -	mm_segment_t old_fs; -	unsigned long sp; -	compat_uptr_t ss_sp; - -	/* -	 * set sp to the user stack on entry to the system call -	 * the system call router sets R9 to the saved registers -	 */ -	sp = regs->gpr[1]; - -	/* Put new stack info in local 64 bit stack struct */ -	if (newstack) { -		if (get_user(ss_sp, &newstack->ss_sp) || -		    __get_user(uss.ss_flags, &newstack->ss_flags) || -		    __get_user(uss.ss_size, &newstack->ss_size)) -			return -EFAULT; -		uss.ss_sp = compat_ptr(ss_sp); -	} - -	old_fs = get_fs(); -	set_fs(KERNEL_DS); -	/* The __user pointer casts are valid because of the set_fs() */ -	ret = do_sigaltstack( -		newstack ? (stack_t __user *) &uss : NULL, -		oldstack ? (stack_t __user *) &uoss : NULL, -		sp); -	set_fs(old_fs); -	/* Copy the stack information to the user output buffer */ -	if (!ret && oldstack  && -		(put_user(ptr_to_compat(uoss.ss_sp), &oldstack->ss_sp) || -		 __put_user(uoss.ss_flags, &oldstack->ss_flags) || -		 __put_user(uoss.ss_size, &oldstack->ss_size))) -		return -EFAULT; -	return ret; -}  #endif /* CONFIG_PPC64 */  /* @@ -827,6 +960,8 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,  	struct mcontext __user *frame;  	void __user *addr;  	unsigned long newsp = 0; +	int sigret; +	unsigned long tramp;  	/* Set up Signal Frame */  	/* Put a Real Time Context onto stack */ @@ -838,11 +973,7 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,  	/* Put the siginfo & fill in most of the ucontext */  	if (copy_siginfo_to_user(&rt_sf->info, info)  	    || __put_user(0, &rt_sf->uc.uc_flags) -	    || __put_user(0, &rt_sf->uc.uc_link) -	    || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp) -	    || __put_user(sas_ss_flags(regs->gpr[1]), -			  &rt_sf->uc.uc_stack.ss_flags) -	    || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size) +	    || __save_altstack(&rt_sf->uc.uc_stack, regs->gpr[1])  	    || __put_user(to_user_ptr(&rt_sf->uc.uc_mcontext),  		    &rt_sf->uc.uc_regs)  	    || put_sigset_t(&rt_sf->uc.uc_sigmask, oldset)) @@ -852,14 +983,37 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,  	frame = &rt_sf->uc.uc_mcontext;  	addr = frame;  	if (vdso32_rt_sigtramp && current->mm->context.vdso_base) { -		if (save_user_regs(regs, frame, 0, 1)) -			goto badframe; -		regs->link = current->mm->context.vdso_base + vdso32_rt_sigtramp; +		sigret = 0; +		tramp = current->mm->context.vdso_base + vdso32_rt_sigtramp;  	} else { -		if (save_user_regs(regs, frame, __NR_rt_sigreturn, 1)) +		sigret = __NR_rt_sigreturn; +		tramp = (unsigned long) frame->tramp; +	} + +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +	if (MSR_TM_ACTIVE(regs->msr)) { +		if (save_tm_user_regs(regs, &rt_sf->uc.uc_mcontext, +				      &rt_sf->uc_transact.uc_mcontext, sigret)) +			goto badframe; +	} +	else +#endif +		if (save_user_regs(regs, frame, sigret, 1)) +			goto badframe; +	regs->link = tramp; + +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +	if (MSR_TM_ACTIVE(regs->msr)) { +		if (__put_user((unsigned long)&rt_sf->uc_transact, +			       &rt_sf->uc.uc_link) +		    || __put_user(to_user_ptr(&rt_sf->uc_transact.uc_mcontext), +				  &rt_sf->uc_transact.uc_regs))  			goto badframe; -		regs->link = (unsigned long) frame->tramp;  	} +	else +#endif +		if (__put_user(0, &rt_sf->uc.uc_link)) +			goto badframe;  	current->thread.fpscr.val = 0;	/* turn off all fp exceptions */ @@ -878,6 +1032,13 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,  	regs->nip = (unsigned long) ka->sa.sa_handler;  	/* enter the signal handler in big-endian mode */  	regs->msr &= ~MSR_LE; +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +	/* Remove TM bits from thread's MSR.  The MSR in the sigcontext +	 * just indicates to userland that we were doing a transaction, but we +	 * don't want to return in transactional state: +	 */ +	regs->msr &= ~MSR_TS_MASK; +#endif  	return 1;  badframe: @@ -925,6 +1086,35 @@ static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int  	return 0;  } +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +static int do_setcontext_tm(struct ucontext __user *ucp, +			    struct ucontext __user *tm_ucp, +			    struct pt_regs *regs) +{ +	sigset_t set; +	struct mcontext __user *mcp; +	struct mcontext __user *tm_mcp; +	u32 cmcp; +	u32 tm_cmcp; + +	if (get_sigset_t(&set, &ucp->uc_sigmask)) +		return -EFAULT; + +	if (__get_user(cmcp, &ucp->uc_regs) || +	    __get_user(tm_cmcp, &tm_ucp->uc_regs)) +		return -EFAULT; +	mcp = (struct mcontext __user *)(u64)cmcp; +	tm_mcp = (struct mcontext __user *)(u64)tm_cmcp; +	/* no need to check access_ok(mcp), since mcp < 4GB */ + +	set_current_blocked(&set); +	if (restore_tm_user_regs(regs, mcp, tm_mcp)) +		return -EFAULT; + +	return 0; +} +#endif +  long sys_swapcontext(struct ucontext __user *old_ctx,  		     struct ucontext __user *new_ctx,  		     int ctx_size, int r6, int r7, int r8, struct pt_regs *regs) @@ -1020,7 +1210,12 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,  		     struct pt_regs *regs)  {  	struct rt_sigframe __user *rt_sf; - +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +	struct ucontext __user *uc_transact; +	unsigned long msr_hi; +	unsigned long tmp; +	int tm_restore = 0; +#endif  	/* Always make any pending restarted system calls return -EINTR */  	current_thread_info()->restart_block.fn = do_no_restart_syscall; @@ -1028,6 +1223,34 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,  		(regs->gpr[1] + __SIGNAL_FRAMESIZE + 16);  	if (!access_ok(VERIFY_READ, rt_sf, sizeof(*rt_sf)))  		goto bad; +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +	if (__get_user(tmp, &rt_sf->uc.uc_link)) +		goto bad; +	uc_transact = (struct ucontext __user *)(uintptr_t)tmp; +	if (uc_transact) { +		u32 cmcp; +		struct mcontext __user *mcp; + +		if (__get_user(cmcp, &uc_transact->uc_regs)) +			return -EFAULT; +		mcp = (struct mcontext __user *)(u64)cmcp; +		/* The top 32 bits of the MSR are stashed in the transactional +		 * ucontext. */ +		if (__get_user(msr_hi, &mcp->mc_gregs[PT_MSR])) +			goto bad; + +		if (MSR_TM_SUSPENDED(msr_hi<<32)) { +			/* We only recheckpoint on return if we're +			 * transaction. +			 */ +			tm_restore = 1; +			if (do_setcontext_tm(&rt_sf->uc, uc_transact, regs)) +				goto bad; +		} +	} +	if (!tm_restore) +		/* Fall through, for non-TM restore */ +#endif  	if (do_setcontext(&rt_sf->uc, regs, 1))  		goto bad; @@ -1039,14 +1262,11 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,  	 * change it.  -- paulus  	 */  #ifdef CONFIG_PPC64 -	/* -	 * We use the compat_sys_ version that does the 32/64 bits conversion -	 * and takes userland pointer directly. What about error checking ? -	 * nobody does any... -	 */ -	compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); +	if (compat_restore_altstack(&rt_sf->uc.uc_stack)) +		goto bad;  #else -	do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]); +	if (restore_altstack(&rt_sf->uc.uc_stack)) +		goto bad;  #endif  	set_thread_flag(TIF_RESTOREALL);  	return 0; @@ -1162,7 +1382,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx,  	 * always done it up until now so it is probably better not to  	 * change it.  -- paulus  	 */ -	do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]); +	restore_altstack(&ctx->uc_stack);  	set_thread_flag(TIF_RESTOREALL);   out: @@ -1179,6 +1399,8 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,  	struct sigcontext __user *sc;  	struct sigframe __user *frame;  	unsigned long newsp = 0; +	int sigret; +	unsigned long tramp;  	/* Set up Signal Frame */  	frame = get_sigframe(ka, regs, sizeof(*frame), 1); @@ -1201,14 +1423,25 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,  		goto badframe;  	if (vdso32_sigtramp && current->mm->context.vdso_base) { -		if (save_user_regs(regs, &frame->mctx, 0, 1)) -			goto badframe; -		regs->link = current->mm->context.vdso_base + vdso32_sigtramp; +		sigret = 0; +		tramp = current->mm->context.vdso_base + vdso32_sigtramp;  	} else { -		if (save_user_regs(regs, &frame->mctx, __NR_sigreturn, 1)) +		sigret = __NR_sigreturn; +		tramp = (unsigned long) frame->mctx.tramp; +	} + +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +	if (MSR_TM_ACTIVE(regs->msr)) { +		if (save_tm_user_regs(regs, &frame->mctx, &frame->mctx_transact, +				      sigret))  			goto badframe; -		regs->link = (unsigned long) frame->mctx.tramp;  	} +	else +#endif +		if (save_user_regs(regs, &frame->mctx, sigret, 1)) +			goto badframe; + +	regs->link = tramp;  	current->thread.fpscr.val = 0;	/* turn off all fp exceptions */ @@ -1223,7 +1456,13 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,  	regs->nip = (unsigned long) ka->sa.sa_handler;  	/* enter the signal handler in big-endian mode */  	regs->msr &= ~MSR_LE; - +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM +	/* Remove TM bits from thread's MSR.  The MSR in the sigcontext +	 * just indicates to userland that we were doing a transaction, but we +	 * don't want to return in transactional state: +	 */ +	regs->msr &= ~MSR_TS_MASK; +#endif  	return 1;  badframe:  |