ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / um / kernel / signal_kern.c
1 /* 
2  * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3  * Licensed under the GPL
4  */
5
6 #include "linux/config.h"
7 #include "linux/stddef.h"
8 #include "linux/sys.h"
9 #include "linux/sched.h"
10 #include "linux/wait.h"
11 #include "linux/kernel.h"
12 #include "linux/smp_lock.h"
13 #include "linux/module.h"
14 #include "linux/slab.h"
15 #include "linux/tty.h"
16 #include "linux/binfmts.h"
17 #include "linux/ptrace.h"
18 #include "asm/signal.h"
19 #include "asm/uaccess.h"
20 #include "asm/unistd.h"
21 #include "user_util.h"
22 #include "asm/ucontext.h"
23 #include "kern_util.h"
24 #include "signal_kern.h"
25 #include "signal_user.h"
26 #include "kern.h"
27 #include "frame_kern.h"
28 #include "sigcontext.h"
29 #include "mode.h"
30
31 EXPORT_SYMBOL(block_signals);
32 EXPORT_SYMBOL(unblock_signals);
33
34 static void force_segv(int sig)
35 {
36         if(sig == SIGSEGV){
37                 struct k_sigaction *ka;
38
39                 ka = &current->sig->action[SIGSEGV - 1];
40                 ka->sa.sa_handler = SIG_DFL;
41         }
42         force_sig(SIGSEGV, current);
43 }
44
45 #define _S(nr) (1<<((nr)-1))
46
47 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
48
49 /*
50  * OK, we're invoking a handler
51  */     
52 static int handle_signal(struct pt_regs *regs, unsigned long signr, 
53                          struct k_sigaction *ka, siginfo_t *info, 
54                          sigset_t *oldset, int error)
55 {
56         __sighandler_t handler;
57         void (*restorer)(void);
58         unsigned long sp;
59         sigset_t save;
60         int err, ret;
61
62         ret = 0;
63         switch(error){
64         case -ERESTART_RESTARTBLOCK:
65                 current_thread_info()->restart_block.fn = 
66                         do_no_restart_syscall;
67         case -ERESTARTNOHAND:
68                 ret = -EINTR;
69                 break;
70
71         case -ERESTARTSYS:
72                 if (!(ka->sa.sa_flags & SA_RESTART)) {
73                         ret = -EINTR;
74                         break;
75                 }
76                 /* fallthrough */
77         case -ERESTARTNOINTR:
78                 PT_REGS_RESTART_SYSCALL(regs);
79                 PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
80
81                 /* This is because of the UM_SET_SYSCALL_RETURN and the fact
82                  * that on i386 the system call number and return value are
83                  * in the same register.  When the system call restarts, %eax
84                  * had better have the system call number in it.  Since the
85                  * return value doesn't matter (except that it shouldn't be
86                  * -ERESTART*), we'll stick the system call number there.
87                  */
88                 ret = PT_REGS_SYSCALL_NR(regs);
89                 break;
90         }
91
92         handler = ka->sa.sa_handler;
93         save = *oldset;
94
95         if (ka->sa.sa_flags & SA_ONESHOT)
96                 ka->sa.sa_handler = SIG_DFL;
97
98         if (!(ka->sa.sa_flags & SA_NODEFER)) {
99                 spin_lock_irq(&current->sighand->siglock);
100                 sigorsets(&current->blocked, &current->blocked, 
101                           &ka->sa.sa_mask);
102                 sigaddset(&current->blocked, signr);
103                 recalc_sigpending();
104                 spin_unlock_irq(&current->sighand->siglock);
105         }
106
107         sp = PT_REGS_SP(regs);
108
109         if((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
110                 sp = current->sas_ss_sp + current->sas_ss_size;
111         
112         if(error != 0) PT_REGS_SET_SYSCALL_RETURN(regs, ret);
113
114         if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer;
115         else restorer = NULL;
116
117         if(ka->sa.sa_flags & SA_SIGINFO)
118                 err = setup_signal_stack_si(sp, signr, (unsigned long) handler,
119                                             restorer, regs, info, &save);
120         else
121                 err = setup_signal_stack_sc(sp, signr, (unsigned long) handler,
122                                             restorer, regs, &save);
123         if(err) goto segv;
124
125         return(0);
126  segv:
127         force_segv(signr);
128         return(1);
129 }
130
131 static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error)
132 {
133         siginfo_t info;
134         struct k_sigaction *ka;
135         int err, sig;
136
137         if (!oldset)
138                 oldset = &current->blocked;
139
140         sig = get_signal_to_deliver(&info, regs, NULL);
141         if(sig == 0)
142                 return(0);
143
144         /* Whee!  Actually deliver the signal.  */
145         ka = &current->sig->action[sig -1 ];
146         err = handle_signal(regs, sig, ka, &info, oldset, error);
147         if(!err) return(1);
148
149         /* Did we come from a system call? */
150         if(PT_REGS_SYSCALL_NR(regs) >= 0){
151                 /* Restart the system call - no handlers present */
152                 if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND ||
153                    PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS ||
154                    PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){
155                         PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
156                         PT_REGS_RESTART_SYSCALL(regs);
157                 }
158                 else if(PT_REGS_SYSCALL_RET(regs) == -ERESTART_RESTARTBLOCK){
159                         PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall;
160                         PT_REGS_RESTART_SYSCALL(regs);
161                 }
162         }
163
164         /* This closes a way to execute a system call on the host.  If
165          * you set a breakpoint on a system call instruction and singlestep
166          * from it, the tracing thread used to PTRACE_SINGLESTEP the process
167          * rather than PTRACE_SYSCALL it, allowing the system call to execute
168          * on the host.  The tracing thread will check this flag and 
169          * PTRACE_SYSCALL if necessary.
170          */
171         if((current->ptrace & PT_DTRACE) && 
172            is_syscall(PT_REGS_IP(&current->thread.regs)))
173                 (void) CHOOSE_MODE(current->thread.mode.tt.singlestep_syscall = 1, 0);
174         return(0);
175 }
176
177 int do_signal(int error)
178 {
179         return(kern_do_signal(&current->thread.regs, NULL, error));
180 }
181
182 /*
183  * Atomically swap in the new signal mask, and wait for a signal.
184  */
185 int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
186 {
187         sigset_t saveset;
188
189         mask &= _BLOCKABLE;
190         spin_lock_irq(&current->sighand->siglock);
191         saveset = current->blocked;
192         siginitset(&current->blocked, mask);
193         recalc_sigpending();
194         spin_unlock_irq(&current->sighand->siglock);
195
196         while (1) {
197                 current->state = TASK_INTERRUPTIBLE;
198                 schedule();
199                 if(kern_do_signal(&current->thread.regs, &saveset, -EINTR))
200                         return(-EINTR);
201         }
202 }
203
204 int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
205 {
206         sigset_t saveset, newset;
207
208         /* XXX: Don't preclude handling different sized sigset_t's.  */
209         if (sigsetsize != sizeof(sigset_t))
210                 return -EINVAL;
211
212         if (copy_from_user(&newset, unewset, sizeof(newset)))
213                 return -EFAULT;
214         sigdelsetmask(&newset, ~_BLOCKABLE);
215
216         spin_lock_irq(&current->sighand->siglock);
217         saveset = current->blocked;
218         current->blocked = newset;
219         recalc_sigpending();
220         spin_unlock_irq(&current->sighand->siglock);
221
222         while (1) {
223                 current->state = TASK_INTERRUPTIBLE;
224                 schedule();
225                 if (kern_do_signal(&current->thread.regs, &saveset, -EINTR))
226                         return(-EINTR);
227         }
228 }
229
230 static int copy_sc_from_user(struct pt_regs *to, void *from, 
231                              struct arch_frame_data *arch)
232 {
233         int ret;
234
235         ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch),
236                           copy_sc_from_user_skas(&to->regs, from));
237         return(ret);
238 }
239
240 int sys_sigreturn(struct pt_regs regs)
241 {
242         void *sc = sp_to_sc(PT_REGS_SP(&current->thread.regs));
243         void *mask = sp_to_mask(PT_REGS_SP(&current->thread.regs));
244         int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
245
246         spin_lock_irq(&current->sighand->siglock);
247         copy_from_user(&current->blocked.sig[0], sc_sigmask(sc), 
248                        sizeof(current->blocked.sig[0]));
249         copy_from_user(&current->blocked.sig[1], mask, sig_size);
250         sigdelsetmask(&current->blocked, ~_BLOCKABLE);
251         recalc_sigpending();
252         spin_unlock_irq(&current->sighand->siglock);
253         copy_sc_from_user(&current->thread.regs, sc, 
254                           &signal_frame_sc.common.arch);
255         return(PT_REGS_SYSCALL_RET(&current->thread.regs));
256 }
257
258 int sys_rt_sigreturn(struct pt_regs regs)
259 {
260         struct ucontext *uc = sp_to_uc(PT_REGS_SP(&current->thread.regs));
261         void *fp;
262         int sig_size = _NSIG_WORDS * sizeof(unsigned long);
263
264         spin_lock_irq(&current->sighand->siglock);
265         copy_from_user(&current->blocked, &uc->uc_sigmask, sig_size);
266         sigdelsetmask(&current->blocked, ~_BLOCKABLE);
267         recalc_sigpending();
268         spin_unlock_irq(&current->sighand->siglock);
269         fp = (void *) (((unsigned long) uc) + sizeof(struct ucontext));
270         copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext,
271                           &signal_frame_si.common.arch);
272         return(PT_REGS_SYSCALL_RET(&current->thread.regs));
273 }
274
275 /*
276  * Overrides for Emacs so that we follow Linus's tabbing style.
277  * Emacs will notice this stuff at the end of the file and automatically
278  * adjust the settings for this buffer only.  This must remain at the end
279  * of the file.
280  * ---------------------------------------------------------------------------
281  * Local variables:
282  * c-file-style: "linux"
283  * End:
284  */