blob: a69245ba27e328363de1e389dd5ba50ed2eb979c [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/errno.h>
16#include <linux/wait.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/unistd.h>
18#include <linux/stddef.h>
19#include <linux/personality.h>
20#include <linux/compat.h>
Andi Kleen9fbbd4d2007-02-13 13:26:26 +010021#include <linux/binfmts.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <asm/ucontext.h>
23#include <asm/uaccess.h>
24#include <asm/i387.h>
Linus Torvalds1361b832012-02-21 13:19:22 -080025#include <asm/fpu-internal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/ptrace.h>
27#include <asm/ia32_unistd.h>
28#include <asm/user32.h>
29#include <asm/sigcontext32.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <asm/proto.h>
Roland McGrathaf65d642008-01-30 13:30:43 +010031#include <asm/vdso.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080032#include <asm/sigframe.h>
H. Peter Anvinf28f0c22012-02-19 07:38:43 -080033#include <asm/sighandling.h>
Jaswinder Singh Rajput2f06de02008-12-27 21:37:10 +053034#include <asm/sys_ia32.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080035
H. Peter Anvinf28f0c22012-02-19 07:38:43 -080036#define FIX_EFLAGS __FIX_EFLAGS
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
38int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
39{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080040 int err = 0;
H. Peter Anvinbb6fa8b2012-03-13 22:44:41 -070041 bool ia32 = is_ia32_task();
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010042
43 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 return -EFAULT;
45
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080046 put_user_try {
47 /* If you change siginfo_t structure, please make sure that
48 this code is fixed accordingly.
49 It should never copy any pad contained in the structure
50 to avoid security leaks, but must copy the generic
51 3 ints plus the relevant union member. */
52 put_user_ex(from->si_signo, &to->si_signo);
53 put_user_ex(from->si_errno, &to->si_errno);
54 put_user_ex((short)from->si_code, &to->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080056 if (from->si_code < 0) {
57 put_user_ex(from->si_pid, &to->si_pid);
58 put_user_ex(from->si_uid, &to->si_uid);
59 put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
60 } else {
61 /*
62 * First 32bits of unions are always present:
63 * si_pid === si_band === si_tid === si_addr(LS half)
64 */
65 put_user_ex(from->_sifields._pad[0],
66 &to->_sifields._pad[0]);
67 switch (from->si_code >> 16) {
68 case __SI_FAULT >> 16:
69 break;
70 case __SI_CHLD >> 16:
H. Peter Anvine7084fd2012-03-05 13:40:24 -080071 if (ia32) {
72 put_user_ex(from->si_utime, &to->si_utime);
73 put_user_ex(from->si_stime, &to->si_stime);
74 } else {
75 put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
76 put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
77 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080078 put_user_ex(from->si_status, &to->si_status);
79 /* FALL THROUGH */
80 default:
81 case __SI_KILL >> 16:
82 put_user_ex(from->si_uid, &to->si_uid);
83 break;
84 case __SI_POLL >> 16:
85 put_user_ex(from->si_fd, &to->si_fd);
86 break;
87 case __SI_TIMER >> 16:
88 put_user_ex(from->si_overrun, &to->si_overrun);
89 put_user_ex(ptr_to_compat(from->si_ptr),
90 &to->si_ptr);
91 break;
92 /* This is not generated by the kernel as of now. */
93 case __SI_RT >> 16:
94 case __SI_MESGQ >> 16:
95 put_user_ex(from->si_uid, &to->si_uid);
96 put_user_ex(from->si_int, &to->si_int);
97 break;
98 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800100 } put_user_catch(err);
101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 return err;
103}
104
105int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
106{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800107 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 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
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800113 get_user_try {
114 get_user_ex(to->si_signo, &from->si_signo);
115 get_user_ex(to->si_errno, &from->si_errno);
116 get_user_ex(to->si_code, &from->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800118 get_user_ex(to->si_pid, &from->si_pid);
119 get_user_ex(to->si_uid, &from->si_uid);
120 get_user_ex(ptr32, &from->si_ptr);
121 to->si_ptr = compat_ptr(ptr32);
122 } get_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
124 return err;
125}
126
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100127asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128{
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200129 sigset_t blocked;
130
Andi Kleen1d001df2006-09-26 10:52:26 +0200131 current->saved_sigmask = current->blocked;
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200132
133 mask &= _BLOCKABLE;
134 siginitset(&blocked, mask);
135 set_current_blocked(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
Andi Kleen1d001df2006-09-26 10:52:26 +0200137 current->state = TASK_INTERRUPTIBLE;
138 schedule();
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200139
Roland McGrath5a8da0e2008-04-30 00:53:10 -0700140 set_restore_sigmask();
Andi Kleen1d001df2006-09-26 10:52:26 +0200141 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142}
143
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100144asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
145 stack_ia32_t __user *uoss_ptr,
146 struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100148 stack_t uss, uoss;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800149 int ret, err = 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100150 mm_segment_t seg;
151
152 if (uss_ptr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 u32 ptr;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100154
155 memset(&uss, 0, sizeof(stack_t));
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800156 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)))
157 return -EFAULT;
158
159 get_user_try {
160 get_user_ex(ptr, &uss_ptr->ss_sp);
161 get_user_ex(uss.ss_flags, &uss_ptr->ss_flags);
162 get_user_ex(uss.ss_size, &uss_ptr->ss_size);
163 } get_user_catch(err);
164
165 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 return -EFAULT;
167 uss.ss_sp = compat_ptr(ptr);
168 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100169 seg = get_fs();
170 set_fs(KERNEL_DS);
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100171 ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100172 set_fs(seg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 if (ret >= 0 && uoss_ptr) {
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800174 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
175 return -EFAULT;
176
177 put_user_try {
178 put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
179 put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
180 put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
181 } put_user_catch(err);
182
183 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 ret = -EFAULT;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100185 }
186 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187}
188
189/*
190 * Do a signal return; undo the signal stack.
191 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800192#define loadsegment_gs(v) load_gs_index(v)
193#define loadsegment_fs(v) loadsegment(fs, v)
194#define loadsegment_ds(v) loadsegment(ds, v)
195#define loadsegment_es(v) loadsegment(es, v)
196
197#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
198#define set_user_seg(seg, v) loadsegment_##seg(v)
199
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800200#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800201 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202}
203
Hiroshi Shimamoto8801ead2009-02-20 19:00:13 -0800204#define GET_SEG(seg) ({ \
205 unsigned short tmp; \
206 get_user_ex(tmp, &sc->seg); \
207 tmp; \
208})
209
210#define COPY_SEG_CPL3(seg) do { \
211 regs->seg = GET_SEG(seg) | 3; \
212} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800213
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800214#define RELOAD_SEG(seg) { \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800215 unsigned int pre = GET_SEG(seg); \
216 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800217 pre |= 3; \
218 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800219 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800220}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100222static int ia32_restore_sigcontext(struct pt_regs *regs,
223 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800224 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100225{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800226 unsigned int tmpflags, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700227 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100228 u32 tmp;
229
230 /* Always make any pending restarted system calls return -EINTR */
231 current_thread_info()->restart_block.fn = do_no_restart_syscall;
232
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800233 get_user_try {
234 /*
235 * Reload fs and gs if they have changed in the signal
236 * handler. This does not handle long fs/gs base changes in
237 * the handler, but does not clobber them at least in the
238 * normal case.
239 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800240 RELOAD_SEG(gs);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800241 RELOAD_SEG(fs);
242 RELOAD_SEG(ds);
243 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800245 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
246 COPY(dx); COPY(cx); COPY(ip);
247 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800249 COPY_SEG_CPL3(cs);
250 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800252 get_user_ex(tmpflags, &sc->flags);
253 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
254 /* disable syscall checks */
255 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100256
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800257 get_user_ex(tmp, &sc->fpstate);
258 buf = compat_ptr(tmp);
259 err |= restore_i387_xstate_ia32(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800261 get_user_ex(*pax, &sc->ax);
262 } get_user_catch(err);
263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265}
266
267asmlinkage long sys32_sigreturn(struct pt_regs *regs)
268{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800269 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100271 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
273 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
274 goto badframe;
275 if (__get_user(set.sig[0], &frame->sc.oldmask)
276 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100277 && __copy_from_user((((char *) &set.sig) + 4),
278 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 sizeof(frame->extramask))))
280 goto badframe;
281
282 sigdelsetmask(&set, ~_BLOCKABLE);
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200283 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100284
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100285 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100287 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
289badframe:
290 signal_fault(regs, frame, "32bit sigreturn");
291 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100292}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
294asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
295{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800296 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100298 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 struct pt_regs tregs;
300
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800301 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
304 goto badframe;
305 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
306 goto badframe;
307
308 sigdelsetmask(&set, ~_BLOCKABLE);
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200309 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100310
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100311 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 goto badframe;
313
314 tregs = *regs;
315 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
316 goto badframe;
317
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100318 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
320badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100321 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100323}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325/*
326 * Set up a signal frame.
327 */
328
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100329static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700330 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100331 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800333 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800335 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800336 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
337 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
338 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
339 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800341 put_user_ex(regs->di, &sc->di);
342 put_user_ex(regs->si, &sc->si);
343 put_user_ex(regs->bp, &sc->bp);
344 put_user_ex(regs->sp, &sc->sp);
345 put_user_ex(regs->bx, &sc->bx);
346 put_user_ex(regs->dx, &sc->dx);
347 put_user_ex(regs->cx, &sc->cx);
348 put_user_ex(regs->ax, &sc->ax);
Srikar Dronamraju51e7dc72012-03-12 14:55:55 +0530349 put_user_ex(current->thread.trap_nr, &sc->trapno);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800350 put_user_ex(current->thread.error_code, &sc->err);
351 put_user_ex(regs->ip, &sc->ip);
352 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
353 put_user_ex(regs->flags, &sc->flags);
354 put_user_ex(regs->sp, &sc->sp_at_signal);
355 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800357 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800359 /* non-iBCS2 extensions.. */
360 put_user_ex(mask, &sc->oldmask);
361 put_user_ex(current->thread.cr2, &sc->cr2);
362 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364 return err;
365}
366
367/*
368 * Determine which stack to use..
369 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100370static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700371 size_t frame_size,
Suresh Siddhaab513702008-07-29 10:29:22 -0700372 void **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100374 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100377 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379 /* This is the X/Open sanctioned signal stack switching. */
380 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100381 if (sas_ss_flags(sp) == 0)
382 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 }
384
385 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800386 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100388 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100389 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700391 if (used_math()) {
392 sp = sp - sig_xstate_ia32_size;
393 *fpstate = (struct _fpstate_ia32 *) sp;
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800394 if (save_i387_xstate_ia32(*fpstate) < 0)
395 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700396 }
397
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100398 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200399 /* Align the stack pointer according to the i386 ABI,
400 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100401 sp = ((sp + 4) & -16ul) - 4;
402 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403}
404
Roland McGrath0928d6e2005-06-23 00:08:37 -0700405int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100406 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800408 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100409 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700411 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100413 /* copy_to_user optimizes that into a single 8 byte store */
414 static const struct {
415 u16 poplmovl;
416 u32 val;
417 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100418 } __attribute__((packed)) code = {
419 0xb858, /* popl %eax ; movl $...,%eax */
420 __NR_ia32_sigreturn,
421 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100422 };
423
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700424 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
426 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700427 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700429 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700430 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700432 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700433 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
435 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700436 if (__copy_to_user(frame->extramask, &set->sig[1],
437 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700438 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Roland McGrathaf65d642008-01-30 13:30:43 +0100441 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100442 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100443 } else {
444 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700445 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100446 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
447 sigreturn);
448 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100449 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100450 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100451
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800452 put_user_try {
453 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
454
455 /*
456 * These are actually not used anymore, but left because some
457 * gdb versions depend on them as a marker.
458 */
459 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
460 } put_user_catch(err);
461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700463 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100466 regs->sp = (unsigned long) frame;
467 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Andi Kleen536e3ee2006-09-26 10:52:41 +0200469 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100470 regs->ax = sig;
471 regs->dx = 0;
472 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200473
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700474 loadsegment(ds, __USER32_DS);
475 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100477 regs->cs = __USER32_CS;
478 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
Andi Kleen1d001df2006-09-26 10:52:26 +0200480 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481}
482
Roland McGrath0928d6e2005-06-23 00:08:37 -0700483int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100484 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800486 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100487 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700489 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100491 /* __copy_to_user optimizes that into a single 8 byte store */
492 static const struct {
493 u8 movl;
494 u32 val;
495 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800496 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100497 } __attribute__((packed)) code = {
498 0xb8,
499 __NR_ia32_rt_sigreturn,
500 0x80cd,
501 0,
502 };
503
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700504 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
506 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700507 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800509 put_user_try {
510 put_user_ex(sig, &frame->sig);
511 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
512 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
513 err |= copy_siginfo_to_user32(&frame->info, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800515 /* Create the ucontext. */
516 if (cpu_has_xsave)
517 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
518 else
519 put_user_ex(0, &frame->uc.uc_flags);
520 put_user_ex(0, &frame->uc.uc_link);
521 put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
522 put_user_ex(sas_ss_flags(regs->sp),
523 &frame->uc.uc_stack.ss_flags);
524 put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
525 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
526 regs, set->sig[0]);
527 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800529 if (ka->sa.sa_flags & SA_RESTORER)
530 restorer = ka->sa.sa_restorer;
531 else
532 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
533 rt_sigreturn);
534 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800536 /*
537 * Not actually used anymore, but left because some gdb
538 * versions need it.
539 */
540 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
541 } put_user_catch(err);
542
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700544 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
546 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100547 regs->sp = (unsigned long) frame;
548 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500550 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100551 regs->ax = sig;
552 regs->dx = (unsigned long) &frame->info;
553 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500554
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700555 loadsegment(ds, __USER32_DS);
556 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100557
558 regs->cs = __USER32_CS;
559 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
Andi Kleen1d001df2006-09-26 10:52:26 +0200561 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562}