* (except for MSR).
*/
static int
-restore_user_regs(struct pt_regs *regs, struct mcontext __user *sr)
+restore_user_regs(struct pt_regs *regs, struct mcontext __user *sr, int sig)
{
+ unsigned long save_r2;
#ifdef CONFIG_ALTIVEC
unsigned long msr;
#endif
+ /* backup/restore the TLS as we don't want it to be modified */
+ if (!sig)
+ save_r2 = regs->gpr[2];
/* copy up to but not including MSR */
if (__copy_from_user(regs, &sr->mc_gregs, PT_MSR * sizeof(elf_greg_t)))
return 1;
if (__copy_from_user(®s->orig_gpr3, &sr->mc_gregs[PT_ORIG_R3],
GP_REGS_SIZE - PT_ORIG_R3 * sizeof(elf_greg_t)))
return 1;
+ if (!sig)
+ regs->gpr[2] = save_r2;
/* force the process to reload the FP registers from
current->thread when it next does FP instructions */
force_sig(SIGSEGV, current);
}
-static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs)
+static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int sig)
{
sigset_t set;
struct mcontext *mcp;
|| __get_user(mcp, &ucp->uc_regs))
return -EFAULT;
restore_sigmask(&set);
- if (restore_user_regs(regs, mcp))
+ if (restore_user_regs(regs, mcp, sig))
return -EFAULT;
return 0;
int sys_swapcontext(struct ucontext __user *old_ctx,
struct ucontext __user *new_ctx,
- int r5, int r6, int r7, int r8, struct pt_regs *regs)
+ int ctx_size, int r6, int r7, int r8, struct pt_regs *regs)
{
unsigned char tmp;
+ /* Context size is for future use. Right now, we only make sure
+ * we are passed something we understand
+ */
+ if (ctx_size < sizeof(struct ucontext))
+ return -EINVAL;
+
if (old_ctx != NULL) {
if (verify_area(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))
|| save_user_regs(regs, &old_ctx->uc_mcontext, 0)
* or if another thread unmaps the region containing the context.
* We kill the task with a SIGSEGV in this situation.
*/
- if (do_setcontext(new_ctx, regs))
+ if (do_setcontext(new_ctx, regs, 0))
do_exit(SIGSEGV);
sigreturn_exit(regs);
/* doesn't actually return back to here */
(regs->gpr[1] + __SIGNAL_FRAMESIZE + 16);
if (verify_area(VERIFY_READ, rt_sf, sizeof(struct rt_sigframe)))
goto bad;
- if (do_setcontext(&rt_sf->uc, regs))
+ if (do_setcontext(&rt_sf->uc, regs, 1))
goto bad;
/*
if (save_user_regs(regs, &frame->mctx, __NR_sigreturn))
goto badframe;
- if (put_user(regs->gpr[1], (unsigned long *)newsp))
+ if (put_user(regs->gpr[1], (unsigned long __user *)newsp))
goto badframe;
regs->gpr[1] = newsp;
regs->gpr[3] = sig;
sr = (struct mcontext *) sigctx.regs;
if (verify_area(VERIFY_READ, sr, sizeof(*sr))
- || restore_user_regs(regs, sr))
+ || restore_user_regs(regs, sr, 1))
goto badframe;
sigreturn_exit(regs); /* doesn't return */