upgrade to linux 2.6.10-1.12_FC2
[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 #define _S(nr) (1<<((nr)-1))
35
36 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
37
38 /*
39  * OK, we're invoking a handler
40  */     
41 static int handle_signal(struct pt_regs *regs, unsigned long signr,
42                          struct k_sigaction *ka, siginfo_t *info,
43                          sigset_t *oldset)
44 {
45         unsigned long sp;
46         int err;
47
48         /* Always make any pending restarted system calls return -EINTR */
49         current_thread_info()->restart_block.fn = do_no_restart_syscall;
50
51         /* Did we come from a system call? */
52         if(PT_REGS_SYSCALL_NR(regs) >= 0){
53                 /* If so, check system call restarting.. */
54                 switch(PT_REGS_SYSCALL_RET(regs)){
55                 case -ERESTART_RESTARTBLOCK:
56                 case -ERESTARTNOHAND:
57                         PT_REGS_SYSCALL_RET(regs) = -EINTR;
58                         break;
59
60                 case -ERESTARTSYS:
61                         if (!(ka->sa.sa_flags & SA_RESTART)) {
62                                 PT_REGS_SYSCALL_RET(regs) = -EINTR;
63                                 break;
64                         }
65                 /* fallthrough */
66                 case -ERESTARTNOINTR:
67                         PT_REGS_RESTART_SYSCALL(regs);
68                         PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
69                         break;
70                 }
71         }
72
73         sp = PT_REGS_SP(regs);
74         if((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
75                 sp = current->sas_ss_sp + current->sas_ss_size;
76
77         if(ka->sa.sa_flags & SA_SIGINFO)
78                 err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset);
79         else
80                 err = setup_signal_stack_sc(sp, signr, ka, regs, oldset);
81
82         if(err){
83                 spin_lock_irq(&current->sighand->siglock);
84                 current->blocked = *oldset;
85                 recalc_sigpending();
86                 spin_unlock_irq(&current->sighand->siglock);
87                 force_sigsegv(signr, current);
88         }
89         else if(!(ka->sa.sa_flags & SA_NODEFER)){
90                 spin_lock_irq(&current->sighand->siglock);
91                 sigorsets(&current->blocked, &current->blocked, 
92                           &ka->sa.sa_mask);
93                 sigaddset(&current->blocked, signr);
94                 recalc_sigpending();
95                 spin_unlock_irq(&current->sighand->siglock);
96         }
97
98         return err;
99 }
100
101 static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset)
102 {
103         struct k_sigaction ka_copy;
104         siginfo_t info;
105         int sig, handled_sig = 0;
106
107         while((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0){
108                 handled_sig = 1;
109                 /* Whee!  Actually deliver the signal.  */
110                 if(!handle_signal(regs, sig, &ka_copy, &info, oldset))
111                         break;
112         }
113
114         /* Did we come from a system call? */
115         if(!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)){
116                 /* Restart the system call - no handlers present */
117                 if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND ||
118                    PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS ||
119                    PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){
120                         PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
121                         PT_REGS_RESTART_SYSCALL(regs);
122                 }
123                 else if(PT_REGS_SYSCALL_RET(regs) == -ERESTART_RESTARTBLOCK){
124                         PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall;
125                         PT_REGS_RESTART_SYSCALL(regs);
126                 }
127         }
128
129         /* This closes a way to execute a system call on the host.  If
130          * you set a breakpoint on a system call instruction and singlestep
131          * from it, the tracing thread used to PTRACE_SINGLESTEP the process
132          * rather than PTRACE_SYSCALL it, allowing the system call to execute
133          * on the host.  The tracing thread will check this flag and 
134          * PTRACE_SYSCALL if necessary.
135          */
136         if(current->ptrace & PT_DTRACE)
137                 current->thread.singlestep_syscall =
138                         is_syscall(PT_REGS_IP(&current->thread.regs));
139         return(handled_sig);
140 }
141
142 int do_signal(void)
143 {
144         return(kern_do_signal(&current->thread.regs, &current->blocked));
145 }
146
147 /*
148  * Atomically swap in the new signal mask, and wait for a signal.
149  */
150 long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
151 {
152         sigset_t saveset;
153
154         mask &= _BLOCKABLE;
155         spin_lock_irq(&current->sighand->siglock);
156         saveset = current->blocked;
157         siginitset(&current->blocked, mask);
158         recalc_sigpending();
159         spin_unlock_irq(&current->sighand->siglock);
160
161         PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
162         while (1) {
163                 current->state = TASK_INTERRUPTIBLE;
164                 schedule();
165                 if(kern_do_signal(&current->thread.regs, &saveset))
166                         return(-EINTR);
167         }
168 }
169
170 long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
171 {
172         sigset_t saveset, newset;
173
174         /* XXX: Don't preclude handling different sized sigset_t's.  */
175         if (sigsetsize != sizeof(sigset_t))
176                 return -EINVAL;
177
178         if (copy_from_user(&newset, unewset, sizeof(newset)))
179                 return -EFAULT;
180         sigdelsetmask(&newset, ~_BLOCKABLE);
181
182         spin_lock_irq(&current->sighand->siglock);
183         saveset = current->blocked;
184         current->blocked = newset;
185         recalc_sigpending();
186         spin_unlock_irq(&current->sighand->siglock);
187
188         PT_REGS_SYSCALL_RET(&current->thread.regs) = -EINTR;
189         while (1) {
190                 current->state = TASK_INTERRUPTIBLE;
191                 schedule();
192                 if (kern_do_signal(&current->thread.regs, &saveset))
193                         return(-EINTR);
194         }
195 }
196
197 int sys_sigaction(int sig, const struct old_sigaction __user *act,
198                          struct old_sigaction __user *oact)
199 {
200         struct k_sigaction new_ka, old_ka;
201         int ret;
202
203         if (act) {
204                 old_sigset_t mask;
205                 if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
206                     __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
207                     __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
208                         return -EFAULT;
209                 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
210                 __get_user(mask, &act->sa_mask);
211                 siginitset(&new_ka.sa.sa_mask, mask);
212         }
213
214         ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
215
216         if (!ret && oact) {
217                 if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
218                     __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
219                     __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
220                         return -EFAULT;
221                 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
222                 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
223         }
224
225         return ret;
226 }
227
228 long sys_sigaltstack(const stack_t *uss, stack_t *uoss)
229 {
230         return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
231 }
232
233 extern int userspace_pid[];
234
235 static int copy_sc_from_user(struct pt_regs *to, void *from, 
236                              struct arch_frame_data *arch)
237 {
238         int ret;
239
240         ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch),
241                           copy_sc_from_user_skas(userspace_pid[0],
242                                                  &to->regs, from));
243         return(ret);
244 }
245
246 long sys_sigreturn(struct pt_regs regs)
247 {
248         void __user *sc = sp_to_sc(PT_REGS_SP(&current->thread.regs));
249         void __user *mask = sp_to_mask(PT_REGS_SP(&current->thread.regs));
250         int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
251
252         spin_lock_irq(&current->sighand->siglock);
253         copy_from_user(&current->blocked.sig[0], sc_sigmask(sc), 
254                        sizeof(current->blocked.sig[0]));
255         copy_from_user(&current->blocked.sig[1], mask, sig_size);
256         sigdelsetmask(&current->blocked, ~_BLOCKABLE);
257         recalc_sigpending();
258         spin_unlock_irq(&current->sighand->siglock);
259         copy_sc_from_user(&current->thread.regs, sc, 
260                           &signal_frame_sc.common.arch);
261         return(PT_REGS_SYSCALL_RET(&current->thread.regs));
262 }
263
264 long sys_rt_sigreturn(struct pt_regs regs)
265 {
266         unsigned long sp = PT_REGS_SP(&current->thread.regs);
267         struct ucontext __user *uc = sp_to_uc(sp);
268         int sig_size = _NSIG_WORDS * sizeof(unsigned long);
269
270         spin_lock_irq(&current->sighand->siglock);
271         copy_from_user(&current->blocked, &uc->uc_sigmask, sig_size);
272         sigdelsetmask(&current->blocked, ~_BLOCKABLE);
273         recalc_sigpending();
274         spin_unlock_irq(&current->sighand->siglock);
275         copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext,
276                           &signal_frame_si.common.arch);
277         return(PT_REGS_SYSCALL_RET(&current->thread.regs));
278 }
279
280 /*
281  * Overrides for Emacs so that we follow Linus's tabbing style.
282  * Emacs will notice this stuff at the end of the file and automatically
283  * adjust the settings for this buffer only.  This must remain at the end
284  * of the file.
285  * ---------------------------------------------------------------------------
286  * Local variables:
287  * c-file-style: "linux"
288  * End:
289  */