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