Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/viro/signal

Pull third pile of kernel_execve() patches from Al Viro:
 "The last bits of infrastructure for kernel_thread() et.al., with
  alpha/arm/x86 use of those.  Plus sanitizing the asm glue and
  do_notify_resume() on alpha, fixing the "disabled irq while running
  task_work stuff" breakage there.

  At that point the rest of kernel_thread/kernel_execve/sys_execve work
  can be done independently for different architectures.  The only
  pending bits that do depend on having all architectures converted are
  restrictred to fs/* and kernel/* - that'll obviously have to wait for
  the next cycle.

  I thought we'd have to wait for all of them done before we start
  eliminating the longjump-style insanity in kernel_execve(), but it
  turned out there's a very simple way to do that without flagday-style
  changes."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal:
  alpha: switch to saner kernel_execve() semantics
  arm: switch to saner kernel_execve() semantics
  x86, um: convert to saner kernel_execve() semantics
  infrastructure for saner ret_from_kernel_thread semantics
  make sure that kernel_thread() callbacks call do_exit() themselves
  make sure that we always have a return path from kernel_execve()
  ppc: eeh_event should just use kthread_run()
  don't bother with kernel_thread/kernel_execve for launching linuxrc
  alpha: get rid of switch_stack argument of do_work_pending()
  alpha: don't bother passing switch_stack separately from regs
  alpha: take SIGPENDING/NOTIFY_RESUME loop into signal.c
  alpha: simplify TIF_NEED_RESCHED handling
  • Loading branch information
torvalds committed Oct 13, 2012
2 parents 8418263 + 5522be6 commit 4e21fc1
Show file tree
Hide file tree
Showing 25 changed files with 137 additions and 223 deletions.
3 changes: 3 additions & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ config ARCH_WANT_OLD_COMPAT_IPC
config GENERIC_KERNEL_THREAD
bool

config GENERIC_KERNEL_EXECVE
bool

config HAVE_ARCH_SECCOMP_FILTER
bool
help
Expand Down
1 change: 1 addition & 0 deletions arch/alpha/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ config ALPHA
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select GENERIC_KERNEL_THREAD
select GENERIC_KERNEL_EXECVE
help
The Alpha is a 64-bit general-purpose processor designed and
marketed by the Digital Equipment Corporation of blessed memory,
Expand Down
1 change: 0 additions & 1 deletion arch/alpha/include/asm/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,6 @@
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_EXECVE
#define __ARCH_WANT_KERNEL_EXECVE

/* "Conditional" syscalls. What we want is
Expand Down
87 changes: 28 additions & 59 deletions arch/alpha/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ entSys:

.align 4
ret_from_sys_call:
cmovne $26, 0, $19 /* $19 = 0 => non-restartable */
cmovne $26, 0, $18 /* $18 = 0 => non-restartable */
ldq $0, SP_OFF($sp)
and $0, 8, $0
beq $0, ret_to_kernel
Expand All @@ -320,8 +320,8 @@ ret_to_user:
sampling and the rti. */
lda $16, 7
call_pal PAL_swpipl
ldl $5, TI_FLAGS($8)
and $5, _TIF_WORK_MASK, $2
ldl $17, TI_FLAGS($8)
and $17, _TIF_WORK_MASK, $2
bne $2, work_pending
restore_all:
RESTORE_ALL
Expand All @@ -341,10 +341,10 @@ $syscall_error:
* frame to indicate that a negative return value wasn't an
* error number..
*/
ldq $19, 0($sp) /* old syscall nr (zero if success) */
beq $19, $ret_success
ldq $18, 0($sp) /* old syscall nr (zero if success) */
beq $18, $ret_success

ldq $20, 72($sp) /* .. and this a3 */
ldq $19, 72($sp) /* .. and this a3 */
subq $31, $0, $0 /* with error in v0 */
addq $31, 1, $1 /* set a3 for errno return */
stq $0, 0($sp)
Expand All @@ -362,51 +362,35 @@ $ret_success:
* Do all cleanup when returning from all interrupts and system calls.
*
* Arguments:
* $5: TI_FLAGS.
* $8: current.
* $19: The old syscall number, or zero if this is not a return
* $17: TI_FLAGS.
* $18: The old syscall number, or zero if this is not a return
* from a syscall that errored and is possibly restartable.
* $20: The old a3 value
* $19: The old a3 value
*/

.align 4
.ent work_pending
work_pending:
and $5, _TIF_NEED_RESCHED, $2
beq $2, $work_notifysig
and $17, _TIF_NOTIFY_RESUME | _TIF_SIGPENDING, $2
bne $2, $work_notifysig

