Blame view

arch/um/kernel/signal.c 4.81 KB
1d3468a66   Jeff Dike   [PATCH] uml: move...
1
  /*
ba180fd43   Jeff Dike   uml: style fixes ...
2
   * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
   * Licensed under the GPL
   */
c5d4bb171   Jeff Dike   uml: style fixes ...
5
6
7
8
9
10
  #include <linux/module.h>
  #include <linux/ptrace.h>
  #include <linux/sched.h>
  #include <asm/siginfo.h>
  #include <asm/signal.h>
  #include <asm/unistd.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include "frame_kern.h"
ba180fd43   Jeff Dike   uml: style fixes ...
12
  #include "kern_util.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
17
18
19
20
21
22
  
  EXPORT_SYMBOL(block_signals);
  EXPORT_SYMBOL(unblock_signals);
  
  #define _S(nr) (1<<((nr)-1))
  
  #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  
  /*
   * OK, we're invoking a handler
1d3468a66   Jeff Dike   [PATCH] uml: move...
23
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
30
31
32
33
34
  static int handle_signal(struct pt_regs *regs, unsigned long signr,
  			 struct k_sigaction *ka, siginfo_t *info,
  			 sigset_t *oldset)
  {
  	unsigned long sp;
  	int err;
  
  	/* Always make any pending restarted system calls return -EINTR */
  	current_thread_info()->restart_block.fn = do_no_restart_syscall;
  
  	/* Did we come from a system call? */
ba180fd43   Jeff Dike   uml: style fixes ...
35
  	if (PT_REGS_SYSCALL_NR(regs) >= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  		/* If so, check system call restarting.. */
c5d4bb171   Jeff Dike   uml: style fixes ...
37
  		switch (PT_REGS_SYSCALL_RET(regs)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  		case -ERESTART_RESTARTBLOCK:
  		case -ERESTARTNOHAND:
  			PT_REGS_SYSCALL_RET(regs) = -EINTR;
  			break;
  
  		case -ERESTARTSYS:
  			if (!(ka->sa.sa_flags & SA_RESTART)) {
  				PT_REGS_SYSCALL_RET(regs) = -EINTR;
  				break;
  			}
  		/* fallthrough */
  		case -ERESTARTNOINTR:
  			PT_REGS_RESTART_SYSCALL(regs);
  			PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
  			break;
  		}
  	}
  
  	sp = PT_REGS_SP(regs);
ba180fd43   Jeff Dike   uml: style fixes ...
57
  	if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
  		sp = current->sas_ss_sp + current->sas_ss_size;
  
  #ifdef CONFIG_ARCH_HAS_SC_SIGNALS
ba180fd43   Jeff Dike   uml: style fixes ...
61
  	if (!(ka->sa.sa_flags & SA_SIGINFO))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
  		err = setup_signal_stack_sc(sp, signr, ka, regs, oldset);
  	else
  #endif
  		err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset);
ba180fd43   Jeff Dike   uml: style fixes ...
66
  	if (err) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
  		spin_lock_irq(&current->sighand->siglock);
  		current->blocked = *oldset;
  		recalc_sigpending();
  		spin_unlock_irq(&current->sighand->siglock);
  		force_sigsegv(signr, current);
69be8f189   Steven Rostedt   [PATCH] convert s...
72
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
  		spin_lock_irq(&current->sighand->siglock);
1d3468a66   Jeff Dike   [PATCH] uml: move...
74
  		sigorsets(&current->blocked, &current->blocked,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  			  &ka->sa.sa_mask);
ba180fd43   Jeff Dike   uml: style fixes ...
76
  		if (!(ka->sa.sa_flags & SA_NODEFER))
69be8f189   Steven Rostedt   [PATCH] convert s...
77
  			sigaddset(&current->blocked, signr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
81
82
83
  		recalc_sigpending();
  		spin_unlock_irq(&current->sighand->siglock);
  	}
  
  	return err;
  }
