blob: b195f85526e35813e08e93b2553587a37896af2f [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
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080035#include <asm/sigframe.h>
36
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define DEBUG_SIG 0
38
39#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
40
Hiroshi Shimamotofbdb7da2008-07-14 15:34:09 -070041#define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \
42 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
43 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
44 X86_EFLAGS_CF)
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
47
48int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
49{
50 int err;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010051
52 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 return -EFAULT;
54
55 /* If you change siginfo_t structure, please make sure that
56 this code is fixed accordingly.
57 It should never copy any pad contained in the structure
58 to avoid security leaks, but must copy the generic
59 3 ints plus the relevant union member. */
60 err = __put_user(from->si_signo, &to->si_signo);
61 err |= __put_user(from->si_errno, &to->si_errno);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010062 err |= __put_user((short)from->si_code, &to->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64 if (from->si_code < 0) {
65 err |= __put_user(from->si_pid, &to->si_pid);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010066 err |= __put_user(from->si_uid, &to->si_uid);
67 err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 } else {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010069 /*
70 * First 32bits of unions are always present:
71 * si_pid === si_band === si_tid === si_addr(LS half)
72 */
73 err |= __put_user(from->_sifields._pad[0],
74 &to->_sifields._pad[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 switch (from->si_code >> 16) {
76 case __SI_FAULT >> 16:
77 break;
78 case __SI_CHLD >> 16:
79 err |= __put_user(from->si_utime, &to->si_utime);
80 err |= __put_user(from->si_stime, &to->si_stime);
81 err |= __put_user(from->si_status, &to->si_status);
82 /* FALL THROUGH */
83 default:
84 case __SI_KILL >> 16:
85 err |= __put_user(from->si_uid, &to->si_uid);
86 break;
87 case __SI_POLL >> 16:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010088 err |= __put_user(from->si_fd, &to->si_fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 break;
90 case __SI_TIMER >> 16:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010091 err |= __put_user(from->si_overrun, &to->si_overrun);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 err |= __put_user(ptr_to_compat(from->si_ptr),
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010093 &to->si_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 break;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010095 /* This is not generated by the kernel as of now. */
96 case __SI_RT >> 16:
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 case __SI_MESGQ >> 16:
98 err |= __put_user(from->si_uid, &to->si_uid);
99 err |= __put_user(from->si_int, &to->si_int);
100 break;
101 }
102 }
103 return err;
104}
105
106int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
107{
108 int err;
109 u32 ptr32;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100110
111 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 return -EFAULT;
113
114 err = __get_user(to->si_signo, &from->si_signo);
115 err |= __get_user(to->si_errno, &from->si_errno);
116 err |= __get_user(to->si_code, &from->si_code);
117
118 err |= __get_user(to->si_pid, &from->si_pid);
119 err |= __get_user(to->si_uid, &from->si_uid);
120 err |= __get_user(ptr32, &from->si_ptr);
121 to->si_ptr = compat_ptr(ptr32);
122
123 return err;
124}
125
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100126asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 mask &= _BLOCKABLE;
129 spin_lock_irq(&current->sighand->siglock);
Andi Kleen1d001df2006-09-26 10:52:26 +0200130 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 siginitset(&current->blocked, mask);
132 recalc_sigpending();
133 spin_unlock_irq(&current->sighand->siglock);
134
Andi Kleen1d001df2006-09-26 10:52:26 +0200135 current->state = TASK_INTERRUPTIBLE;
136 schedule();
Roland McGrath5a8da0e2008-04-30 00:53:10 -0700137 set_restore_sigmask();
Andi Kleen1d001df2006-09-26 10:52:26 +0200138 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139}
140
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100141asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
142 stack_ia32_t __user *uoss_ptr,
143 struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144{
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100145 stack_t uss, uoss;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 int ret;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100147 mm_segment_t seg;
148
149 if (uss_ptr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 u32 ptr;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100151
152 memset(&uss, 0, sizeof(stack_t));
153 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 __get_user(ptr, &uss_ptr->ss_sp) ||
155 __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
156 __get_user(uss.ss_size, &uss_ptr->ss_size))
157 return -EFAULT;
158 uss.ss_sp = compat_ptr(ptr);
159 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100160 seg = get_fs();
161 set_fs(KERNEL_DS);
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100162 ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100163 set_fs(seg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 if (ret >= 0 && uoss_ptr) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100165 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
167 __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
168 __put_user(uoss.ss_size, &uoss_ptr->ss_size))
169 ret = -EFAULT;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100170 }
171 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172}
173
174/*
175 * Do a signal return; undo the signal stack.
176 */
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800177#define COPY(x) { \
178 err |= __get_user(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179}
180
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800181#define COPY_SEG_CPL3(seg) { \
182 unsigned short tmp; \
183 err |= __get_user(tmp, &sc->seg); \
184 regs->seg = tmp | 3; \
185}
186
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800187#define RELOAD_SEG(seg) { \
188 unsigned int cur, pre; \
189 err |= __get_user(pre, &sc->seg); \
190 savesegment(seg, cur); \
191 pre |= 3; \
192 if (pre != cur) \
193 loadsegment(seg, pre); \
194}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100196static int ia32_restore_sigcontext(struct pt_regs *regs,
197 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800198 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100199{
200 unsigned int tmpflags, gs, oldgs, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700201 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100202 u32 tmp;
203
204 /* Always make any pending restarted system calls return -EINTR */
205 current_thread_info()->restart_block.fn = do_no_restart_syscall;
206
207#if DEBUG_SIG
208 printk(KERN_DEBUG "SIG restore_sigcontext: "
209 "sc=%p err(%x) eip(%x) cs(%x) flg(%x)\n",
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100210 sc, sc->err, sc->ip, sc->cs, sc->flags);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100211#endif
212
213 /*
214 * Reload fs and gs if they have changed in the signal
215 * handler. This does not handle long fs/gs base changes in
216 * the handler, but does not clobber them at least in the
217 * normal case.
218 */
219 err |= __get_user(gs, &sc->gs);
220 gs |= 3;
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700221 savesegment(gs, oldgs);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100222 if (gs != oldgs)
223 load_gs_index(gs);
224
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800225 RELOAD_SEG(fs);
226 RELOAD_SEG(ds);
227 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
230 COPY(dx); COPY(cx); COPY(ip);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100231 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800233 COPY_SEG_CPL3(cs);
234 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
H. Peter Anvin742fa542008-01-30 13:30:56 +0100236 err |= __get_user(tmpflags, &sc->flags);
Hiroshi Shimamotofbdb7da2008-07-14 15:34:09 -0700237 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100238 /* disable syscall checks */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100239 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100240
241 err |= __get_user(tmp, &sc->fpstate);
242 buf = compat_ptr(tmp);
Suresh Siddhaab513702008-07-29 10:29:22 -0700243 err |= restore_i387_xstate_ia32(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800245 err |= __get_user(*pax, &sc->ax);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247}
248
249asmlinkage long sys32_sigreturn(struct pt_regs *regs)
250{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800251 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100253 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
256 goto badframe;
257 if (__get_user(set.sig[0], &frame->sc.oldmask)
258 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100259 && __copy_from_user((((char *) &set.sig) + 4),
260 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 sizeof(frame->extramask))))
262 goto badframe;
263
264 sigdelsetmask(&set, ~_BLOCKABLE);
265 spin_lock_irq(&current->sighand->siglock);
266 current->blocked = set;
267 recalc_sigpending();
268 spin_unlock_irq(&current->sighand->siglock);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100269
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100270 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100272 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
274badframe:
275 signal_fault(regs, frame, "32bit sigreturn");
276 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100277}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
280{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800281 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100283 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 struct pt_regs tregs;
285
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800286 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
289 goto badframe;
290 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
291 goto badframe;
292
293 sigdelsetmask(&set, ~_BLOCKABLE);
294 spin_lock_irq(&current->sighand->siglock);
295 current->blocked = set;
296 recalc_sigpending();
297 spin_unlock_irq(&current->sighand->siglock);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100298
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100299 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 goto badframe;
301
302 tregs = *regs;
303 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
304 goto badframe;
305
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100306 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
308badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100309 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100311}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313/*
314 * Set up a signal frame.
315 */
316
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100317static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700318 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100319 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 int tmp, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700323 savesegment(gs, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700325 savesegment(fs, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700327 savesegment(ds, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 err |= __put_user(tmp, (unsigned int __user *)&sc->ds);
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700329 savesegment(es, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 err |= __put_user(tmp, (unsigned int __user *)&sc->es);
331
Hiroshi Shimamotobff0aa42008-09-30 20:28:20 -0700332 err |= __put_user(regs->di, &sc->di);
333 err |= __put_user(regs->si, &sc->si);
334 err |= __put_user(regs->bp, &sc->bp);
335 err |= __put_user(regs->sp, &sc->sp);
336 err |= __put_user(regs->bx, &sc->bx);
337 err |= __put_user(regs->dx, &sc->dx);
338 err |= __put_user(regs->cx, &sc->cx);
339 err |= __put_user(regs->ax, &sc->ax);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 err |= __put_user(current->thread.trap_no, &sc->trapno);
341 err |= __put_user(current->thread.error_code, &sc->err);
Hiroshi Shimamotobff0aa42008-09-30 20:28:20 -0700342 err |= __put_user(regs->ip, &sc->ip);
Hiroshi Shimamoto64977602008-11-17 15:49:14 -0800343 err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs);
Hiroshi Shimamotobff0aa42008-09-30 20:28:20 -0700344 err |= __put_user(regs->flags, &sc->flags);
345 err |= __put_user(regs->sp, &sc->sp_at_signal);
Hiroshi Shimamoto64977602008-11-17 15:49:14 -0800346 err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800348 err |= __put_user(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 /* non-iBCS2 extensions.. */
351 err |= __put_user(mask, &sc->oldmask);
352 err |= __put_user(current->thread.cr2, &sc->cr2);
353
354 return err;
355}
356
357/*
358 * Determine which stack to use..
359 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100360static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700361 size_t frame_size,
Suresh Siddhaab513702008-07-29 10:29:22 -0700362 void **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100364 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100367 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369 /* This is the X/Open sanctioned signal stack switching. */
370 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100371 if (sas_ss_flags(sp) == 0)
372 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 }
374
375 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800376 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100378 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100379 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700381 if (used_math()) {
382 sp = sp - sig_xstate_ia32_size;
383 *fpstate = (struct _fpstate_ia32 *) sp;
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800384 if (save_i387_xstate_ia32(*fpstate) < 0)
385 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700386 }
387
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100388 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200389 /* Align the stack pointer according to the i386 ABI,
390 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100391 sp = ((sp + 4) & -16ul) - 4;
392 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393}
394
Roland McGrath0928d6e2005-06-23 00:08:37 -0700395int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100396 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800398 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100399 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700401 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100403 /* copy_to_user optimizes that into a single 8 byte store */
404 static const struct {
405 u16 poplmovl;
406 u32 val;
407 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100408 } __attribute__((packed)) code = {
409 0xb858, /* popl %eax ; movl $...,%eax */
410 __NR_ia32_sigreturn,
411 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100412 };
413
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700414 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700417 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700419 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700420 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700422 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700423 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
425 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700426 if (__copy_to_user(frame->extramask, &set->sig[1],
427 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700428 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
Roland McGrathaf65d642008-01-30 13:30:43 +0100431 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100432 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100433 } else {
434 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700435 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100436 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
437 sigreturn);
438 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100439 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100440 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100441 err |= __put_user(ptr_to_compat(restorer), &frame->pretcode);
442
443 /*
444 * These are actually not used anymore, but left because some
445 * gdb versions depend on them as a marker.
446 */
Hiroshi Shimamotod0b48ca2008-12-16 14:03:36 -0800447 err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700449 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100452 regs->sp = (unsigned long) frame;
453 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
Andi Kleen536e3ee2006-09-26 10:52:41 +0200455 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100456 regs->ax = sig;
457 regs->dx = 0;
458 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200459
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700460 loadsegment(ds, __USER32_DS);
461 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100463 regs->cs = __USER32_CS;
464 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466#if DEBUG_SIG
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100467 printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n",
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100468 current->comm, current->pid, frame, regs->ip, frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469#endif
470
Andi Kleen1d001df2006-09-26 10:52:26 +0200471 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472}
473
Roland McGrath0928d6e2005-06-23 00:08:37 -0700474int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100475 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800477 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100478 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700480 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100482 /* __copy_to_user optimizes that into a single 8 byte store */
483 static const struct {
484 u8 movl;
485 u32 val;
486 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800487 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100488 } __attribute__((packed)) code = {
489 0xb8,
490 __NR_ia32_rt_sigreturn,
491 0x80cd,
492 0,
493 };
494
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700495 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
497 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700498 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Hiroshi Shimamoto812b1212008-07-16 19:21:31 -0700500 err |= __put_user(sig, &frame->sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo);
502 err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc);
503 err |= copy_siginfo_to_user32(&frame->info, info);
504 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700505 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 /* Create the ucontext. */
Suresh Siddhac37b5ef2008-07-29 10:29:25 -0700508 if (cpu_has_xsave)
509 err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
510 else
511 err |= __put_user(0, &frame->uc.uc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 err |= __put_user(0, &frame->uc.uc_link);
513 err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100514 err |= __put_user(sas_ss_flags(regs->sp),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 &frame->uc.uc_stack.ss_flags);
516 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700517 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100518 regs, set->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
520 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700521 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100523 if (ka->sa.sa_flags & SA_RESTORER)
524 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100525 else
526 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
527 rt_sigreturn);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100528 err |= __put_user(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100530 /*
531 * Not actually used anymore, but left because some gdb
532 * versions need it.
533 */
Hiroshi Shimamotod0b48ca2008-12-16 14:03:36 -0800534 err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700536 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
538 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100539 regs->sp = (unsigned long) frame;
540 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500542 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100543 regs->ax = sig;
544 regs->dx = (unsigned long) &frame->info;
545 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500546
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700547 loadsegment(ds, __USER32_DS);
548 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100549
550 regs->cs = __USER32_CS;
551 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553#if DEBUG_SIG
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100554 printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n",
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100555 current->comm, current->pid, frame, regs->ip, frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556#endif
557
Andi Kleen1d001df2006-09-26 10:52:26 +0200558 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559}