blob: 673ac9b63d6bf51ca36e2a0f18c4ca0d125d4fde [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);
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100165 ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100166 set_fs(seg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 if (ret >= 0 && uoss_ptr) {
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800168 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
169 return -EFAULT;
170
171 put_user_try {
172 put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
173 put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
174 put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
175 } put_user_catch(err);
176
177 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 ret = -EFAULT;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100179 }
180 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181}
182
183/*
184 * Do a signal return; undo the signal stack.
185 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800186#define loadsegment_gs(v) load_gs_index(v)
187#define loadsegment_fs(v) loadsegment(fs, v)
188#define loadsegment_ds(v) loadsegment(ds, v)
189#define loadsegment_es(v) loadsegment(es, v)
190
191#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
192#define set_user_seg(seg, v) loadsegment_##seg(v)
193
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800194#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800195 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196}
197
Hiroshi Shimamoto8801ead2009-02-20 19:00:13 -0800198#define GET_SEG(seg) ({ \
199 unsigned short tmp; \
200 get_user_ex(tmp, &sc->seg); \
201 tmp; \
202})
203
204#define COPY_SEG_CPL3(seg) do { \
205 regs->seg = GET_SEG(seg) | 3; \
206} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800207
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800208#define RELOAD_SEG(seg) { \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800209 unsigned int pre = GET_SEG(seg); \
210 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800211 pre |= 3; \
212 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800213 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800214}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100216static int ia32_restore_sigcontext(struct pt_regs *regs,
217 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800218 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100219{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800220 unsigned int tmpflags, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700221 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100222 u32 tmp;
223
224 /* Always make any pending restarted system calls return -EINTR */
225 current_thread_info()->restart_block.fn = do_no_restart_syscall;
226
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800227 get_user_try {
228 /*
229 * Reload fs and gs if they have changed in the signal
230 * handler. This does not handle long fs/gs base changes in
231 * the handler, but does not clobber them at least in the
232 * normal case.
233 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800234 RELOAD_SEG(gs);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800235 RELOAD_SEG(fs);
236 RELOAD_SEG(ds);
237 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800239 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
240 COPY(dx); COPY(cx); COPY(ip);
241 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800243 COPY_SEG_CPL3(cs);
244 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800246 get_user_ex(tmpflags, &sc->flags);
247 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
248 /* disable syscall checks */
249 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100250
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800251 get_user_ex(tmp, &sc->fpstate);
252 buf = compat_ptr(tmp);
253 err |= restore_i387_xstate_ia32(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800255 get_user_ex(*pax, &sc->ax);
256 } get_user_catch(err);
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259}
260
261asmlinkage long sys32_sigreturn(struct pt_regs *regs)
262{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800263 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100265 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
268 goto badframe;
269 if (__get_user(set.sig[0], &frame->sc.oldmask)
270 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100271 && __copy_from_user((((char *) &set.sig) + 4),
272 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 sizeof(frame->extramask))))
274 goto badframe;
275
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200276 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100277
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100278 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100280 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282badframe:
283 signal_fault(regs, frame, "32bit sigreturn");
284 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100285}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
288{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800289 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100291 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 struct pt_regs tregs;
293
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800294 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
297 goto badframe;
298 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
299 goto badframe;
300
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200301 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100302
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100303 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 goto badframe;
305
306 tregs = *regs;
307 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
308 goto badframe;
309
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100310 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100313 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100315}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317/*
318 * Set up a signal frame.
319 */
320
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100321static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700322 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100323 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800325 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800327 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800328 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
329 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
330 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
331 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800333 put_user_ex(regs->di, &sc->di);
334 put_user_ex(regs->si, &sc->si);
335 put_user_ex(regs->bp, &sc->bp);
336 put_user_ex(regs->sp, &sc->sp);
337 put_user_ex(regs->bx, &sc->bx);
338 put_user_ex(regs->dx, &sc->dx);
339 put_user_ex(regs->cx, &sc->cx);
340 put_user_ex(regs->ax, &sc->ax);
Srikar Dronamraju51e7dc72012-03-12 14:55:55 +0530341 put_user_ex(current->thread.trap_nr, &sc->trapno);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800342 put_user_ex(current->thread.error_code, &sc->err);
343 put_user_ex(regs->ip, &sc->ip);
344 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
345 put_user_ex(regs->flags, &sc->flags);
346 put_user_ex(regs->sp, &sc->sp_at_signal);
347 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800349 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800351 /* non-iBCS2 extensions.. */
352 put_user_ex(mask, &sc->oldmask);
353 put_user_ex(current->thread.cr2, &sc->cr2);
354 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356 return err;
357}
358
359/*
360 * Determine which stack to use..
361 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100362static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700363 size_t frame_size,
Suresh Siddhaab513702008-07-29 10:29:22 -0700364 void **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100366 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
368 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100369 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 /* This is the X/Open sanctioned signal stack switching. */
372 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100373 if (sas_ss_flags(sp) == 0)
374 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 }
376
377 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800378 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100380 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100381 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700383 if (used_math()) {
384 sp = sp - sig_xstate_ia32_size;
385 *fpstate = (struct _fpstate_ia32 *) sp;
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800386 if (save_i387_xstate_ia32(*fpstate) < 0)
387 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700388 }
389
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100390 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200391 /* Align the stack pointer according to the i386 ABI,
392 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100393 sp = ((sp + 4) & -16ul) - 4;
394 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395}
396
Roland McGrath0928d6e2005-06-23 00:08:37 -0700397int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100398 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800400 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100401 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700403 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100405 /* copy_to_user optimizes that into a single 8 byte store */
406 static const struct {
407 u16 poplmovl;
408 u32 val;
409 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100410 } __attribute__((packed)) code = {
411 0xb858, /* popl %eax ; movl $...,%eax */
412 __NR_ia32_sigreturn,
413 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100414 };
415
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700416 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
418 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700419 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700421 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700422 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700424 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700425 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700428 if (__copy_to_user(frame->extramask, &set->sig[1],
429 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700430 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Roland McGrathaf65d642008-01-30 13:30:43 +0100433 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100434 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100435 } else {
436 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700437 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100438 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
439 sigreturn);
440 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100441 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100442 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100443
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800444 put_user_try {
445 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
446
447 /*
448 * These are actually not used anymore, but left because some
449 * gdb versions depend on them as a marker.
450 */
451 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
452 } put_user_catch(err);
453
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700455 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
457 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100458 regs->sp = (unsigned long) frame;
459 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Andi Kleen536e3ee2006-09-26 10:52:41 +0200461 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100462 regs->ax = sig;
463 regs->dx = 0;
464 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200465
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700466 loadsegment(ds, __USER32_DS);
467 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100469 regs->cs = __USER32_CS;
470 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
Andi Kleen1d001df2006-09-26 10:52:26 +0200472 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473}
474
Roland McGrath0928d6e2005-06-23 00:08:37 -0700475int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100476 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800478 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100479 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700481 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100483 /* __copy_to_user optimizes that into a single 8 byte store */
484 static const struct {
485 u8 movl;
486 u32 val;
487 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800488 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100489 } __attribute__((packed)) code = {
490 0xb8,
491 __NR_ia32_rt_sigreturn,
492 0x80cd,
493 0,
494 };
495
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700496 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497
498 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700499 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800501 put_user_try {
502 put_user_ex(sig, &frame->sig);
503 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
504 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
505 err |= copy_siginfo_to_user32(&frame->info, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800507 /* Create the ucontext. */
508 if (cpu_has_xsave)
509 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
510 else
511 put_user_ex(0, &frame->uc.uc_flags);
512 put_user_ex(0, &frame->uc.uc_link);
513 put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
514 put_user_ex(sas_ss_flags(regs->sp),
515 &frame->uc.uc_stack.ss_flags);
516 put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
517 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
518 regs, set->sig[0]);
519 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800521 if (ka->sa.sa_flags & SA_RESTORER)
522 restorer = ka->sa.sa_restorer;
523 else
524 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
525 rt_sigreturn);
526 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800528 /*
529 * Not actually used anymore, but left because some gdb
530 * versions need it.
531 */
532 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
533 } put_user_catch(err);
534
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
Andi Kleen1d001df2006-09-26 10:52:26 +0200553 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554}