2fc10620e   Jeff Dike   [PATCH] uml: add ...
84
  static int kern_do_signal(struct pt_regs *regs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
  {
  	struct k_sigaction ka_copy;
  	siginfo_t info;
2fc10620e   Jeff Dike   [PATCH] uml: add ...
88
  	sigset_t *oldset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  	int sig, handled_sig = 0;
2fc10620e   Jeff Dike   [PATCH] uml: add ...
90
91
92
93
  	if (test_thread_flag(TIF_RESTORE_SIGMASK))
  		oldset = &current->saved_sigmask;
  	else
  		oldset = &current->blocked;
ba180fd43   Jeff Dike   uml: style fixes ...
94
  	while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
  		handled_sig = 1;
  		/* Whee!  Actually deliver the signal.  */
ba180fd43   Jeff Dike   uml: style fixes ...
97
98
99
  		if (!handle_signal(regs, sig, &ka_copy, &info, oldset)) {
  			/*
  			 * a signal was successfully delivered; the saved
2fc10620e   Jeff Dike   [PATCH] uml: add ...
100
101
  			 * sigmask will have been stored in the signal frame,
  			 * and will be restored by sigreturn, so we can simply
ba180fd43   Jeff Dike   uml: style fixes ...
102
103
  			 * clear the TIF_RESTORE_SIGMASK flag
  			 */
2fc10620e   Jeff Dike   [PATCH] uml: add ...
104
105
  			if (test_thread_flag(TIF_RESTORE_SIGMASK))
  				clear_thread_flag(TIF_RESTORE_SIGMASK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  			break;
2fc10620e   Jeff Dike   [PATCH] uml: add ...
107
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
  	}
  
  	/* Did we come from a system call? */
ba180fd43   Jeff Dike   uml: style fixes ...
111
  	if (!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  		/* Restart the system call - no handlers present */
c5d4bb171   Jeff Dike   uml: style fixes ...
113
  		switch (PT_REGS_SYSCALL_RET(regs)) {
2fc10620e   Jeff Dike   [PATCH] uml: add ...
114
115
116
  		case -ERESTARTNOHAND:
  		case -ERESTARTSYS:
  		case -ERESTARTNOINTR:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
  			PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
  			PT_REGS_RESTART_SYSCALL(regs);
2fc10620e   Jeff Dike   [PATCH] uml: add ...
119
120
  			break;
  		case -ERESTART_RESTARTBLOCK:
1d3468a66   Jeff Dike   [PATCH] uml: move...
121
  			PT_REGS_ORIG_SYSCALL(regs) = __NR_restart_syscall;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  			PT_REGS_RESTART_SYSCALL(regs);
2fc10620e   Jeff Dike   [PATCH] uml: add ...
123
  			break;
ba180fd43   Jeff Dike   uml: style fixes ...
124
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  	}
ba180fd43   Jeff Dike   uml: style fixes ...
126
127
  	/*
  	 * This closes a way to execute a system call on the host.  If
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
  	 * you set a breakpoint on a system call instruction and singlestep
  	 * from it, the tracing thread used to PTRACE_SINGLESTEP the process
  	 * rather than PTRACE_SYSCALL it, allowing the system call to execute
1d3468a66   Jeff Dike   [PATCH] uml: move...
131
  	 * on the host.  The tracing thread will check this flag and
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
  	 * PTRACE_SYSCALL if necessary.
  	 */
ba180fd43   Jeff Dike   uml: style fixes ...
134
  	if (current->ptrace & PT_DTRACE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
  		current->thread.singlestep_syscall =
  			is_syscall(PT_REGS_IP(&current->thread.regs));
2fc10620e   Jeff Dike   [PATCH] uml: add ...
137

ba180fd43   Jeff Dike   uml: style fixes ...
138
139
140
141
  	/*
  	 * if there's no signal to deliver, we just put the saved sigmask
  	 * back
  	 */
2fc10620e   Jeff Dike   [PATCH] uml: add ...
142
143
144
145
  	if (!handled_sig && test_thread_flag(TIF_RESTORE_SIGMASK)) {
  		clear_thread_flag(TIF_RESTORE_SIGMASK);
  		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
  	}
7c7a89499   Jeff Dike   [PATCH] uml: fix ...
146
  	return handled_sig;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
  }
  
  int do_signal(void)
  {
7c7a89499   Jeff Dike   [PATCH] uml: fix ...
151
  	return kern_do_signal(&current->thread.regs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
155
156
157
158
  }
  
  /*
   * Atomically swap in the new signal mask, and wait for a signal.
   */
  long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
  	mask &= _BLOCKABLE;
  	spin_lock_irq(&current->sighand->siglock);
2fc10620e   Jeff Dike   [PATCH] uml: add ...
161
  	current->saved_sigmask = current->blocked;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
  	siginitset(&current->blocked, mask);
  	recalc_sigpending();
  	spin_unlock_irq(&current->sighand->siglock);
2fc10620e   Jeff Dike   [PATCH] uml: add ...
165
166
167
168
  	current->state = TASK_INTERRUPTIBLE;
  	schedule();
  	set_thread_flag(TIF_RESTORE_SIGMASK);
  	return -ERESTARTNOHAND;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
  long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
  {
7c7a89499   Jeff Dike   [PATCH] uml: fix ...
172
  	return do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  }