blob: dd77ac0cac46a754215c85fb3aa040c332b9541c [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <asm/ptrace.h>
28#include <asm/ia32_unistd.h>
29#include <asm/user32.h>
30#include <asm/sigcontext32.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <asm/proto.h>
Roland McGrathaf65d642008-01-30 13:30:43 +010032#include <asm/vdso.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080033#include <asm/sigframe.h>
Jaswinder Singh Rajput2f06de02008-12-27 21:37:10 +053034#include <asm/sys_ia32.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080035
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define DEBUG_SIG 0
37
38#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
39
Hiroshi Shimamotofbdb7da2008-07-14 15:34:09 -070040#define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \
41 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
42 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
43 X86_EFLAGS_CF)
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045void 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{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080049 int err = 0;
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
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080054 put_user_try {
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 put_user_ex(from->si_signo, &to->si_signo);
61 put_user_ex(from->si_errno, &to->si_errno);
62 put_user_ex((short)from->si_code, &to->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080064 if (from->si_code < 0) {
65 put_user_ex(from->si_pid, &to->si_pid);
66 put_user_ex(from->si_uid, &to->si_uid);
67 put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
68 } else {
69 /*
70 * First 32bits of unions are always present:
71 * si_pid === si_band === si_tid === si_addr(LS half)
72 */
73 put_user_ex(from->_sifields._pad[0],
74 &to->_sifields._pad[0]);
75 switch (from->si_code >> 16) {
76 case __SI_FAULT >> 16:
77 break;
78 case __SI_CHLD >> 16:
79 put_user_ex(from->si_utime, &to->si_utime);
80 put_user_ex(from->si_stime, &to->si_stime);
81 put_user_ex(from->si_status, &to->si_status);
82 /* FALL THROUGH */
83 default:
84 case __SI_KILL >> 16:
85 put_user_ex(from->si_uid, &to->si_uid);
86 break;
87 case __SI_POLL >> 16:
88 put_user_ex(from->si_fd, &to->si_fd);
89 break;
90 case __SI_TIMER >> 16:
91 put_user_ex(from->si_overrun, &to->si_overrun);
92 put_user_ex(ptr_to_compat(from->si_ptr),
93 &to->si_ptr);
94 break;
95 /* This is not generated by the kernel as of now. */
96 case __SI_RT >> 16:
97 case __SI_MESGQ >> 16:
98 put_user_ex(from->si_uid, &to->si_uid);
99 put_user_ex(from->si_int, &to->si_int);
100 break;
101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800103 } put_user_catch(err);
104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 return err;
106}
107
108int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
109{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800110 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 u32 ptr32;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100112
113 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 return -EFAULT;
115
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800116 get_user_try {
117 get_user_ex(to->si_signo, &from->si_signo);
118 get_user_ex(to->si_errno, &from->si_errno);
119 get_user_ex(to->si_code, &from->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800121 get_user_ex(to->si_pid, &from->si_pid);
122 get_user_ex(to->si_uid, &from->si_uid);
123 get_user_ex(ptr32, &from->si_ptr);
124 to->si_ptr = compat_ptr(ptr32);
125 } get_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127 return err;
128}
129
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100130asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 mask &= _BLOCKABLE;
133 spin_lock_irq(&current->sighand->siglock);
Andi Kleen1d001df2006-09-26 10:52:26 +0200134 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 siginitset(&current->blocked, mask);
136 recalc_sigpending();
137 spin_unlock_irq(&current->sighand->siglock);
138
Andi Kleen1d001df2006-09-26 10:52:26 +0200139 current->state = TASK_INTERRUPTIBLE;
140 schedule();
Roland McGrath5a8da0e2008-04-30 00:53:10 -0700141 set_restore_sigmask();
Andi Kleen1d001df2006-09-26 10:52:26 +0200142 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143}
144
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100145asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
146 stack_ia32_t __user *uoss_ptr,
147 struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148{
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100149 stack_t uss, uoss;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800150 int ret, err = 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100151 mm_segment_t seg;
152
153 if (uss_ptr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 u32 ptr;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100155
156 memset(&uss, 0, sizeof(stack_t));
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800157 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)))
158 return -EFAULT;
159
160 get_user_try {
161 get_user_ex(ptr, &uss_ptr->ss_sp);
162 get_user_ex(uss.ss_flags, &uss_ptr->ss_flags);
163 get_user_ex(uss.ss_size, &uss_ptr->ss_size);
164 } get_user_catch(err);
165
166 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 return -EFAULT;
168 uss.ss_sp = compat_ptr(ptr);
169 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100170 seg = get_fs();
171 set_fs(KERNEL_DS);
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100172 ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100173 set_fs(seg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 if (ret >= 0 && uoss_ptr) {
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800175 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
176 return -EFAULT;
177
178 put_user_try {
179 put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
180 put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
181 put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
182 } put_user_catch(err);
183
184 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 ret = -EFAULT;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100186 }
187 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188}
189
190/*
191 * Do a signal return; undo the signal stack.
192 */
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800193#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800194 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195}
196
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800197#define COPY_SEG_CPL3(seg) { \
198 unsigned short tmp; \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800199 get_user_ex(tmp, &sc->seg); \
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800200 regs->seg = tmp | 3; \
201}
202
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800203#define RELOAD_SEG(seg) { \
204 unsigned int cur, pre; \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800205 get_user_ex(pre, &sc->seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800206 savesegment(seg, cur); \
207 pre |= 3; \
208 if (pre != cur) \
209 loadsegment(seg, pre); \
210}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100212static int ia32_restore_sigcontext(struct pt_regs *regs,
213 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800214 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100215{
216 unsigned int tmpflags, gs, oldgs, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700217 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100218 u32 tmp;
219
220 /* Always make any pending restarted system calls return -EINTR */
221 current_thread_info()->restart_block.fn = do_no_restart_syscall;
222
223#if DEBUG_SIG
224 printk(KERN_DEBUG "SIG restore_sigcontext: "
225 "sc=%p err(%x) eip(%x) cs(%x) flg(%x)\n",
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100226 sc, sc->err, sc->ip, sc->cs, sc->flags);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100227#endif
228
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800229 get_user_try {
230 /*
231 * Reload fs and gs if they have changed in the signal
232 * handler. This does not handle long fs/gs base changes in
233 * the handler, but does not clobber them at least in the
234 * normal case.
235 */
236 get_user_ex(gs, &sc->gs);
237 gs |= 3;
238 savesegment(gs, oldgs);
239 if (gs != oldgs)
240 load_gs_index(gs);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100241
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800242 RELOAD_SEG(fs);
243 RELOAD_SEG(ds);
244 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800246 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
247 COPY(dx); COPY(cx); COPY(ip);
248 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800250 COPY_SEG_CPL3(cs);
251 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800253 get_user_ex(tmpflags, &sc->flags);
254 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
255 /* disable syscall checks */
256 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100257
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800258 get_user_ex(tmp, &sc->fpstate);
259 buf = compat_ptr(tmp);
260 err |= restore_i387_xstate_ia32(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800262 get_user_ex(*pax, &sc->ax);
263 } get_user_catch(err);
264
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266}
267
268asmlinkage long sys32_sigreturn(struct pt_regs *regs)
269{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800270 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100272 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
274 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
275 goto badframe;
276 if (__get_user(set.sig[0], &frame->sc.oldmask)
277 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100278 && __copy_from_user((((char *) &set.sig) + 4),
279 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 sizeof(frame->extramask))))
281 goto badframe;
282
283 sigdelsetmask(&set, ~_BLOCKABLE);
284 spin_lock_irq(&current->sighand->siglock);
285 current->blocked = set;
286 recalc_sigpending();
287 spin_unlock_irq(&current->sighand->siglock);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100288
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100289 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100291 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
293badframe:
294 signal_fault(regs, frame, "32bit sigreturn");
295 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100296}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
299{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800300 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100302 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 struct pt_regs tregs;
304
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800305 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
307 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
308 goto badframe;
309 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
310 goto badframe;
311
312 sigdelsetmask(&set, ~_BLOCKABLE);
313 spin_lock_irq(&current->sighand->siglock);
314 current->blocked = set;
315 recalc_sigpending();
316 spin_unlock_irq(&current->sighand->siglock);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100317
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100318 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 goto badframe;
320
321 tregs = *regs;
322 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
323 goto badframe;
324
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100325 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100328 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100330}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332/*
333 * Set up a signal frame.
334 */
335
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100336static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700337 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100338 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
340 int tmp, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800342 put_user_try {
343 savesegment(gs, tmp);
344 put_user_ex(tmp, (unsigned int __user *)&sc->gs);
345 savesegment(fs, tmp);
346 put_user_ex(tmp, (unsigned int __user *)&sc->fs);
347 savesegment(ds, tmp);
348 put_user_ex(tmp, (unsigned int __user *)&sc->ds);
349 savesegment(es, tmp);
350 put_user_ex(tmp, (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800352 put_user_ex(regs->di, &sc->di);
353 put_user_ex(regs->si, &sc->si);
354 put_user_ex(regs->bp, &sc->bp);
355 put_user_ex(regs->sp, &sc->sp);
356 put_user_ex(regs->bx, &sc->bx);
357 put_user_ex(regs->dx, &sc->dx);
358 put_user_ex(regs->cx, &sc->cx);
359 put_user_ex(regs->ax, &sc->ax);
360 put_user_ex(current->thread.trap_no, &sc->trapno);
361 put_user_ex(current->thread.error_code, &sc->err);
362 put_user_ex(regs->ip, &sc->ip);
363 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
364 put_user_ex(regs->flags, &sc->flags);
365 put_user_ex(regs->sp, &sc->sp_at_signal);
366 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800368 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800370 /* non-iBCS2 extensions.. */
371 put_user_ex(mask, &sc->oldmask);
372 put_user_ex(current->thread.cr2, &sc->cr2);
373 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 return err;
376}
377
378/*
379 * Determine which stack to use..
380 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100381static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700382 size_t frame_size,
Suresh Siddhaab513702008-07-29 10:29:22 -0700383 void **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100385 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100388 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
390 /* This is the X/Open sanctioned signal stack switching. */
391 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100392 if (sas_ss_flags(sp) == 0)
393 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 }
395
396 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800397 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100399 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100400 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700402 if (used_math()) {
403 sp = sp - sig_xstate_ia32_size;
404 *fpstate = (struct _fpstate_ia32 *) sp;
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800405 if (save_i387_xstate_ia32(*fpstate) < 0)
406 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700407 }
408
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100409 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200410 /* Align the stack pointer according to the i386 ABI,
411 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100412 sp = ((sp + 4) & -16ul) - 4;
413 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
Roland McGrath0928d6e2005-06-23 00:08:37 -0700416int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100417 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800419 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100420 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700422 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100424 /* copy_to_user optimizes that into a single 8 byte store */
425 static const struct {
426 u16 poplmovl;
427 u32 val;
428 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100429 } __attribute__((packed)) code = {
430 0xb858, /* popl %eax ; movl $...,%eax */
431 __NR_ia32_sigreturn,
432 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100433 };
434
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700435 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700438 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700440 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700441 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700443 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700444 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
446 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700447 if (__copy_to_user(frame->extramask, &set->sig[1],
448 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700449 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
Roland McGrathaf65d642008-01-30 13:30:43 +0100452 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100453 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100454 } else {
455 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700456 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100457 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
458 sigreturn);
459 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100460 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100461 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100462
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800463 put_user_try {
464 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
465
466 /*
467 * These are actually not used anymore, but left because some
468 * gdb versions depend on them as a marker.
469 */
470 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
471 } put_user_catch(err);
472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700474 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
476 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100477 regs->sp = (unsigned long) frame;
478 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
Andi Kleen536e3ee2006-09-26 10:52:41 +0200480 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100481 regs->ax = sig;
482 regs->dx = 0;
483 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200484
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700485 loadsegment(ds, __USER32_DS);
486 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100488 regs->cs = __USER32_CS;
489 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491#if DEBUG_SIG
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100492 printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n",
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100493 current->comm, current->pid, frame, regs->ip, frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494#endif
495
Andi Kleen1d001df2006-09-26 10:52:26 +0200496 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}
498
Roland McGrath0928d6e2005-06-23 00:08:37 -0700499int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100500 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800502 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100503 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700505 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100507 /* __copy_to_user optimizes that into a single 8 byte store */
508 static const struct {
509 u8 movl;
510 u32 val;
511 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800512 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100513 } __attribute__((packed)) code = {
514 0xb8,
515 __NR_ia32_rt_sigreturn,
516 0x80cd,
517 0,
518 };
519
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700520 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
522 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700523 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800525 put_user_try {
526 put_user_ex(sig, &frame->sig);
527 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
528 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
529 err |= copy_siginfo_to_user32(&frame->info, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800531 /* Create the ucontext. */
532 if (cpu_has_xsave)
533 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
534 else
535 put_user_ex(0, &frame->uc.uc_flags);
536 put_user_ex(0, &frame->uc.uc_link);
537 put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
538 put_user_ex(sas_ss_flags(regs->sp),
539 &frame->uc.uc_stack.ss_flags);
540 put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
541 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
542 regs, set->sig[0]);
543 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800545 if (ka->sa.sa_flags & SA_RESTORER)
546 restorer = ka->sa.sa_restorer;
547 else
548 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
549 rt_sigreturn);
550 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800552 /*
553 * Not actually used anymore, but left because some gdb
554 * versions need it.
555 */
556 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
557 } put_user_catch(err);
558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700560 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
562 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100563 regs->sp = (unsigned long) frame;
564 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500566 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100567 regs->ax = sig;
568 regs->dx = (unsigned long) &frame->info;
569 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500570
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700571 loadsegment(ds, __USER32_DS);
572 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100573
574 regs->cs = __USER32_CS;
575 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577#if DEBUG_SIG
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100578 printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n",
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100579 current->comm, current->pid, frame, regs->ip, frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580#endif
581
Andi Kleen1d001df2006-09-26 10:52:26 +0200582 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583}