blob: a05bf0fb741530b001c09a63553bbcff4d68c43d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/x86_64/ia32/ia32_signal.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
7 * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
8 * 2000-12-* x86-64 compatibility mode signal handling by Andi Kleen
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10
11#include <linux/sched.h>
12#include <linux/mm.h>
13#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/kernel.h>
15#include <linux/signal.h>
16#include <linux/errno.h>
17#include <linux/wait.h>
18#include <linux/ptrace.h>
19#include <linux/unistd.h>
20#include <linux/stddef.h>
21#include <linux/personality.h>
22#include <linux/compat.h>
Andi Kleen9fbbd4d2007-02-13 13:26:26 +010023#include <linux/binfmts.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <asm/ucontext.h>
25#include <asm/uaccess.h>
26#include <asm/i387.h>
27#include <asm/ia32.h>
28#include <asm/ptrace.h>
29#include <asm/ia32_unistd.h>
30#include <asm/user32.h>
31#include <asm/sigcontext32.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/proto.h>
Roland McGrathaf65d642008-01-30 13:30:43 +010033#include <asm/vdso.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35#define DEBUG_SIG 0
36
37#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
38
Hiroshi Shimamotofbdb7da2008-07-14 15:34:09 -070039#define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \
40 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
41 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
42 X86_EFLAGS_CF)
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
45void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
46
47int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
48{
49 int err;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010050
51 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 return -EFAULT;
53
54 /* If you change siginfo_t structure, please make sure that
55 this code is fixed accordingly.
56 It should never copy any pad contained in the structure
57 to avoid security leaks, but must copy the generic
58 3 ints plus the relevant union member. */
59 err = __put_user(from->si_signo, &to->si_signo);
60 err |= __put_user(from->si_errno, &to->si_errno);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010061 err |= __put_user((short)from->si_code, &to->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63 if (from->si_code < 0) {
64 err |= __put_user(from->si_pid, &to->si_pid);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010065 err |= __put_user(from->si_uid, &to->si_uid);
66 err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 } else {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010068 /*
69 * First 32bits of unions are always present:
70 * si_pid === si_band === si_tid === si_addr(LS half)
71 */
72 err |= __put_user(from->_sifields._pad[0],
73 &to->_sifields._pad[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 switch (from->si_code >> 16) {
75 case __SI_FAULT >> 16:
76 break;
77 case __SI_CHLD >> 16:
78 err |= __put_user(from->si_utime, &to->si_utime);
79 err |= __put_user(from->si_stime, &to->si_stime);
80 err |= __put_user(from->si_status, &to->si_status);
81 /* FALL THROUGH */
82 default:
83 case __SI_KILL >> 16:
84 err |= __put_user(from->si_uid, &to->si_uid);
85 break;
86 case __SI_POLL >> 16:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010087 err |= __put_user(from->si_fd, &to->si_fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 break;
89 case __SI_TIMER >> 16:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010090 err |= __put_user(from->si_overrun, &to->si_overrun);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 err |= __put_user(ptr_to_compat(from->si_ptr),
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010092 &to->si_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 break;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010094 /* This is not generated by the kernel as of now. */
95 case __SI_RT >> 16:
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 case __SI_MESGQ >> 16:
97 err |= __put_user(from->si_uid, &to->si_uid);
98 err |= __put_user(from->si_int, &to->si_int);
99 break;
100 }
101 }
102 return err;
103}
104
105int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
106{
107 int err;
108 u32 ptr32;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100109
110 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 return -EFAULT;
112
113 err = __get_user(to->si_signo, &from->si_signo);
114 err |= __get_user(to->si_errno, &from->si_errno);
115 err |= __get_user(to->si_code, &from->si_code);
116
117 err |= __get_user(to->si_pid, &from->si_pid);
118 err |= __get_user(to->si_uid, &from->si_uid);
119 err |= __get_user(ptr32, &from->si_ptr);
120 to->si_ptr = compat_ptr(ptr32);
121
122 return err;
123}
124
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100125asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 mask &= _BLOCKABLE;
128 spin_lock_irq(&current->sighand->siglock);
Andi Kleen1d001df2006-09-26 10:52:26 +0200129 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 siginitset(&current->blocked, mask);
131 recalc_sigpending();
132 spin_unlock_irq(&current->sighand->siglock);
133
Andi Kleen1d001df2006-09-26 10:52:26 +0200134 current->state = TASK_INTERRUPTIBLE;
135 schedule();
Roland McGrath5a8da0e2008-04-30 00:53:10 -0700136 set_restore_sigmask();
Andi Kleen1d001df2006-09-26 10:52:26 +0200137 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138}
139
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100140asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
141 stack_ia32_t __user *uoss_ptr,
142 struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143{
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100144 stack_t uss, uoss;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 int ret;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100146 mm_segment_t seg;
147
148 if (uss_ptr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 u32 ptr;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100150
151 memset(&uss, 0, sizeof(stack_t));
152 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 __get_user(ptr, &uss_ptr->ss_sp) ||
154 __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
155 __get_user(uss.ss_size, &uss_ptr->ss_size))
156 return -EFAULT;
157 uss.ss_sp = compat_ptr(ptr);
158 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100159 seg = get_fs();
160 set_fs(KERNEL_DS);
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100161 ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100162 set_fs(seg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 if (ret >= 0 && uoss_ptr) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100164 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
166 __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
167 __put_user(uoss.ss_size, &uoss_ptr->ss_size))
168 ret = -EFAULT;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100169 }
170 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171}
172
173/*
174 * Do a signal return; undo the signal stack.
175 */
176
177struct sigframe
178{
179 u32 pretcode;
180 int sig;
181 struct sigcontext_ia32 sc;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700182 struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 unsigned int extramask[_COMPAT_NSIG_WORDS-1];
184 char retcode[8];
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700185 /* fp state follows here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186};
187
188struct rt_sigframe
189{
190 u32 pretcode;
191 int sig;
192 u32 pinfo;
193 u32 puc;
194 compat_siginfo_t info;
195 struct ucontext_ia32 uc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 char retcode[8];
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700197 /* fp state follows here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198};
199
H. Peter Anvin742fa542008-01-30 13:30:56 +0100200#define COPY(x) { \
201 unsigned int reg; \
202 err |= __get_user(reg, &sc->x); \
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100203 regs->x = reg; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204}
205
206#define RELOAD_SEG(seg,mask) \
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100207 { unsigned int cur; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 unsigned short pre; \
209 err |= __get_user(pre, &sc->seg); \
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100210 asm volatile("movl %%" #seg ",%0" : "=r" (cur)); \
211 pre |= mask; \
212 if (pre != cur) loadsegment(seg, pre); }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100214static int ia32_restore_sigcontext(struct pt_regs *regs,
215 struct sigcontext_ia32 __user *sc,
216 unsigned int *peax)
217{
218 unsigned int tmpflags, gs, oldgs, err = 0;
219 struct _fpstate_ia32 __user *buf;
220 u32 tmp;
221
222 /* Always make any pending restarted system calls return -EINTR */
223 current_thread_info()->restart_block.fn = do_no_restart_syscall;
224
225#if DEBUG_SIG
226 printk(KERN_DEBUG "SIG restore_sigcontext: "
227 "sc=%p err(%x) eip(%x) cs(%x) flg(%x)\n",
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100228 sc, sc->err, sc->ip, sc->cs, sc->flags);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100229#endif
230
231 /*
232 * Reload fs and gs if they have changed in the signal
233 * handler. This does not handle long fs/gs base changes in
234 * the handler, but does not clobber them at least in the
235 * normal case.
236 */
237 err |= __get_user(gs, &sc->gs);
238 gs |= 3;
239 asm("movl %%gs,%0" : "=r" (oldgs));
240 if (gs != oldgs)
241 load_gs_index(gs);
242
243 RELOAD_SEG(fs, 3);
244 RELOAD_SEG(ds, 3);
245 RELOAD_SEG(es, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
247 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
248 COPY(dx); COPY(cx); COPY(ip);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100249 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100251 err |= __get_user(regs->cs, &sc->cs);
252 regs->cs |= 3;
253 err |= __get_user(regs->ss, &sc->ss);
254 regs->ss |= 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
H. Peter Anvin742fa542008-01-30 13:30:56 +0100256 err |= __get_user(tmpflags, &sc->flags);
Hiroshi Shimamotofbdb7da2008-07-14 15:34:09 -0700257 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100258 /* disable syscall checks */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100259 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100260
261 err |= __get_user(tmp, &sc->fpstate);
262 buf = compat_ptr(tmp);
263 if (buf) {
264 if (!access_ok(VERIFY_READ, buf, sizeof(*buf)))
265 goto badframe;
Roland McGrath44210112008-01-30 13:31:50 +0100266 err |= restore_i387_ia32(buf);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100267 } else {
268 struct task_struct *me = current;
269
270 if (used_math()) {
271 clear_fpu(me);
272 clear_used_math();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 }
274 }
275
H. Peter Anvin742fa542008-01-30 13:30:56 +0100276 err |= __get_user(tmp, &sc->ax);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100277 *peax = tmp;
278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 return err;
280
281badframe:
282 return 1;
283}
284
285asmlinkage long sys32_sigreturn(struct pt_regs *regs)
286{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100287 struct sigframe __user *frame = (struct sigframe __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100289 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
292 goto badframe;
293 if (__get_user(set.sig[0], &frame->sc.oldmask)
294 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100295 && __copy_from_user((((char *) &set.sig) + 4),
296 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 sizeof(frame->extramask))))
298 goto badframe;
299
300 sigdelsetmask(&set, ~_BLOCKABLE);
301 spin_lock_irq(&current->sighand->siglock);
302 current->blocked = set;
303 recalc_sigpending();
304 spin_unlock_irq(&current->sighand->siglock);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100305
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100306 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100308 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
310badframe:
311 signal_fault(regs, frame, "32bit sigreturn");
312 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100313}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
316{
317 struct rt_sigframe __user *frame;
318 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100319 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 struct pt_regs tregs;
321
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100322 frame = (struct rt_sigframe __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
325 goto badframe;
326 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
327 goto badframe;
328
329 sigdelsetmask(&set, ~_BLOCKABLE);
330 spin_lock_irq(&current->sighand->siglock);
331 current->blocked = set;
332 recalc_sigpending();
333 spin_unlock_irq(&current->sighand->siglock);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100334
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100335 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 goto badframe;
337
338 tregs = *regs;
339 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
340 goto badframe;
341
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100342 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100345 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100347}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349/*
350 * Set up a signal frame.
351 */
352
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100353static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
354 struct _fpstate_ia32 __user *fpstate,
355 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
357 int tmp, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359 tmp = 0;
360 __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
361 err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
362 __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
363 err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
364 __asm__("movl %%ds,%0" : "=r"(tmp): "0"(tmp));
365 err |= __put_user(tmp, (unsigned int __user *)&sc->ds);
366 __asm__("movl %%es,%0" : "=r"(tmp): "0"(tmp));
367 err |= __put_user(tmp, (unsigned int __user *)&sc->es);
368
H. Peter Anvin742fa542008-01-30 13:30:56 +0100369 err |= __put_user((u32)regs->di, &sc->di);
370 err |= __put_user((u32)regs->si, &sc->si);
371 err |= __put_user((u32)regs->bp, &sc->bp);
372 err |= __put_user((u32)regs->sp, &sc->sp);
373 err |= __put_user((u32)regs->bx, &sc->bx);
374 err |= __put_user((u32)regs->dx, &sc->dx);
375 err |= __put_user((u32)regs->cx, &sc->cx);
376 err |= __put_user((u32)regs->ax, &sc->ax);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 err |= __put_user((u32)regs->cs, &sc->cs);
378 err |= __put_user((u32)regs->ss, &sc->ss);
379 err |= __put_user(current->thread.trap_no, &sc->trapno);
380 err |= __put_user(current->thread.error_code, &sc->err);
H. Peter Anvin742fa542008-01-30 13:30:56 +0100381 err |= __put_user((u32)regs->ip, &sc->ip);
382 err |= __put_user((u32)regs->flags, &sc->flags);
383 err |= __put_user((u32)regs->sp, &sc->sp_at_signal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Roland McGrath44210112008-01-30 13:31:50 +0100385 tmp = save_i387_ia32(fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 if (tmp < 0)
387 err = -EFAULT;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100388 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 clear_used_math();
390 stts();
391 err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
392 &sc->fpstate);
393 }
394
395 /* non-iBCS2 extensions.. */
396 err |= __put_user(mask, &sc->oldmask);
397 err |= __put_user(current->thread.cr2, &sc->cr2);
398
399 return err;
400}
401
402/*
403 * Determine which stack to use..
404 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100405static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700406 size_t frame_size,
407 struct _fpstate_ia32 **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100409 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
411 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100412 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
414 /* This is the X/Open sanctioned signal stack switching. */
415 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100416 if (sas_ss_flags(sp) == 0)
417 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 }
419
420 /* This is the legacy signal stack switching. */
421 else if ((regs->ss & 0xffff) != __USER_DS &&
422 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100423 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100424 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700426 if (used_math()) {
427 sp = sp - sig_xstate_ia32_size;
428 *fpstate = (struct _fpstate_ia32 *) sp;
429 }
430
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100431 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200432 /* Align the stack pointer according to the i386 ABI,
433 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100434 sp = ((sp + 4) & -16ul) - 4;
435 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436}
437
Roland McGrath0928d6e2005-06-23 00:08:37 -0700438int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100439 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
441 struct sigframe __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100442 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 int err = 0;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700444 struct _fpstate_ia32 __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100446 /* copy_to_user optimizes that into a single 8 byte store */
447 static const struct {
448 u16 poplmovl;
449 u32 val;
450 u16 int80;
451 u16 pad;
452 } __attribute__((packed)) code = {
453 0xb858, /* popl %eax ; movl $...,%eax */
454 __NR_ia32_sigreturn,
455 0x80cd, /* int $0x80 */
456 0,
457 };
458
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700459 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
462 goto give_sigsegv;
463
Andi Kleendd54a112006-09-26 10:52:41 +0200464 err |= __put_user(sig, &frame->sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (err)
466 goto give_sigsegv;
467
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700468 err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 if (err)
470 goto give_sigsegv;
471
472 if (_COMPAT_NSIG_WORDS > 1) {
473 err |= __copy_to_user(frame->extramask, &set->sig[1],
474 sizeof(frame->extramask));
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100475 if (err)
476 goto give_sigsegv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Roland McGrathaf65d642008-01-30 13:30:43 +0100479 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100480 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100481 } else {
482 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700483 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100484 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
485 sigreturn);
486 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100487 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100488 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100489 err |= __put_user(ptr_to_compat(restorer), &frame->pretcode);
490
491 /*
492 * These are actually not used anymore, but left because some
493 * gdb versions depend on them as a marker.
494 */
495 err |= __copy_to_user(frame->retcode, &code, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 if (err)
497 goto give_sigsegv;
498
499 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100500 regs->sp = (unsigned long) frame;
501 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Andi Kleen536e3ee2006-09-26 10:52:41 +0200503 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100504 regs->ax = sig;
505 regs->dx = 0;
506 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200507
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100508 asm volatile("movl %0,%%ds" :: "r" (__USER32_DS));
509 asm volatile("movl %0,%%es" :: "r" (__USER32_DS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100511 regs->cs = __USER32_CS;
512 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514#if DEBUG_SIG
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100515 printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n",
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100516 current->comm, current->pid, frame, regs->ip, frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517#endif
518
Andi Kleen1d001df2006-09-26 10:52:26 +0200519 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
521give_sigsegv:
522 force_sigsegv(sig, current);
Andi Kleen1d001df2006-09-26 10:52:26 +0200523 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524}
525
Roland McGrath0928d6e2005-06-23 00:08:37 -0700526int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100527 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528{
529 struct rt_sigframe __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100530 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 int err = 0;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700532 struct _fpstate_ia32 __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100534 /* __copy_to_user optimizes that into a single 8 byte store */
535 static const struct {
536 u8 movl;
537 u32 val;
538 u16 int80;
539 u16 pad;
540 u8 pad2;
541 } __attribute__((packed)) code = {
542 0xb8,
543 __NR_ia32_rt_sigreturn,
544 0x80cd,
545 0,
546 };
547
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700548 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
550 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
551 goto give_sigsegv;
552
Hiroshi Shimamoto812b1212008-07-16 19:21:31 -0700553 err |= __put_user(sig, &frame->sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo);
555 err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc);
556 err |= copy_siginfo_to_user32(&frame->info, info);
557 if (err)
558 goto give_sigsegv;
559
560 /* Create the ucontext. */
561 err |= __put_user(0, &frame->uc.uc_flags);
562 err |= __put_user(0, &frame->uc.uc_link);
563 err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100564 err |= __put_user(sas_ss_flags(regs->sp),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 &frame->uc.uc_stack.ss_flags);
566 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700567 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100568 regs, set->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
570 if (err)
571 goto give_sigsegv;
572
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100573 if (ka->sa.sa_flags & SA_RESTORER)
574 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100575 else
576 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
577 rt_sigreturn);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100578 err |= __put_user(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100580 /*
581 * Not actually used anymore, but left because some gdb
582 * versions need it.
583 */
584 err |= __copy_to_user(frame->retcode, &code, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 if (err)
586 goto give_sigsegv;
587
588 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100589 regs->sp = (unsigned long) frame;
590 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500592 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100593 regs->ax = sig;
594 regs->dx = (unsigned long) &frame->info;
595 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500596
Albert Cahalan8e3de532006-12-07 02:14:06 +0100597 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100598 regs->ax = sig;
599 regs->dx = (unsigned long) &frame->info;
600 regs->cx = (unsigned long) &frame->uc;
Albert Cahalan8e3de532006-12-07 02:14:06 +0100601
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100602 asm volatile("movl %0,%%ds" :: "r" (__USER32_DS));
603 asm volatile("movl %0,%%es" :: "r" (__USER32_DS));
604
605 regs->cs = __USER32_CS;
606 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608#if DEBUG_SIG
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100609 printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n",
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100610 current->comm, current->pid, frame, regs->ip, frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611#endif
612
Andi Kleen1d001df2006-09-26 10:52:26 +0200613 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615give_sigsegv:
616 force_sigsegv(sig, current);
Andi Kleen1d001df2006-09-26 10:52:26 +0200617 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618}