$work_resched:
subq $sp, 16, $sp
stq $19, 0($sp) /* save syscall nr */
stq $20, 8($sp) /* and error indication (a3) */
/*
* We can get here only if we returned from syscall without SIGPENDING
* or got through work_notifysig already. Either case means no syscall
* restarts for us, so let $18 and $19 burn.
*/
jsr $26, schedule
ldq $19, 0($sp)
ldq $20, 8($sp)
addq $sp, 16, $sp
/* Make sure need_resched and sigpending don't change between
sampling and the rti. */
lda $16, 7
call_pal PAL_swpipl
ldl $5, TI_FLAGS($8)
and $5, _TIF_WORK_MASK, $2
beq $2, restore_all
and $5, _TIF_NEED_RESCHED, $2
bne $2, $work_resched
mov 0, $18
br ret_to_user

$work_notifysig:
mov $sp, $16
bsr $1, do_switch_stack
mov $sp, $17
mov $5, $18
mov $19, $9 /* save old syscall number */
mov $20, $10 /* save old a3 */
and $5, _TIF_SIGPENDING, $2
cmovne $2, 0, $9 /* we don't want double syscall restarts */
jsr $26, do_notify_resume
mov $9, $19
mov $10, $20
jsr $26, do_work_pending
bsr $1, undo_switch_stack
br ret_to_user
br restore_all
.end work_pending

/*
Expand Down Expand Up @@ -454,21 +438,21 @@ $strace_success:

.align 3
$strace_error:
ldq $19, 0($sp) /* old syscall nr (zero if success) */
beq $19, $strace_success
ldq $20, 72($sp) /* .. and this a3 */
ldq $18, 0($sp) /* old syscall nr (zero if success) */
beq $18, $strace_success
ldq $19, 72($sp) /* .. and this a3 */

subq $31, $0, $0 /* with error in v0 */
addq $31, 1, $1 /* set a3 for errno return */
stq $0, 0($sp)
stq $1, 72($sp) /* a3 for return */

bsr $1, do_switch_stack
mov $19, $9 /* save old syscall number */
mov $20, $10 /* save old a3 */
mov $18, $9 /* save old syscall number */
mov $19, $10 /* save old a3 */
jsr $26, syscall_trace_leave
mov $9, $19
mov $10, $20
mov $9, $18
mov $10, $19
bsr $1, undo_switch_stack

mov $31, $26 /* tell "ret_from_sys_call" we can restart */
Expand Down Expand Up @@ -619,24 +603,9 @@ ret_from_kernel_thread:
mov $9, $27
mov $10, $16
jsr $26, ($9)
ldgp $gp, 0($26)
mov $0, $16
mov $31, $26
jmp $31, sys_exit
.end ret_from_kernel_thread

.globl ret_from_kernel_execve
.align 4
.ent ret_from_kernel_execve
ret_from_kernel_execve:
mov $16, $sp
/* Avoid the HAE being gratuitously wrong, to avoid restoring it. */
ldq $2, alpha_mv+HAE_CACHE
stq $2, 152($sp) /* HAE */
mov $31, $19 /* to disable syscall restarts */
br $31, ret_to_user

.end ret_from_kernel_execve
.end ret_from_kernel_thread


/*
Expand Down
48 changes: 28 additions & 20 deletions arch/alpha/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,9 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)

static long
setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
struct switch_stack *sw, unsigned long mask, unsigned long sp)
unsigned long mask, unsigned long sp)
{
struct switch_stack *sw = (struct switch_stack *)regs - 1;
long i, err = 0;

err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack);
Expand Down Expand Up @@ -354,7 +355,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,

static int
setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
struct pt_regs *regs, struct switch_stack * sw)
struct pt_regs *regs)
{
unsigned long oldsp, r26, err = 0;
struct sigframe __user *frame;
Expand All @@ -364,7 +365,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;

err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
err |= setup_sigcontext(&frame->sc, regs, set->sig[0], oldsp);
if (err)
return -EFAULT;

Expand Down Expand Up @@ -401,7 +402,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,

static int
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs, struct switch_stack * sw)
sigset_t *set, struct pt_regs *regs)
{
unsigned long oldsp, r26, err = 0;
struct rt_sigframe __user *frame;
Expand All @@ -420,7 +421,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw,
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs,
set->sig[0], oldsp);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
Expand Down Expand Up @@ -464,15 +465,15 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
*/
static inline void
handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
struct pt_regs * regs, struct switch_stack *sw)
struct pt_regs * regs)
{
sigset_t *oldset = sigmask_to_save();
int ret;

if (ka->sa.sa_flags & SA_SIGINFO)
ret = setup_rt_frame(sig, ka, info, oldset, regs, sw);
ret = setup_rt_frame(sig, ka, info, oldset, regs);
else
ret = setup_frame(sig, ka, oldset, regs, sw);
ret = setup_frame(sig, ka, oldset, regs);

if (ret) {
force_sigsegv(sig, current);
Expand Down Expand Up @@ -519,8 +520,7 @@ syscall_restart(unsigned long r0, unsigned long r19,
* all (if we get here from anything but a syscall return, it will be 0)
*/
static void
do_signal(struct pt_regs * regs, struct switch_stack * sw,
unsigned long r0, unsigned long r19)
do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
{
siginfo_t info;
int signr;
Expand All @@ -537,7 +537,7 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw,
/* Whee! Actually deliver the signal. */
if (r0)
syscall_restart(r0, r19, regs, &ka);
handle_signal(signr, &ka, &info, regs, sw);
handle_signal(signr, &ka, &info, regs);
if (single_stepping)
ptrace_set_bpt(current); /* re-set bpt */
return;
Expand Down Expand Up @@ -568,15 +568,23 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw,
}

void
do_notify_resume(struct pt_regs *regs, struct switch_stack *sw,
unsigned long thread_info_flags,
do_work_pending(struct pt_regs *regs, unsigned long thread_flags,
unsigned long r0, unsigned long r19)
{
if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs, sw, r0, r19);

if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
}
do {
if (thread_flags & _TIF_NEED_RESCHED) {
schedule();
} else {
local_irq_enable();
if (thread_flags & _TIF_SIGPENDING) {
do_signal(regs, r0, r19);
r0 = 0;
} else {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
}
}
local_irq_disable();
thread_flags = current_thread_info()->flags;
} while (thread_flags & _TIF_WORK_MASK);
}
1 change: 1 addition & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ config ARM
select GENERIC_STRNLEN_USER
select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN
select GENERIC_KERNEL_THREAD
select GENERIC_KERNEL_EXECVE
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
Expand Down
1 change: 0 additions & 1 deletion arch/arm/include/asm/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,6 @@
#define __ARCH_WANT_SYS_SOCKETCALL
#endif
#define __ARCH_WANT_SYS_EXECVE
#define __ARCH_WANT_KERNEL_EXECVE

/*
* "Conditional" syscalls
Expand Down
29 changes: 4 additions & 25 deletions arch/arm/kernel/entry-common.S
Original file line number Diff line number Diff line change
Expand Up @@ -86,35 +86,14 @@ ENDPROC(ret_to_user)
*/
ENTRY(ret_from_fork)
bl schedule_tail
cmp r5, #0
movne r0, r4
movne lr, pc
movne pc, r5
get_thread_info tsk
mov why, #1
b ret_slow_syscall
ENDPROC(ret_from_fork)

ENTRY(ret_from_kernel_thread)
UNWIND(.fnstart)
UNWIND(.cantunwind)
bl schedule_tail
mov r0, r4
adr lr, BSYM(1f) @ kernel threads should not exit
mov pc, r5
1: bl do_exit
nop
UNWIND(.fnend)
ENDPROC(ret_from_kernel_thread)

/*
* turn a kernel thread into userland process
* use: ret_from_kernel_execve(struct pt_regs *normal)
*/
ENTRY(ret_from_kernel_execve)
mov why, #0 @ not a syscall
str why, [r0, #S_R0] @ ... and we want 0 in ->ARM_r0 as well
get_thread_info tsk @ thread structure
mov sp, r0 @ stack pointer just under pt_regs
b ret_slow_syscall
ENDPROC(ret_from_kernel_execve)

.equ NR_syscalls,0
#define CALL(x) .equ NR_syscalls,NR_syscalls+1
#include "calls.S"
Expand Down
5 changes: 2 additions & 3 deletions arch/arm/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,6 @@ void release_thread(struct task_struct *dead_task)
}

asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");

int
copy_thread(unsigned long clone_flags, unsigned long stack_start,
Expand All @@ -388,13 +387,13 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
*childregs = *regs;
childregs->ARM_r0 = 0;
childregs->ARM_sp = stack_start;
thread->cpu_context.pc = (unsigned long)ret_from_fork;
} else {
memset(childregs, 0, sizeof(struct pt_regs));
thread->cpu_context.r4 = stk_sz;
thread->cpu_context.r5 = stack_start;
thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread;
childregs->ARM_cpsr = SVC_MODE;
}
thread->cpu_context.pc = (unsigned long)ret_from_fork;
thread->cpu_context.sp = (unsigned long)childregs;

clear_ptrace_hw_breakpoint(p);
Expand Down
Loading

0 comments on commit 4e21fc1

Please sign in to comment.