1eb21a023e33466e9e2bc7127c08a4db8154e851
[safe/jmp/linux-2.6] / arch / um / sys-i386 / signal.c
1 /*
2  * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3  * Licensed under the GPL
4  */
5
6 #include "linux/ptrace.h"
7 #include "asm/unistd.h"
8 #include "asm/uaccess.h"
9 #include "asm/ucontext.h"
10 #include "frame_kern.h"
11 #include "skas.h"
12
13 void copy_sc(struct uml_pt_regs *regs, void *from)
14 {
15         struct sigcontext *sc = from;
16
17         REGS_GS(regs->gp) = sc->gs;
18         REGS_FS(regs->gp) = sc->fs;
19         REGS_ES(regs->gp) = sc->es;
20         REGS_DS(regs->gp) = sc->ds;
21         REGS_EDI(regs->gp) = sc->edi;
22         REGS_ESI(regs->gp) = sc->esi;
23         REGS_EBP(regs->gp) = sc->ebp;
24         REGS_SP(regs->gp) = sc->esp;
25         REGS_EBX(regs->gp) = sc->ebx;
26         REGS_EDX(regs->gp) = sc->edx;
27         REGS_ECX(regs->gp) = sc->ecx;
28         REGS_EAX(regs->gp) = sc->eax;
29         REGS_IP(regs->gp) = sc->eip;
30         REGS_CS(regs->gp) = sc->cs;
31         REGS_EFLAGS(regs->gp) = sc->eflags;
32         REGS_SS(regs->gp) = sc->ss;
33 }
34
35 static int copy_sc_from_user(struct pt_regs *regs,
36                              struct sigcontext __user *from)
37 {
38         struct sigcontext sc;
39         unsigned long fpregs[HOST_FP_SIZE];
40         int err;
41
42         err = copy_from_user(&sc, from, sizeof(sc));
43         err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs));
44         if (err)
45                 return err;
46
47         copy_sc(&regs->regs, &sc);
48
49         err = restore_fp_registers(userspace_pid[0], fpregs);
50         if (err < 0) {
51                 printk(KERN_ERR "copy_sc_from_user_skas - PTRACE_SETFPREGS "
52                        "failed, errno = %d\n", -err);
53                 return err;
54         }
55
56         return 0;
57 }
58
59 static int copy_sc_to_user(struct sigcontext __user *to,
60                            struct _fpstate __user *to_fp, struct pt_regs *regs,
61                            unsigned long sp)
62 {
63         struct sigcontext sc;
64         unsigned long fpregs[HOST_FP_SIZE];
65         struct faultinfo * fi = &current->thread.arch.faultinfo;
66         int err;
67
68         sc.gs = REGS_GS(regs->regs.gp);
69         sc.fs = REGS_FS(regs->regs.gp);
70         sc.es = REGS_ES(regs->regs.gp);
71         sc.ds = REGS_DS(regs->regs.gp);
72         sc.edi = REGS_EDI(regs->regs.gp);
73         sc.esi = REGS_ESI(regs->regs.gp);
74         sc.ebp = REGS_EBP(regs->regs.gp);
75         sc.esp = sp;
76         sc.ebx = REGS_EBX(regs->regs.gp);
77         sc.edx = REGS_EDX(regs->regs.gp);
78         sc.ecx = REGS_ECX(regs->regs.gp);
79         sc.eax = REGS_EAX(regs->regs.gp);
80         sc.eip = REGS_IP(regs->regs.gp);
81         sc.cs = REGS_CS(regs->regs.gp);
82         sc.eflags = REGS_EFLAGS(regs->regs.gp);
83         sc.esp_at_signal = regs->regs.gp[UESP];
84         sc.ss = regs->regs.gp[SS];
85         sc.cr2 = fi->cr2;
86         sc.err = fi->error_code;
87         sc.trapno = fi->trap_no;
88
89         err = save_fp_registers(userspace_pid[0], fpregs);
90         if (err < 0) {
91                 printk(KERN_ERR "copy_sc_to_user_skas - PTRACE_GETFPREGS "
92                        "failed, errno = %d\n", err);
93                 return 1;
94         }
95         to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1));
96         sc.fpstate = to_fp;
97
98         if (err)
99                 return err;
100
101         return copy_to_user(to, &sc, sizeof(sc)) ||
102                copy_to_user(to_fp, fpregs, sizeof(fpregs));
103 }
104
105 static int copy_ucontext_to_user(struct ucontext __user *uc,
106                                  struct _fpstate __user *fp, sigset_t *set,
107                                  unsigned long sp)
108 {
109         int err = 0;
110
111         err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
112         err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
113         err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
114         err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs, sp);
115         err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
116         return err;
117 }
118
119 struct sigframe
120 {
121         char __user *pretcode;
122         int sig;
123         struct sigcontext sc;
124         struct _fpstate fpstate;
125         unsigned long extramask[_NSIG_WORDS-1];
126         char retcode[8];
127 };
128
129 struct rt_sigframe
130 {
131         char __user *pretcode;
132         int sig;
133         struct siginfo __user *pinfo;
134         void __user *puc;
135         struct siginfo info;
136         struct ucontext uc;
137         struct _fpstate fpstate;
138         char retcode[8];
139 };
140
141 int setup_signal_stack_sc(unsigned long stack_top, int sig,
142                           struct k_sigaction *ka, struct pt_regs *regs,
143                           sigset_t *mask)
144 {
145         struct sigframe __user *frame;
146         void __user *restorer;
147         unsigned long save_sp = PT_REGS_SP(regs);
148         int err = 0;
149
150         /* This is the same calculation as i386 - ((sp + 4) & 15) == 0 */
151         stack_top = ((stack_top + 4) & -16UL) - 4;
152         frame = (struct sigframe __user *) stack_top - 1;
153         if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
154                 return 1;
155
156         restorer = frame->retcode;
157         if (ka->sa.sa_flags & SA_RESTORER)
158                 restorer = ka->sa.sa_restorer;
159
160         /* Update SP now because the page fault handler refuses to extend
161          * the stack if the faulting address is too far below the current
162          * SP, which frame now certainly is.  If there's an error, the original
163          * value is restored on the way out.
164          * When writing the sigcontext to the stack, we have to write the
165          * original value, so that's passed to copy_sc_to_user, which does
166          * the right thing with it.
167          */
168         PT_REGS_SP(regs) = (unsigned long) frame;
169
170         err |= __put_user(restorer, &frame->pretcode);
171         err |= __put_user(sig, &frame->sig);
172         err |= copy_sc_to_user(&frame->sc, NULL, regs, save_sp);
173         err |= __put_user(mask->sig[0], &frame->sc.oldmask);
174         if (_NSIG_WORDS > 1)
175                 err |= __copy_to_user(&frame->extramask, &mask->sig[1],
176                                       sizeof(frame->extramask));
177
178         /*
179          * This is popl %eax ; movl $,%eax ; int $0x80
180          *
181          * WE DO NOT USE IT ANY MORE! It's only left here for historical
182          * reasons and because gdb uses it as a signature to notice
183          * signal handler stack frames.
184          */
185         err |= __put_user(0xb858, (short __user *)(frame->retcode+0));
186         err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2));
187         err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
188
189         if (err)
190                 goto err;
191
192         PT_REGS_SP(regs) = (unsigned long) frame;
193         PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
194         PT_REGS_EAX(regs) = (unsigned long) sig;
195         PT_REGS_EDX(regs) = (unsigned long) 0;
196         PT_REGS_ECX(regs) = (unsigned long) 0;
197
198         if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
199                 ptrace_notify(SIGTRAP);
200         return 0;
201
202 err:
203         PT_REGS_SP(regs) = save_sp;
204         return err;
205 }
206
207 int setup_signal_stack_si(unsigned long stack_top, int sig,
208                           struct k_sigaction *ka, struct pt_regs *regs,
209                           siginfo_t *info, sigset_t *mask)
210 {
211         struct rt_sigframe __user *frame;
212         void __user *restorer;
213         unsigned long save_sp = PT_REGS_SP(regs);
214         int err = 0;
215
216         stack_top &= -8UL;
217         frame = (struct rt_sigframe __user *) stack_top - 1;
218         if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
219                 return 1;
220
221         restorer = frame->retcode;
222         if (ka->sa.sa_flags & SA_RESTORER)
223                 restorer = ka->sa.sa_restorer;
224
225         /* See comment above about why this is here */
226         PT_REGS_SP(regs) = (unsigned long) frame;
227
228         err |= __put_user(restorer, &frame->pretcode);
229         err |= __put_user(sig, &frame->sig);
230         err |= __put_user(&frame->info, &frame->pinfo);
231         err |= __put_user(&frame->uc, &frame->puc);
232         err |= copy_siginfo_to_user(&frame->info, info);
233         err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask,
234                                      save_sp);
235
236         /*
237          * This is movl $,%eax ; int $0x80
238          *
239          * WE DO NOT USE IT ANY MORE! It's only left here for historical
240          * reasons and because gdb uses it as a signature to notice
241          * signal handler stack frames.
242          */
243         err |= __put_user(0xb8, (char __user *)(frame->retcode+0));
244         err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1));
245         err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
246
247         if (err)
248                 goto err;
249
250         PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
251         PT_REGS_EAX(regs) = (unsigned long) sig;
252         PT_REGS_EDX(regs) = (unsigned long) &frame->info;
253         PT_REGS_ECX(regs) = (unsigned long) &frame->uc;
254
255         if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
256                 ptrace_notify(SIGTRAP);
257         return 0;
258
259 err:
260         PT_REGS_SP(regs) = save_sp;
261         return err;
262 }
263
264 long sys_sigreturn(struct pt_regs regs)
265 {
266         unsigned long sp = PT_REGS_SP(&current->thread.regs);
267         struct sigframe __user *frame = (struct sigframe __user *)(sp - 8);
268         sigset_t set;
269         struct sigcontext __user *sc = &frame->sc;
270         unsigned long __user *oldmask = &sc->oldmask;
271         unsigned long __user *extramask = frame->extramask;
272         int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
273
274         if (copy_from_user(&set.sig[0], oldmask, sizeof(set.sig[0])) ||
275             copy_from_user(&set.sig[1], extramask, sig_size))
276                 goto segfault;
277
278         sigdelsetmask(&set, ~_BLOCKABLE);
279
280         spin_lock_irq(&current->sighand->siglock);
281         current->blocked = set;
282         recalc_sigpending();
283         spin_unlock_irq(&current->sighand->siglock);
284
285         if (copy_sc_from_user(&current->thread.regs, sc))
286                 goto segfault;
287
288         /* Avoid ERESTART handling */
289         PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
290         return PT_REGS_SYSCALL_RET(&current->thread.regs);
291
292  segfault:
293         force_sig(SIGSEGV, current);
294         return 0;
295 }
296
297 long sys_rt_sigreturn(struct pt_regs regs)
298 {
299         unsigned long sp = PT_REGS_SP(&current->thread.regs);
300         struct rt_sigframe __user *frame =
301                 (struct rt_sigframe __user *) (sp - 4);
302         sigset_t set;
303         struct ucontext __user *uc = &frame->uc;
304         int sig_size = _NSIG_WORDS * sizeof(unsigned long);
305
306         if (copy_from_user(&set, &uc->uc_sigmask, sig_size))
307                 goto segfault;
308
309         sigdelsetmask(&set, ~_BLOCKABLE);
310
311         spin_lock_irq(&current->sighand->siglock);
312         current->blocked = set;
313         recalc_sigpending();
314         spin_unlock_irq(&current->sighand->siglock);
315
316         if (copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext))
317                 goto segfault;
318
319         /* Avoid ERESTART handling */
320         PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
321         return PT_REGS_SYSCALL_RET(&current->thread.regs);
322
323  segfault:
324         force_sig(SIGSEGV, current);
325         return 0;
326 }