blob: bc09ed2a8b973ec748d6a885ab80f0392d29ba70 [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 Torvalds1da177e2005-04-16 15:20:36 -070025#include <asm/ptrace.h>
26#include <asm/ia32_unistd.h>
27#include <asm/user32.h>
28#include <asm/sigcontext32.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <asm/proto.h>
Roland McGrathaf65d642008-01-30 13:30:43 +010030#include <asm/vdso.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080031#include <asm/sigframe.h>
H. Peter Anvinf28f0c22012-02-19 07:38:43 -080032#include <asm/sighandling.h>
Jaswinder Singh Rajput2f06de02008-12-27 21:37:10 +053033#include <asm/sys_ia32.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080034
H. Peter Anvinf28f0c22012-02-19 07:38:43 -080035#define FIX_EFLAGS __FIX_EFLAGS
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
38{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080039 int err = 0;
H. Peter Anvine7084fd2012-03-05 13:40:24 -080040 bool ia32 = !is_ia32_task();
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010041
42 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 return -EFAULT;
44
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080045 put_user_try {
46 /* If you change siginfo_t structure, please make sure that
47 this code is fixed accordingly.
48 It should never copy any pad contained in the structure
49 to avoid security leaks, but must copy the generic
50 3 ints plus the relevant union member. */
51 put_user_ex(from->si_signo, &to->si_signo);
52 put_user_ex(from->si_errno, &to->si_errno);
53 put_user_ex((short)from->si_code, &to->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080055 if (from->si_code < 0) {
56 put_user_ex(from->si_pid, &to->si_pid);
57 put_user_ex(from->si_uid, &to->si_uid);
58 put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
59 } else {
60 /*
61 * First 32bits of unions are always present:
62 * si_pid === si_band === si_tid === si_addr(LS half)
63 */
64 put_user_ex(from->_sifields._pad[0],
65 &to->_sifields._pad[0]);
66 switch (from->si_code >> 16) {
67 case __SI_FAULT >> 16:
68 break;
69 case __SI_CHLD >> 16:
H. Peter Anvine7084fd2012-03-05 13:40:24 -080070 if (ia32) {
71 put_user_ex(from->si_utime, &to->si_utime);
72 put_user_ex(from->si_stime, &to->si_stime);
73 } else {
74 put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
75 put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
76 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080077 put_user_ex(from->si_status, &to->si_status);
78 /* FALL THROUGH */
79 default:
80 case __SI_KILL >> 16:
81 put_user_ex(from->si_uid, &to->si_uid);
82 break;
83 case __SI_POLL >> 16:
84 put_user_ex(from->si_fd, &to->si_fd);
85 break;
86 case __SI_TIMER >> 16:
87 put_user_ex(from->si_overrun, &to->si_overrun);
88 put_user_ex(ptr_to_compat(from->si_ptr),
89 &to->si_ptr);
90 break;
91 /* This is not generated by the kernel as of now. */
92 case __SI_RT >> 16:
93 case __SI_MESGQ >> 16:
94 put_user_ex(from->si_uid, &to->si_uid);
95 put_user_ex(from->si_int, &to->si_int);
96 break;
97 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080099 } put_user_catch(err);
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 return err;
102}
103
104int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
105{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800106 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 u32 ptr32;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100108
109 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 return -EFAULT;
111
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800112 get_user_try {
113 get_user_ex(to->si_signo, &from->si_signo);
114 get_user_ex(to->si_errno, &from->si_errno);
115 get_user_ex(to->si_code, &from->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800117 get_user_ex(to->si_pid, &from->si_pid);
118 get_user_ex(to->si_uid, &from->si_uid);
119 get_user_ex(ptr32, &from->si_ptr);
120 to->si_ptr = compat_ptr(ptr32);
121 } get_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
123 return err;
124}
125
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100126asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200128 sigset_t blocked;
129
Andi Kleen1d001df2006-09-26 10:52:26 +0200130 current->saved_sigmask = current->blocked;
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200131
132 mask &= _BLOCKABLE;
133 siginitset(&blocked, mask);
134 set_current_blocked(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
Andi Kleen1d001df2006-09-26 10:52:26 +0200136 current->state = TASK_INTERRUPTIBLE;
137 schedule();
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200138
Roland McGrath5a8da0e2008-04-30 00:53:10 -0700139 set_restore_sigmask();
Andi Kleen1d001df2006-09-26 10:52:26 +0200140 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141}
142
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100143asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
144 stack_ia32_t __user *uoss_ptr,
145 struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100147 stack_t uss, uoss;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800148 int ret, err = 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100149 mm_segment_t seg;
150
151 if (uss_ptr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 u32 ptr;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100153
154 memset(&uss, 0, sizeof(stack_t));
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800155 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)))
156 return -EFAULT;
157
158 get_user_try {
159 get_user_ex(ptr, &uss_ptr->ss_sp);
160 get_user_ex(uss.ss_flags, &uss_ptr->ss_flags);
161 get_user_ex(uss.ss_size, &uss_ptr->ss_size);
162 } get_user_catch(err);
163
164 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 return -EFAULT;
166 uss.ss_sp = compat_ptr(ptr);
167 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100168 seg = get_fs();
169 set_fs(KERNEL_DS);
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100170 ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100171 set_fs(seg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 if (ret >= 0 && uoss_ptr) {
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800173 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
174 return -EFAULT;
175
176 put_user_try {
177 put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
178 put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
179 put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
180 } put_user_catch(err);
181
182 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 ret = -EFAULT;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100184 }
185 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186}
187
188/*
189 * Do a signal return; undo the signal stack.
190 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800191#define loadsegment_gs(v) load_gs_index(v)
192#define loadsegment_fs(v) loadsegment(fs, v)
193#define loadsegment_ds(v) loadsegment(ds, v)
194#define loadsegment_es(v) loadsegment(es, v)
195
196#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
197#define set_user_seg(seg, v) loadsegment_##seg(v)
198
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800199#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800200 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201}
202
Hiroshi Shimamoto8801ead2009-02-20 19:00:13 -0800203#define GET_SEG(seg) ({ \
204 unsigned short tmp; \
205 get_user_ex(tmp, &sc->seg); \
206 tmp; \
207})
208
209#define COPY_SEG_CPL3(seg) do { \
210 regs->seg = GET_SEG(seg) | 3; \
211} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800212
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800213#define RELOAD_SEG(seg) { \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800214 unsigned int pre = GET_SEG(seg); \
215 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800216 pre |= 3; \
217 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800218 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800219}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100221static int ia32_restore_sigcontext(struct pt_regs *regs,
222 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800223 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100224{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800225 unsigned int tmpflags, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700226 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100227 u32 tmp;
228
229 /* Always make any pending restarted system calls return -EINTR */
230 current_thread_info()->restart_block.fn = do_no_restart_syscall;
231
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800232 get_user_try {
233 /*
234 * Reload fs and gs if they have changed in the signal
235 * handler. This does not handle long fs/gs base changes in
236 * the handler, but does not clobber them at least in the
237 * normal case.
238 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800239 RELOAD_SEG(gs);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800240 RELOAD_SEG(fs);
241 RELOAD_SEG(ds);
242 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800244 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
245 COPY(dx); COPY(cx); COPY(ip);
246 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800248 COPY_SEG_CPL3(cs);
249 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800251 get_user_ex(tmpflags, &sc->flags);
252 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
253 /* disable syscall checks */
254 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100255
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800256 get_user_ex(tmp, &sc->fpstate);
257 buf = compat_ptr(tmp);
258 err |= restore_i387_xstate_ia32(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800260 get_user_ex(*pax, &sc->ax);
261 } get_user_catch(err);
262
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
265
266asmlinkage long sys32_sigreturn(struct pt_regs *regs)
267{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800268 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100270 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
272 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
273 goto badframe;
274 if (__get_user(set.sig[0], &frame->sc.oldmask)
275 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100276 && __copy_from_user((((char *) &set.sig) + 4),
277 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 sizeof(frame->extramask))))
279 goto badframe;
280
281 sigdelsetmask(&set, ~_BLOCKABLE);
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200282 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100283
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100284 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100286 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288badframe:
289 signal_fault(regs, frame, "32bit sigreturn");
290 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100291}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
293asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
294{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800295 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100297 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 struct pt_regs tregs;
299
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800300 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
302 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
303 goto badframe;
304 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
305 goto badframe;
306
307 sigdelsetmask(&set, ~_BLOCKABLE);
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200308 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100309
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100310 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 goto badframe;
312
313 tregs = *regs;
314 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
315 goto badframe;
316
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100317 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100320 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100322}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324/*
325 * Set up a signal frame.
326 */
327
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100328static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700329 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100330 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800332 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800334 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800335 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
336 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
337 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
338 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800340 put_user_ex(regs->di, &sc->di);
341 put_user_ex(regs->si, &sc->si);
342 put_user_ex(regs->bp, &sc->bp);
343 put_user_ex(regs->sp, &sc->sp);
344 put_user_ex(regs->bx, &sc->bx);
345 put_user_ex(regs->dx, &sc->dx);
346 put_user_ex(regs->cx, &sc->cx);
347 put_user_ex(regs->ax, &sc->ax);
348 put_user_ex(current->thread.trap_no, &sc->trapno);
349 put_user_ex(current->thread.error_code, &sc->err);
350 put_user_ex(regs->ip, &sc->ip);
351 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
352 put_user_ex(regs->flags, &sc->flags);
353 put_user_ex(regs->sp, &sc->sp_at_signal);
354 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800356 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800358 /* non-iBCS2 extensions.. */
359 put_user_ex(mask, &sc->oldmask);
360 put_user_ex(current->thread.cr2, &sc->cr2);
361 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363 return err;
364}
365
366/*
367 * Determine which stack to use..
368 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100369static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700370 size_t frame_size,
Suresh Siddhaab513702008-07-29 10:29:22 -0700371 void **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100373 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100376 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 /* This is the X/Open sanctioned signal stack switching. */
379 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100380 if (sas_ss_flags(sp) == 0)
381 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 }
383
384 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800385 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100387 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100388 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700390 if (used_math()) {
391 sp = sp - sig_xstate_ia32_size;
392 *fpstate = (struct _fpstate_ia32 *) sp;
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800393 if (save_i387_xstate_ia32(*fpstate) < 0)
394 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700395 }
396
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100397 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200398 /* Align the stack pointer according to the i386 ABI,
399 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100400 sp = ((sp + 4) & -16ul) - 4;
401 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402}
403
Roland McGrath0928d6e2005-06-23 00:08:37 -0700404int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100405 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800407 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100408 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700410 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100412 /* copy_to_user optimizes that into a single 8 byte store */
413 static const struct {
414 u16 poplmovl;
415 u32 val;
416 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100417 } __attribute__((packed)) code = {
418 0xb858, /* popl %eax ; movl $...,%eax */
419 __NR_ia32_sigreturn,
420 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100421 };
422
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700423 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
425 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700426 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700428 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700429 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700431 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700432 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
434 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700435 if (__copy_to_user(frame->extramask, &set->sig[1],
436 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700437 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Roland McGrathaf65d642008-01-30 13:30:43 +0100440 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100441 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100442 } else {
443 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700444 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100445 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
446 sigreturn);
447 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100448 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100449 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100450
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800451 put_user_try {
452 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
453
454 /*
455 * These are actually not used anymore, but left because some
456 * gdb versions depend on them as a marker.
457 */
458 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
459 } put_user_catch(err);
460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700462 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100465 regs->sp = (unsigned long) frame;
466 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Andi Kleen536e3ee2006-09-26 10:52:41 +0200468 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100469 regs->ax = sig;
470 regs->dx = 0;
471 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200472
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700473 loadsegment(ds, __USER32_DS);
474 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100476 regs->cs = __USER32_CS;
477 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Andi Kleen1d001df2006-09-26 10:52:26 +0200479 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480}
481
Roland McGrath0928d6e2005-06-23 00:08:37 -0700482int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100483 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800485 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100486 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700488 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100490 /* __copy_to_user optimizes that into a single 8 byte store */
491 static const struct {
492 u8 movl;
493 u32 val;
494 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800495 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100496 } __attribute__((packed)) code = {
497 0xb8,
498 __NR_ia32_rt_sigreturn,
499 0x80cd,
500 0,
501 };
502
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700503 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700506 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800508 put_user_try {
509 put_user_ex(sig, &frame->sig);
510 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
511 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
512 err |= copy_siginfo_to_user32(&frame->info, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800514 /* Create the ucontext. */
515 if (cpu_has_xsave)
516 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
517 else
518 put_user_ex(0, &frame->uc.uc_flags);
519 put_user_ex(0, &frame->uc.uc_link);
520 put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
521 put_user_ex(sas_ss_flags(regs->sp),
522 &frame->uc.uc_stack.ss_flags);
523 put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
524 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
525 regs, set->sig[0]);
526 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800528 if (ka->sa.sa_flags & SA_RESTORER)
529 restorer = ka->sa.sa_restorer;
530 else
531 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
532 rt_sigreturn);
533 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800535 /*
536 * Not actually used anymore, but left because some gdb
537 * versions need it.
538 */
539 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
540 } put_user_catch(err);
541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700543 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100546 regs->sp = (unsigned long) frame;
547 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500549 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100550 regs->ax = sig;
551 regs->dx = (unsigned long) &frame->info;
552 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500553
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700554 loadsegment(ds, __USER32_DS);
555 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100556
557 regs->cs = __USER32_CS;
558 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
Andi Kleen1d001df2006-09-26 10:52:26 +0200560 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561}