blob: 452d4dd0a95a941267500d1e2955928f7d21f8e6 [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;
Suresh Siddha0b91f452012-06-14 18:07:15 -070041 bool ia32 = test_thread_flag(TIF_IA32);
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;
Will Drewrya0727e82012-04-12 16:48:00 -050070 case __SI_SYS >> 16:
71 put_user_ex(from->si_syscall, &to->si_syscall);
72 put_user_ex(from->si_arch, &to->si_arch);
73 break;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080074 case __SI_CHLD >> 16:
H. Peter Anvine7084fd2012-03-05 13:40:24 -080075 if (ia32) {
76 put_user_ex(from->si_utime, &to->si_utime);
77 put_user_ex(from->si_stime, &to->si_stime);
78 } else {
79 put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
80 put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
81 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080082 put_user_ex(from->si_status, &to->si_status);
83 /* FALL THROUGH */
84 default:
85 case __SI_KILL >> 16:
86 put_user_ex(from->si_uid, &to->si_uid);
87 break;
88 case __SI_POLL >> 16:
89 put_user_ex(from->si_fd, &to->si_fd);
90 break;
91 case __SI_TIMER >> 16:
92 put_user_ex(from->si_overrun, &to->si_overrun);
93 put_user_ex(ptr_to_compat(from->si_ptr),
94 &to->si_ptr);
95 break;
96 /* This is not generated by the kernel as of now. */
97 case __SI_RT >> 16:
98 case __SI_MESGQ >> 16:
99 put_user_ex(from->si_uid, &to->si_uid);
100 put_user_ex(from->si_int, &to->si_int);
101 break;
102 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800104 } put_user_catch(err);
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 return err;
107}
108
109int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
110{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800111 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 u32 ptr32;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100113
114 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 return -EFAULT;
116
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800117 get_user_try {
118 get_user_ex(to->si_signo, &from->si_signo);
119 get_user_ex(to->si_errno, &from->si_errno);
120 get_user_ex(to->si_code, &from->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800122 get_user_ex(to->si_pid, &from->si_pid);
123 get_user_ex(to->si_uid, &from->si_uid);
124 get_user_ex(ptr32, &from->si_ptr);
125 to->si_ptr = compat_ptr(ptr32);
126 } get_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128 return err;
129}
130
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100131asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132{
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200133 sigset_t blocked;
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200134 siginitset(&blocked, mask);
Al Viro68f3f162012-05-21 21:42:32 -0400135 return sigsuspend(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100138asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
139 stack_ia32_t __user *uoss_ptr,
140 struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141{
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100142 stack_t uss, uoss;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800143 int ret, err = 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100144 mm_segment_t seg;
145
146 if (uss_ptr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 u32 ptr;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100148
149 memset(&uss, 0, sizeof(stack_t));
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800150 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)))
151 return -EFAULT;
152
153 get_user_try {
154 get_user_ex(ptr, &uss_ptr->ss_sp);
155 get_user_ex(uss.ss_flags, &uss_ptr->ss_flags);
156 get_user_ex(uss.ss_size, &uss_ptr->ss_size);
157 } get_user_catch(err);
158
159 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 return -EFAULT;
161 uss.ss_sp = compat_ptr(ptr);
162 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100163 seg = get_fs();
164 set_fs(KERNEL_DS);
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200165 ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
166 (stack_t __force __user *) &uoss, regs->sp);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100167 set_fs(seg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 if (ret >= 0 && uoss_ptr) {
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800169 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
170 return -EFAULT;
171
172 put_user_try {
173 put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
174 put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
175 put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
176 } put_user_catch(err);
177
178 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 ret = -EFAULT;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100180 }
181 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182}
183
184/*
185 * Do a signal return; undo the signal stack.
186 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800187#define loadsegment_gs(v) load_gs_index(v)
188#define loadsegment_fs(v) loadsegment(fs, v)
189#define loadsegment_ds(v) loadsegment(ds, v)
190#define loadsegment_es(v) loadsegment(es, v)
191
192#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
193#define set_user_seg(seg, v) loadsegment_##seg(v)
194
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800195#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800196 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197}
198
Hiroshi Shimamoto8801ead2009-02-20 19:00:13 -0800199#define GET_SEG(seg) ({ \
200 unsigned short tmp; \
201 get_user_ex(tmp, &sc->seg); \
202 tmp; \
203})
204
205#define COPY_SEG_CPL3(seg) do { \
206 regs->seg = GET_SEG(seg) | 3; \
207} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800208
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800209#define RELOAD_SEG(seg) { \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800210 unsigned int pre = GET_SEG(seg); \
211 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800212 pre |= 3; \
213 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800214 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800215}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100217static int ia32_restore_sigcontext(struct pt_regs *regs,
218 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800219 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100220{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800221 unsigned int tmpflags, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700222 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100223 u32 tmp;
224
225 /* Always make any pending restarted system calls return -EINTR */
226 current_thread_info()->restart_block.fn = do_no_restart_syscall;
227
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800228 get_user_try {
229 /*
230 * Reload fs and gs if they have changed in the signal
231 * handler. This does not handle long fs/gs base changes in
232 * the handler, but does not clobber them at least in the
233 * normal case.
234 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800235 RELOAD_SEG(gs);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800236 RELOAD_SEG(fs);
237 RELOAD_SEG(ds);
238 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800240 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
241 COPY(dx); COPY(cx); COPY(ip);
242 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800244 COPY_SEG_CPL3(cs);
245 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800247 get_user_ex(tmpflags, &sc->flags);
248 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
249 /* disable syscall checks */
250 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100251
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800252 get_user_ex(tmp, &sc->fpstate);
253 buf = compat_ptr(tmp);
254 err |= restore_i387_xstate_ia32(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800256 get_user_ex(*pax, &sc->ax);
257 } get_user_catch(err);
258
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260}
261
262asmlinkage long sys32_sigreturn(struct pt_regs *regs)
263{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800264 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100266 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
269 goto badframe;
270 if (__get_user(set.sig[0], &frame->sc.oldmask)
271 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100272 && __copy_from_user((((char *) &set.sig) + 4),
273 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 sizeof(frame->extramask))))
275 goto badframe;
276
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200277 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100278
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100279 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100281 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
283badframe:
284 signal_fault(regs, frame, "32bit sigreturn");
285 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100286}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
289{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800290 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100292 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 struct pt_regs tregs;
294
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800295 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
298 goto badframe;
299 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
300 goto badframe;
301
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200302 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100303
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100304 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 goto badframe;
306
307 tregs = *regs;
308 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
309 goto badframe;
310
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100311 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100314 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100316}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318/*
319 * Set up a signal frame.
320 */
321
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100322static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700323 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100324 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800326 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800328 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800329 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
330 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
331 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
332 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800334 put_user_ex(regs->di, &sc->di);
335 put_user_ex(regs->si, &sc->si);
336 put_user_ex(regs->bp, &sc->bp);
337 put_user_ex(regs->sp, &sc->sp);
338 put_user_ex(regs->bx, &sc->bx);
339 put_user_ex(regs->dx, &sc->dx);
340 put_user_ex(regs->cx, &sc->cx);
341 put_user_ex(regs->ax, &sc->ax);
Srikar Dronamraju51e7dc72012-03-12 14:55:55 +0530342 put_user_ex(current->thread.trap_nr, &sc->trapno);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800343 put_user_ex(current->thread.error_code, &sc->err);
344 put_user_ex(regs->ip, &sc->ip);
345 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
346 put_user_ex(regs->flags, &sc->flags);
347 put_user_ex(regs->sp, &sc->sp_at_signal);
348 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800350 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800352 /* non-iBCS2 extensions.. */
353 put_user_ex(mask, &sc->oldmask);
354 put_user_ex(current->thread.cr2, &sc->cr2);
355 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357 return err;
358}
359
360/*
361 * Determine which stack to use..
362 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100363static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700364 size_t frame_size,
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200365 void __user **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100367 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100370 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
372 /* This is the X/Open sanctioned signal stack switching. */
373 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100374 if (sas_ss_flags(sp) == 0)
375 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 }
377
378 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800379 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100381 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100382 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700384 if (used_math()) {
385 sp = sp - sig_xstate_ia32_size;
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200386 *fpstate = (struct _fpstate_ia32 __user *) sp;
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800387 if (save_i387_xstate_ia32(*fpstate) < 0)
388 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700389 }
390
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100391 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200392 /* Align the stack pointer according to the i386 ABI,
393 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100394 sp = ((sp + 4) & -16ul) - 4;
395 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396}
397
Roland McGrath0928d6e2005-06-23 00:08:37 -0700398int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100399 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800401 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100402 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700404 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100406 /* copy_to_user optimizes that into a single 8 byte store */
407 static const struct {
408 u16 poplmovl;
409 u32 val;
410 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100411 } __attribute__((packed)) code = {
412 0xb858, /* popl %eax ; movl $...,%eax */
413 __NR_ia32_sigreturn,
414 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100415 };
416
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700417 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
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 (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700423 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700425 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700426 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700429 if (__copy_to_user(frame->extramask, &set->sig[1],
430 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700431 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
Roland McGrathaf65d642008-01-30 13:30:43 +0100434 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100435 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100436 } else {
437 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700438 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100439 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
440 sigreturn);
441 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100442 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100443 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100444
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800445 put_user_try {
446 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
447
448 /*
449 * These are actually not used anymore, but left because some
450 * gdb versions depend on them as a marker.
451 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200452 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800453 } put_user_catch(err);
454
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700456 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
458 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100459 regs->sp = (unsigned long) frame;
460 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Andi Kleen536e3ee2006-09-26 10:52:41 +0200462 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100463 regs->ax = sig;
464 regs->dx = 0;
465 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200466
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700467 loadsegment(ds, __USER32_DS);
468 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100470 regs->cs = __USER32_CS;
471 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Andi Kleen1d001df2006-09-26 10:52:26 +0200473 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474}
475
Roland McGrath0928d6e2005-06-23 00:08:37 -0700476int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100477 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800479 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100480 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700482 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100484 /* __copy_to_user optimizes that into a single 8 byte store */
485 static const struct {
486 u8 movl;
487 u32 val;
488 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800489 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100490 } __attribute__((packed)) code = {
491 0xb8,
492 __NR_ia32_rt_sigreturn,
493 0x80cd,
494 0,
495 };
496
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700497 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700500 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800502 put_user_try {
503 put_user_ex(sig, &frame->sig);
504 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
505 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
506 err |= copy_siginfo_to_user32(&frame->info, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800508 /* Create the ucontext. */
509 if (cpu_has_xsave)
510 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
511 else
512 put_user_ex(0, &frame->uc.uc_flags);
513 put_user_ex(0, &frame->uc.uc_link);
514 put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
515 put_user_ex(sas_ss_flags(regs->sp),
516 &frame->uc.uc_stack.ss_flags);
517 put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
518 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
519 regs, set->sig[0]);
520 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800522 if (ka->sa.sa_flags & SA_RESTORER)
523 restorer = ka->sa.sa_restorer;
524 else
525 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
526 rt_sigreturn);
527 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800529 /*
530 * Not actually used anymore, but left because some gdb
531 * versions need it.
532 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200533 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800534 } put_user_catch(err);
535
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700537 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100540 regs->sp = (unsigned long) frame;
541 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500543 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100544 regs->ax = sig;
545 regs->dx = (unsigned long) &frame->info;
546 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500547
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700548 loadsegment(ds, __USER32_DS);
549 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100550
551 regs->cs = __USER32_CS;
552 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Andi Kleen1d001df2006-09-26 10:52:26 +0200554 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555}