Commit 0a592281 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile

* git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile:
  arch/tile: handle rt_sigreturn() more cleanly
  arch/tile: handle CLONE_SETTLS in copy_thread(), not user space
parents 2ba16c4f 81711cee
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#if defined(__KERNEL__) && !defined(__ASSEMBLY__) #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
struct pt_regs; struct pt_regs;
int restore_sigcontext(struct pt_regs *, struct sigcontext __user *, long *); int restore_sigcontext(struct pt_regs *, struct sigcontext __user *);
int setup_sigcontext(struct sigcontext __user *, struct pt_regs *); int setup_sigcontext(struct sigcontext __user *, struct pt_regs *);
void do_signal(struct pt_regs *regs); void do_signal(struct pt_regs *regs);
#endif #endif
......
...@@ -290,12 +290,12 @@ long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr, ...@@ -290,12 +290,12 @@ long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
return ret; return ret;
} }
/* The assembly shim for this function arranges to ignore the return value. */
long compat_sys_rt_sigreturn(struct pt_regs *regs) long compat_sys_rt_sigreturn(struct pt_regs *regs)
{ {
struct compat_rt_sigframe __user *frame = struct compat_rt_sigframe __user *frame =
(struct compat_rt_sigframe __user *) compat_ptr(regs->sp); (struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
sigset_t set; sigset_t set;
long r0;
if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe; goto badframe;
...@@ -308,13 +308,13 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs) ...@@ -308,13 +308,13 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs)
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe; goto badframe;
if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0) if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
goto badframe; goto badframe;
return r0; return 0;
badframe: badframe:
force_sig(SIGSEGV, current); force_sig(SIGSEGV, current);
......
...@@ -1342,8 +1342,8 @@ handle_syscall: ...@@ -1342,8 +1342,8 @@ handle_syscall:
lw r20, r20 lw r20, r20
/* Jump to syscall handler. */ /* Jump to syscall handler. */
jalr r20; .Lhandle_syscall_link: jalr r20
FEEDBACK_REENTER(handle_syscall) .Lhandle_syscall_link: /* value of "lr" after "jalr r20" above */
/* /*
* Write our r0 onto the stack so it gets restored instead * Write our r0 onto the stack so it gets restored instead
...@@ -1352,6 +1352,9 @@ handle_syscall: ...@@ -1352,6 +1352,9 @@ handle_syscall:
PTREGS_PTR(r29, PTREGS_OFFSET_REG(0)) PTREGS_PTR(r29, PTREGS_OFFSET_REG(0))
sw r29, r0 sw r29, r0
.Lsyscall_sigreturn_skip:
FEEDBACK_REENTER(handle_syscall)
/* Do syscall trace again, if requested. */ /* Do syscall trace again, if requested. */
lw r30, r31 lw r30, r31
andi r30, r30, _TIF_SYSCALL_TRACE andi r30, r30, _TIF_SYSCALL_TRACE
...@@ -1536,9 +1539,24 @@ STD_ENTRY_LOCAL(bad_intr) ...@@ -1536,9 +1539,24 @@ STD_ENTRY_LOCAL(bad_intr)
}; \ }; \
STD_ENDPROC(_##x) STD_ENDPROC(_##x)
/*
* Special-case sigreturn to not write r0 to the stack on return.
* This is technically more efficient, but it also avoids difficulties
* in the 64-bit OS when handling 32-bit compat code, since we must not
* sign-extend r0 for the sigreturn return-value case.
*/
#define PTREGS_SYSCALL_SIGRETURN(x, reg) \
STD_ENTRY(_##x); \
addli lr, lr, .Lsyscall_sigreturn_skip - .Lhandle_syscall_link; \
{ \
PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \
j x \
}; \
STD_ENDPROC(_##x)
PTREGS_SYSCALL(sys_execve, r3) PTREGS_SYSCALL(sys_execve, r3)
PTREGS_SYSCALL(sys_sigaltstack, r2) PTREGS_SYSCALL(sys_sigaltstack, r2)
PTREGS_SYSCALL(sys_rt_sigreturn, r0) PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
PTREGS_SYSCALL(sys_cmpxchg_badaddr, r1) PTREGS_SYSCALL(sys_cmpxchg_badaddr, r1)
/* Save additional callee-saves to pt_regs, put address in r4 and jump. */ /* Save additional callee-saves to pt_regs, put address in r4 and jump. */
......
...@@ -211,6 +211,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, ...@@ -211,6 +211,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
childregs->regs[0] = 0; /* return value is zero */ childregs->regs[0] = 0; /* return value is zero */
childregs->sp = sp; /* override with new user stack pointer */ childregs->sp = sp; /* override with new user stack pointer */
/*
* If CLONE_SETTLS is set, set "tp" in the new task to "r4",
* which is passed in as arg #5 to sys_clone().
*/
if (clone_flags & CLONE_SETTLS)
childregs->tp = regs->regs[4];
/* /*
* Copy the callee-saved registers from the passed pt_regs struct * Copy the callee-saved registers from the passed pt_regs struct
* into the context-switch callee-saved registers area. * into the context-switch callee-saved registers area.
...@@ -539,6 +546,7 @@ struct task_struct *__sched _switch_to(struct task_struct *prev, ...@@ -539,6 +546,7 @@ struct task_struct *__sched _switch_to(struct task_struct *prev,
return __switch_to(prev, next, next_current_ksp0(next)); return __switch_to(prev, next, next_current_ksp0(next));
} }
/* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
void __user *, parent_tidptr, void __user *, child_tidptr, void __user *, parent_tidptr, void __user *, child_tidptr,
struct pt_regs *, regs) struct pt_regs *, regs)
......
...@@ -52,7 +52,7 @@ SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss, ...@@ -52,7 +52,7 @@ SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,
*/ */
int restore_sigcontext(struct pt_regs *regs, int restore_sigcontext(struct pt_regs *regs,
struct sigcontext __user *sc, long *pr0) struct sigcontext __user *sc)
{ {
int err = 0; int err = 0;
int i; int i;
...@@ -75,17 +75,15 @@ int restore_sigcontext(struct pt_regs *regs, ...@@ -75,17 +75,15 @@ int restore_sigcontext(struct pt_regs *regs,
regs->faultnum = INT_SWINT_1_SIGRETURN; regs->faultnum = INT_SWINT_1_SIGRETURN;
err |= __get_user(*pr0, &sc->gregs[0]);
return err; return err;
} }
/* sigreturn() returns long since it restores r0 in the interrupted code. */ /* The assembly shim for this function arranges to ignore the return value. */
SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs) SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
{ {
struct rt_sigframe __user *frame = struct rt_sigframe __user *frame =
(struct rt_sigframe __user *)(regs->sp); (struct rt_sigframe __user *)(regs->sp);
sigset_t set; sigset_t set;
long r0;
if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe; goto badframe;
...@@ -98,13 +96,13 @@ SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs) ...@@ -98,13 +96,13 @@ SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe; goto badframe;
if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
goto badframe; goto badframe;
return r0; return 0;
badframe: badframe:
force_sig(SIGSEGV, current); force_sig(SIGSEGV, current);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment