Commit 54dfe5dd authored by Heiko Carstens's avatar Heiko Carstens Committed by Linus Torvalds
Browse files

[PATCH] s390: Add support for new syscalls/TIF_RESTORE_SIGMASK



Add support for the new *at, pselect6 and ppoll system calls.  This includes
adding required support for TIF_RESTORE_SIGMASK.

Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 1ab865c1
Loading
Loading
Loading
Loading
+23 −79
Original line number Diff line number Diff line
/*
 *  arch/s390/kernel/signal32.c
 *  arch/s390/kernel/compat_signal.c
 *
 *  S390 version
 *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *    Copyright (C) IBM Corp. 2000,2006
 *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
 *               Gerhard Tonn (ton@de.ibm.com)                  
 *
@@ -52,8 +51,6 @@ typedef struct
	struct ucontext32 uc;
} rt_sigframe32;

asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));

int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
{
	int err;
@@ -161,66 +158,6 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
	return err;
}

/*
 * Atomically swap in the new signal mask, and wait for a signal.
 */
asmlinkage int
sys32_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t mask)
{
	sigset_t saveset;

	mask &= _BLOCKABLE;
	spin_lock_irq(&current->sighand->siglock);
	saveset = current->blocked;
	siginitset(&current->blocked, mask);
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);
	regs->gprs[2] = -EINTR;

	while (1) {
		set_current_state(TASK_INTERRUPTIBLE);
		schedule();
		if (do_signal(regs, &saveset))
			return -EINTR;
	}
}

asmlinkage int
sys32_rt_sigsuspend(struct pt_regs * regs, compat_sigset_t __user *unewset,
								size_t sigsetsize)
{
	sigset_t saveset, newset;
	compat_sigset_t set32;

	/* XXX: Don't preclude handling different sized sigset_t's.  */
	if (sigsetsize != sizeof(sigset_t))
		return -EINVAL;

	if (copy_from_user(&set32, unewset, sizeof(set32)))
		return -EFAULT;
	switch (_NSIG_WORDS) {
	case 4: newset.sig[3] = set32.sig[6] + (((long)set32.sig[7]) << 32);
	case 3: newset.sig[2] = set32.sig[4] + (((long)set32.sig[5]) << 32);
	case 2: newset.sig[1] = set32.sig[2] + (((long)set32.sig[3]) << 32);
	case 1: newset.sig[0] = set32.sig[0] + (((long)set32.sig[1]) << 32);
	}
        sigdelsetmask(&newset, ~_BLOCKABLE);

        spin_lock_irq(&current->sighand->siglock);
        saveset = current->blocked;
        current->blocked = newset;
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
        regs->gprs[2] = -EINTR;

        while (1) {
                set_current_state(TASK_INTERRUPTIBLE);
                schedule();
                if (do_signal(regs, &saveset))
                        return -EINTR;
        }
}

asmlinkage long
sys32_sigaction(int sig, const struct old_sigaction32 __user *act,
		 struct old_sigaction32 __user *oact)
@@ -520,7 +457,7 @@ static inline int map_signal(int sig)
		return sig;
}

static void setup_frame32(int sig, struct k_sigaction *ka,
static int setup_frame32(int sig, struct k_sigaction *ka,
			sigset_t *set, struct pt_regs * regs)
{
	sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32));
@@ -565,13 +502,14 @@ static void setup_frame32(int sig, struct k_sigaction *ka,
	/* Place signal number on stack to allow backtrace from handler.  */
	if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
		goto give_sigsegv;
	return;
	return 0;

give_sigsegv:
	force_sigsegv(sig, current);
	return -EFAULT;
}

static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
			   sigset_t *set, struct pt_regs * regs)
{
	int err = 0;
@@ -615,26 +553,30 @@ static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
	regs->gprs[2] = map_signal(sig);
	regs->gprs[3] = (__u64) &frame->info;
	regs->gprs[4] = (__u64) &frame->uc;
	return;
	return 0;

give_sigsegv:
	force_sigsegv(sig, current);
	return -EFAULT;
}

/*
 * OK, we're invoking a handler
 */	

void
int
handle_signal32(unsigned long sig, struct k_sigaction *ka,
		siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
{
	int ret;

	/* Set up the stack frame */
	if (ka->sa.sa_flags & SA_SIGINFO)
		setup_rt_frame32(sig, ka, info, oldset, regs);
		ret = setup_rt_frame32(sig, ka, info, oldset, regs);
	else
		setup_frame32(sig, ka, oldset, regs);
		ret = setup_frame32(sig, ka, oldset, regs);

	if (ret == 0) {
		spin_lock_irq(&current->sighand->siglock);
		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
		if (!(ka->sa.sa_flags & SA_NODEFER))
@@ -642,4 +584,6 @@ handle_signal32(unsigned long sig, struct k_sigaction *ka,
		recalc_sigpending();
		spin_unlock_irq(&current->sighand->siglock);
	}
	return ret;
}
+132 −5
Original line number Diff line number Diff line
/*
*  arch/s390/kernel/sys_wrapper31.S
*  arch/s390/kernel/compat_wrapper.S
*    wrapper for 31 bit compatible system calls.
*
*  S390 version
*    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
*    Copyright (C) IBM Corp. 2000,2006
*    Author(s): Gerhard Tonn (ton@de.ibm.com),
*               Thomas Spatzier (tspat@de.ibm.com)
*/ 
@@ -288,7 +287,12 @@ sys32_setregid16_wrapper:
	llgfr	%r3,%r3			# __kernel_old_gid_emu31_t 
	jg	sys32_setregid16	# branch to system call

#sys32_sigsuspend_wrapper		# done in sigsuspend_glue 
	.globl sys_sigsuspend_wrapper
sys_sigsuspend_wrapper:
	lgfr	%r2,%r2			# int
	lgfr	%r3,%r3			# int
	llgfr	%r4,%r4			# old_sigset_t
	jg	sys_sigsuspend

	.globl  compat_sys_sigpending_wrapper 
compat_sys_sigpending_wrapper:
@@ -855,7 +859,11 @@ sys32_rt_sigqueueinfo_wrapper:
	llgtr	%r4,%r4			# siginfo_emu31_t *
	jg	sys32_rt_sigqueueinfo	# branch to system call

#sys32_rt_sigsuspend_wrapper		# done in rt_sigsuspend_glue 
	.globl compat_sys_rt_sigsuspend_wrapper
compat_sys_rt_sigsuspend_wrapper:
	llgtr	%r2,%r2			# compat_sigset_t *
	llgfr	%r3,%r3			# compat_size_t
	jg	compat_sys_rt_sigsuspend

	.globl  sys32_pread64_wrapper 
sys32_pread64_wrapper:
@@ -1475,3 +1483,122 @@ sys_inotify_rm_watch_wrapper:
	lgfr	%r2,%r2			# int
	llgfr	%r3,%r3			# u32
	jg	sys_inotify_rm_watch

	.globl compat_sys_openat_wrapper
compat_sys_openat_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# const char *
	lgfr	%r4,%r4			# int
	lgfr	%r5,%r5			# int
	jg	compat_sys_openat

	.globl sys_mkdirat_wrapper
sys_mkdirat_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# const char *
	lgfr	%r4,%r4			# int
	jg	sys_mkdirat

	.globl sys_mknodat_wrapper
sys_mknodat_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# const char *
	lgfr	%r4,%r4			# int
	llgfr	%r5,%r5			# unsigned int
	jg	sys_mknodat

	.globl sys_fchownat_wrapper
sys_fchownat_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# const char *
	llgfr	%r4,%r4			# uid_t
	llgfr	%r5,%r5			# gid_t
	lgfr	%r6,%r6			# int
	jg	sys_fchownat

	.globl compat_sys_futimesat_wrapper
compat_sys_futimesat_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# char *
	llgtr	%r4,%r4			# struct timeval *
	jg	compat_sys_futimesat

	.globl compat_sys_newfstatat_wrapper
compat_sys_newfstatat_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# char *
	llgtr	%r4,%r4			# struct stat *
	lgfr	%r5,%r5			# int
	jg	compat_sys_newfstatat

	.globl sys_unlinkat_wrapper
sys_unlinkat_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# const char *
	lgfr	%r4,%r4			# int
	jg	sys_unlinkat

	.globl sys_renameat_wrapper
sys_renameat_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# const char *
	lgfr	%r4,%r4			# int
	llgtr	%r5,%r5			# const char *
	jg	sys_renameat

	.globl sys_linkat_wrapper
sys_linkat_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# const char *
	lgfr	%r4,%r4			# int
	llgtr	%r5,%r5			# const char *
	jg	sys_linkat

	.globl sys_symlinkat_wrapper
sys_symlinkat_wrapper:
	llgtr	%r2,%r2			# const char *
	lgfr	%r3,%r3			# int
	llgtr	%r4,%r4			# const char *
	jg	sys_symlinkat

	.globl sys_readlinkat_wrapper
sys_readlinkat_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# const char *
	llgtr	%r4,%r4			# char *
	lgfr	%r5,%r5			# int
	jg	sys_readlinkat

	.globl sys_fchmodat_wrapper
sys_fchmodat_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# const char *
	llgfr	%r4,%r4			# mode_t
	jg	sys_fchmodat

	.globl sys_faccessat_wrapper
sys_faccessat_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# const char *
	lgfr	%r4,%r4			# int
	jg	sys_faccessat

	.globl compat_sys_pselect6_wrapper
compat_sys_pselect6_wrapper:
	lgfr	%r2,%r2			# int
	llgtr	%r3,%r3			# fd_set *
	llgtr	%r4,%r4			# fd_set *
	llgtr	%r5,%r5			# fd_set *
	llgtr	%r6,%r6			# struct timespec *
	llgt	%r0,164(%r15)		# void *
	stg	%r0,160(%r15)
	jg	compat_sys_pselect6

	.globl compat_sys_ppoll_wrapper
compat_sys_ppoll_wrapper:
	llgtr	%r2,%r2			# struct pollfd *
	llgfr	%r3,%r3			# unsigned int
	llgtr	%r4,%r4			# struct timespec *
	llgtr	%r5,%r5			# const sigset_t *
	llgfr	%r6,%r6			# size_t
	jg	compat_sys_ppoll
+13 −38
Original line number Diff line number Diff line
@@ -2,8 +2,7 @@
 *  arch/s390/kernel/entry.S
 *    S390 low-level entry points.
 *
 *  S390 version
 *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *    Copyright (C) IBM Corp. 1999,2006
 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
 *               Hartmut Penner (hp@de.ibm.com),
 *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
@@ -50,9 +49,10 @@ SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
SP_TRAP      =  STACK_FRAME_OVERHEAD + __PT_TRAP
SP_SIZE      =  STACK_FRAME_OVERHEAD + __PT_SIZE

_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \
		 _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
		 _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
		 _TIF_MCCK_PENDING)

STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE  = 1 << STACK_SHIFT
@@ -251,8 +251,8 @@ sysc_work:
	bo	BASED(sysc_mcck_pending)
	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
	bo	BASED(sysc_reschedule)
	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
	bo	BASED(sysc_sigpending)
	tm	__TI_flags+3(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
	bnz	BASED(sysc_sigpending)
	tm	__TI_flags+3(%r9),_TIF_RESTART_SVC
	bo	BASED(sysc_restart)
	tm	__TI_flags+3(%r9),_TIF_SINGLE_STEP
@@ -276,12 +276,11 @@ sysc_mcck_pending:
	br	%r1			# TIF bit will be cleared by handler

#
# _TIF_SIGPENDING is set, call do_signal
# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
#
sysc_sigpending:     
	ni	__TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
        la      %r2,SP_PTREGS(%r15)    # load pt_regs
        sr      %r3,%r3                # clear *oldset
        l       %r1,BASED(.Ldo_signal)
	basr	%r14,%r1               # call do_signal
	tm	__TI_flags+3(%r9),_TIF_RESTART_SVC
@@ -397,30 +396,6 @@ sys_rt_sigreturn_glue:
        l       %r1,BASED(.Lrt_sigreturn)
        br      %r1                   # branch to sys_sigreturn

#
# sigsuspend and rt_sigsuspend need pt_regs as an additional
# parameter and they have to skip the store of %r2 into the
# user register %r2 because the return value was set in 
# sigsuspend and rt_sigsuspend already and must not be overwritten!
#

sys_sigsuspend_glue:    
        lr      %r5,%r4               # move mask back
        lr      %r4,%r3               # move history1 parameter
        lr      %r3,%r2               # move history0 parameter
        la      %r2,SP_PTREGS(%r15)   # load pt_regs as first parameter
        l       %r1,BASED(.Lsigsuspend)
	la      %r14,4(%r14)          # skip store of return value
        br      %r1                   # branch to sys_sigsuspend

sys_rt_sigsuspend_glue: 
        lr      %r4,%r3               # move sigsetsize parameter
        lr      %r3,%r2               # move unewset parameter
        la      %r2,SP_PTREGS(%r15)   # load pt_regs as first parameter
        l       %r1,BASED(.Lrt_sigsuspend)
	la      %r14,4(%r14)          # skip store of return value
        br      %r1                   # branch to sys_rt_sigsuspend

sys_sigaltstack_glue:
        la      %r4,SP_PTREGS(%r15)   # load pt_regs as parameter
        l       %r1,BASED(.Lsigaltstack)
@@ -604,15 +579,16 @@ io_work:
	lr	%r15,%r1
#
# One of the work bits is on. Find out which one.
# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING
# Checked are: _TIF_SIGPENDING, _TIF_RESTORE_SIGMASK, _TIF_NEED_RESCHED
#	        and _TIF_MCCK_PENDING
#
io_work_loop:
	tm	__TI_flags+3(%r9),_TIF_MCCK_PENDING
	bo      BASED(io_mcck_pending)
	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
	bo	BASED(io_reschedule)
	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
	bo	BASED(io_sigpending)
	tm	__TI_flags+3(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
	bnz	BASED(io_sigpending)
	b	BASED(io_leave)

#
@@ -636,12 +612,11 @@ io_reschedule:
	b	BASED(io_work_loop)

#
# _TIF_SIGPENDING is set, call do_signal
# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
#
io_sigpending:     
        stosm   __SF_EMPTY(%r15),0x03  # reenable interrupts
        la      %r2,SP_PTREGS(%r15)    # load pt_regs
        sr      %r3,%r3                # clear *oldset
        l       %r1,BASED(.Ldo_signal)
	basr    %r14,%r1	       # call do_signal
        stnsm   __SF_EMPTY(%r15),0xfc  # disable I/O and ext. interrupts
+14 −61
Original line number Diff line number Diff line
/*
 *  arch/s390/kernel/entry.S
 *  arch/s390/kernel/entry64.S
 *    S390 low-level entry points.
 *
 *  S390 version
 *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *    Copyright (C) IBM Corp. 1999,2006
 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
 *               Hartmut Penner (hp@de.ibm.com),
 *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
@@ -53,9 +52,10 @@ SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE  = 1 << STACK_SHIFT

_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \
		 _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
		 _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
		 _TIF_MCCK_PENDING)

#define BASED(name) name-system_call(%r13)

@@ -249,8 +249,8 @@ sysc_work:
	jo	sysc_mcck_pending
	tm	__TI_flags+7(%r9),_TIF_NEED_RESCHED
	jo	sysc_reschedule
	tm	__TI_flags+7(%r9),_TIF_SIGPENDING
	jo	sysc_sigpending
	tm	__TI_flags+7(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
	jnz	sysc_sigpending
	tm	__TI_flags+7(%r9),_TIF_RESTART_SVC
	jo	sysc_restart
	tm	__TI_flags+7(%r9),_TIF_SINGLE_STEP
@@ -272,12 +272,11 @@ sysc_mcck_pending:
	jg	s390_handle_mcck    # TIF bit will be cleared by handler

#
# _TIF_SIGPENDING is set, call do_signal
# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
#
sysc_sigpending:     
	ni	__TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
        la      %r2,SP_PTREGS(%r15) # load pt_regs
        sgr     %r3,%r3           # clear *oldset
	brasl	%r14,do_signal    # call do_signal
	tm	__TI_flags+7(%r9),_TIF_RESTART_SVC
	jo	sysc_restart
@@ -414,52 +413,6 @@ sys32_rt_sigreturn_glue:
        jg      sys32_rt_sigreturn    # branch to sys32_sigreturn
#endif

#
# sigsuspend and rt_sigsuspend need pt_regs as an additional
# parameter and they have to skip the store of %r2 into the
# user register %r2 because the return value was set in 
# sigsuspend and rt_sigsuspend already and must not be overwritten!
#

sys_sigsuspend_glue:    
        lgr     %r5,%r4               # move mask back
        lgr     %r4,%r3               # move history1 parameter
        lgr     %r3,%r2               # move history0 parameter
        la      %r2,SP_PTREGS(%r15)   # load pt_regs as first parameter
	la      %r14,6(%r14)          # skip store of return value
        jg      sys_sigsuspend        # branch to sys_sigsuspend

#ifdef CONFIG_COMPAT
sys32_sigsuspend_glue:    
	llgfr	%r4,%r4               # unsigned long			
        lgr     %r5,%r4               # move mask back
	lgfr	%r3,%r3               # int			
        lgr     %r4,%r3               # move history1 parameter
	lgfr	%r2,%r2               # int			
        lgr     %r3,%r2               # move history0 parameter
        la      %r2,SP_PTREGS(%r15)   # load pt_regs as first parameter
	la      %r14,6(%r14)          # skip store of return value
        jg      sys32_sigsuspend      # branch to sys32_sigsuspend
#endif

sys_rt_sigsuspend_glue: 
        lgr     %r4,%r3               # move sigsetsize parameter
        lgr     %r3,%r2               # move unewset parameter
        la      %r2,SP_PTREGS(%r15)   # load pt_regs as first parameter
	la      %r14,6(%r14)          # skip store of return value
        jg      sys_rt_sigsuspend     # branch to sys_rt_sigsuspend

#ifdef CONFIG_COMPAT
sys32_rt_sigsuspend_glue: 
	llgfr	%r3,%r3               # size_t			
        lgr     %r4,%r3               # move sigsetsize parameter
	llgtr	%r2,%r2               # sigset_emu31_t *
        lgr     %r3,%r2               # move unewset parameter
        la      %r2,SP_PTREGS(%r15)   # load pt_regs as first parameter
	la      %r14,6(%r14)          # skip store of return value
        jg      sys32_rt_sigsuspend   # branch to sys32_rt_sigsuspend
#endif

sys_sigaltstack_glue:
        la      %r4,SP_PTREGS(%r15)   # load pt_regs as parameter
        jg      sys_sigaltstack       # branch to sys_sigreturn
@@ -646,15 +599,16 @@ io_work:
	lgr	%r15,%r1
#
# One of the work bits is on. Find out which one.
# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING
# Checked are: _TIF_SIGPENDING, _TIF_RESTORE_SIGPENDING, _TIF_NEED_RESCHED
#	       and _TIF_MCCK_PENDING
#
io_work_loop:
	tm	__TI_flags+7(%r9),_TIF_MCCK_PENDING
	jo	io_mcck_pending
	tm	__TI_flags+7(%r9),_TIF_NEED_RESCHED
	jo	io_reschedule
	tm	__TI_flags+7(%r9),_TIF_SIGPENDING
	jo	io_sigpending
	tm	__TI_flags+7(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
	jnz	io_sigpending
	j	io_leave

#
@@ -676,12 +630,11 @@ io_reschedule:
	j	io_work_loop

#
# _TIF_SIGPENDING is set, call do_signal
# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
#
io_sigpending:     
	stosm   __SF_EMPTY(%r15),0x03	# reenable interrupts
	la      %r2,SP_PTREGS(%r15)	# load pt_regs
	slgr    %r3,%r3			# clear *oldset
	brasl	%r14,do_signal		# call do_signal
	stnsm   __SF_EMPTY(%r15),0xfc	# disable I/O and ext. interrupts
	j	io_work_loop
+71 −75
Original line number Diff line number Diff line
/*
 *  arch/s390/kernel/signal.c
 *
 *  S390 version
 *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *    Copyright (C) IBM Corp. 1999,2006
 *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
 *
 *    Based on Intel version
@@ -51,60 +50,24 @@ typedef struct
	struct ucontext uc;
} rt_sigframe;

int do_signal(struct pt_regs *regs, sigset_t *oldset);

/*
 * Atomically swap in the new signal mask, and wait for a signal.
 */
asmlinkage int
sys_sigsuspend(struct pt_regs * regs, int history0, int history1,
	       old_sigset_t mask)
sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
	sigset_t saveset;

	mask &= _BLOCKABLE;
	spin_lock_irq(&current->sighand->siglock);
	saveset = current->blocked;
	current->saved_sigmask = current->blocked;
	siginitset(&current->blocked, mask);
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);
	regs->gprs[2] = -EINTR;

	while (1) {
		set_current_state(TASK_INTERRUPTIBLE);
	current->state = TASK_INTERRUPTIBLE;
	schedule();
		if (do_signal(regs, &saveset))
			return -EINTR;
	}
}

asmlinkage long
sys_rt_sigsuspend(struct pt_regs *regs, sigset_t __user *unewset,
						size_t sigsetsize)
{
	sigset_t saveset, newset;

	/* XXX: Don't preclude handling different sized sigset_t's.  */
	if (sigsetsize != sizeof(sigset_t))
		return -EINVAL;

	if (copy_from_user(&newset, unewset, sizeof(newset)))
		return -EFAULT;
	sigdelsetmask(&newset, ~_BLOCKABLE);
	set_thread_flag(TIF_RESTORE_SIGMASK);

	spin_lock_irq(&current->sighand->siglock);
	saveset = current->blocked;
	current->blocked = newset;
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);
	regs->gprs[2] = -EINTR;

	while (1) {
		set_current_state(TASK_INTERRUPTIBLE);
		schedule();
		if (do_signal(regs, &saveset))
			return -EINTR;
	}
	return -ERESTARTNOHAND;
}

asmlinkage long
@@ -306,7 +269,7 @@ static inline int map_signal(int sig)
		return sig;
}

static void setup_frame(int sig, struct k_sigaction *ka,
static int setup_frame(int sig, struct k_sigaction *ka,
		       sigset_t *set, struct pt_regs * regs)
{
	sigframe __user *frame;
@@ -355,13 +318,14 @@ static void setup_frame(int sig, struct k_sigaction *ka,
	/* Place signal number on stack to allow backtrace from handler.  */
	if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
		goto give_sigsegv;
	return;
	return 0;

give_sigsegv:
	force_sigsegv(sig, current);
	return -EFAULT;
}

static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
			   sigset_t *set, struct pt_regs * regs)
{
	int err = 0;
@@ -409,26 +373,30 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
	regs->gprs[2] = map_signal(sig);
	regs->gprs[3] = (unsigned long) &frame->info;
	regs->gprs[4] = (unsigned long) &frame->uc;
	return;
	return 0;

give_sigsegv:
	force_sigsegv(sig, current);
	return -EFAULT;
}

/*
 * OK, we're invoking a handler
 */	

static void
static int
handle_signal(unsigned long sig, struct k_sigaction *ka,
	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
{
	int ret;

	/* Set up the stack frame */
	if (ka->sa.sa_flags & SA_SIGINFO)
		setup_rt_frame(sig, ka, info, oldset, regs);
		ret = setup_rt_frame(sig, ka, info, oldset, regs);
	else
		setup_frame(sig, ka, oldset, regs);
		ret = setup_frame(sig, ka, oldset, regs);

	if (ret == 0) {
		spin_lock_irq(&current->sighand->siglock);
		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
		if (!(ka->sa.sa_flags & SA_NODEFER))
@@ -437,6 +405,9 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
		spin_unlock_irq(&current->sighand->siglock);
	}

	return ret;
}

/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -446,12 +417,13 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 */
int do_signal(struct pt_regs *regs, sigset_t *oldset)
void do_signal(struct pt_regs *regs)
{
	unsigned long retval = 0, continue_addr = 0, restart_addr = 0;
	siginfo_t info;
	int signr;
	struct k_sigaction ka;
	sigset_t *oldset;

	/*
	 * We want the common case to go fast, which
@@ -460,9 +432,11 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
	 * if so.
	 */
	if (!user_mode(regs))
		return 1;
		return;

	if (!oldset)
	if (test_thread_flag(TIF_RESTORE_SIGMASK))
		oldset = &current->saved_sigmask;
	else
		oldset = &current->blocked;

	/* Are we from a system call? */
@@ -473,12 +447,14 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)

		/* Prepare for system call restart.  We do this here so that a
		   debugger will see the already changed PSW. */
		if (retval == -ERESTARTNOHAND ||
		    retval == -ERESTARTSYS ||
		    retval == -ERESTARTNOINTR) {
		switch (retval) {
		case -ERESTARTNOHAND:
		case -ERESTARTSYS:
		case -ERESTARTNOINTR:
			regs->gprs[2] = regs->orig_gpr2;
			regs->psw.addr = restart_addr;
		} else if (retval == -ERESTART_RESTARTBLOCK) {
			break;
		case -ERESTART_RESTARTBLOCK:
			regs->gprs[2] = -EINTR;
		}
	}
@@ -503,17 +479,38 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
		/* Whee!  Actually deliver the signal.  */
#ifdef CONFIG_COMPAT
		if (test_thread_flag(TIF_31BIT)) {
			extern void handle_signal32(unsigned long sig,
			extern int handle_signal32(unsigned long sig,
						   struct k_sigaction *ka,
						   siginfo_t *info,
						   sigset_t *oldset,
						   struct pt_regs *regs);
			handle_signal32(signr, &ka, &info, oldset, regs);
			return 1;
			if (handle_signal32(
				    signr, &ka, &info, oldset, regs) == 0) {
				if (test_thread_flag(TIF_RESTORE_SIGMASK))
					clear_thread_flag(TIF_RESTORE_SIGMASK);
			}
			return;
	        }
#endif
		handle_signal(signr, &ka, &info, oldset, regs);
		return 1;
		if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
			/*
			 * A signal was successfully delivered; the saved
			 * sigmask will have been stored in the signal frame,
			 * and will be restored by sigreturn, so we can simply
			 * clear the TIF_RESTORE_SIGMASK flag.
			 */
			if (test_thread_flag(TIF_RESTORE_SIGMASK))
				clear_thread_flag(TIF_RESTORE_SIGMASK);
		}
		return;
	}

	/*
	 * If there's no signal to deliver, we just put the saved sigmask back.
	 */
	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
		clear_thread_flag(TIF_RESTORE_SIGMASK);
		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
	}

	/* Restart a different system call. */
@@ -522,5 +519,4 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
		regs->gprs[2] = __NR_restart_syscall;
		set_thread_flag(TIF_RESTART_SVC);
	}
	return 0;
}
Loading