blob: 5563ba1cf5136556a618ae345abd0194dc58e75f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/x86_64/ia32/ia32_signal.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
7 * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
8 * 2000-12-* x86-64 compatibility mode signal handling by Andi Kleen
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10
11#include <linux/sched.h>
12#include <linux/mm.h>
13#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/kernel.h>
15#include <linux/signal.h>
16#include <linux/errno.h>
17#include <linux/wait.h>
18#include <linux/ptrace.h>
19#include <linux/unistd.h>
20#include <linux/stddef.h>
21#include <linux/personality.h>
22#include <linux/compat.h>
Andi Kleen9fbbd4d2007-02-13 13:26:26 +010023#include <linux/binfmts.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <asm/ucontext.h>
25#include <asm/uaccess.h>
26#include <asm/i387.h>
Linus Torvalds1361b832012-02-21 13:19:22 -080027#include <asm/fpu-internal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <asm/ptrace.h>
29#include <asm/ia32_unistd.h>
30#include <asm/user32.h>
31#include <asm/sigcontext32.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/proto.h>
Roland McGrathaf65d642008-01-30 13:30:43 +010033#include <asm/vdso.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080034#include <asm/sigframe.h>
Jaswinder Singh Rajput2f06de02008-12-27 21:37:10 +053035#include <asm/sys_ia32.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080036
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
38
Hiroshi Shimamotofbdb7da2008-07-14 15:34:09 -070039#define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \
40 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
41 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
42 X86_EFLAGS_CF)
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
45
46int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
47{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080048 int err = 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010049
50 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 return -EFAULT;
52
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080053 put_user_try {
54 /* If you change siginfo_t structure, please make sure that
55 this code is fixed accordingly.
56 It should never copy any pad contained in the structure
57 to avoid security leaks, but must copy the generic
58 3 ints plus the relevant union member. */
59 put_user_ex(from->si_signo, &to->si_signo);
60 put_user_ex(from->si_errno, &to->si_errno);
61 put_user_ex((short)from->si_code, &to->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080063 if (from->si_code < 0) {
64 put_user_ex(from->si_pid, &to->si_pid);
65 put_user_ex(from->si_uid, &to->si_uid);
66 put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
67 } else {
68 /*
69 * First 32bits of unions are always present:
70 * si_pid === si_band === si_tid === si_addr(LS half)
71 */
72 put_user_ex(from->_sifields._pad[0],
73 &to->_sifields._pad[0]);
74 switch (from->si_code >> 16) {
75 case __SI_FAULT >> 16:
76 break;
77 case __SI_CHLD >> 16:
78 put_user_ex(from->si_utime, &to->si_utime);
79 put_user_ex(from->si_stime, &to->si_stime);
80 put_user_ex(from->si_status, &to->si_status);
81 /* FALL THROUGH */
82 default:
83 case __SI_KILL >> 16:
84 put_user_ex(from->si_uid, &to->si_uid);
85 break;
86 case __SI_POLL >> 16:
87 put_user_ex(from->si_fd, &to->si_fd);
88 break;
89 case __SI_TIMER >> 16:
90 put_user_ex(from->si_overrun, &to->si_overrun);
91 put_user_ex(ptr_to_compat(from->si_ptr),
92 &to->si_ptr);
93 break;
94 /* This is not generated by the kernel as of now. */
95 case __SI_RT >> 16:
96 case __SI_MESGQ >> 16:
97 put_user_ex(from->si_uid, &to->si_uid);
98 put_user_ex(from->si_int, &to->si_int);
99 break;
100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800102 } put_user_catch(err);
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 return err;
105}
106
107int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
108{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800109 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 u32 ptr32;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100111
112 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 return -EFAULT;
114
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800115 get_user_try {
116 get_user_ex(to->si_signo, &from->si_signo);
117 get_user_ex(to->si_errno, &from->si_errno);
118 get_user_ex(to->si_code, &from->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800120 get_user_ex(to->si_pid, &from->si_pid);
121 get_user_ex(to->si_uid, &from->si_uid);
122 get_user_ex(ptr32, &from->si_ptr);
123 to->si_ptr = compat_ptr(ptr32);
124 } get_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126 return err;
127}
128
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100129asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200131 sigset_t blocked;
132
Andi Kleen1d001df2006-09-26 10:52:26 +0200133 current->saved_sigmask = current->blocked;
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200134
135 mask &= _BLOCKABLE;
136 siginitset(&blocked, mask);
137 set_current_blocked(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Andi Kleen1d001df2006-09-26 10:52:26 +0200139 current->state = TASK_INTERRUPTIBLE;
140 schedule();
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200141
Roland McGrath5a8da0e2008-04-30 00:53:10 -0700142 set_restore_sigmask();
Andi Kleen1d001df2006-09-26 10:52:26 +0200143 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144}
145
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100146asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
147 stack_ia32_t __user *uoss_ptr,
148 struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100150 stack_t uss, uoss;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800151 int ret, err = 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100152 mm_segment_t seg;
153
154 if (uss_ptr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 u32 ptr;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100156
157 memset(&uss, 0, sizeof(stack_t));
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800158 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)))
159 return -EFAULT;
160
161 get_user_try {
162 get_user_ex(ptr, &uss_ptr->ss_sp);
163 get_user_ex(uss.ss_flags, &uss_ptr->ss_flags);
164 get_user_ex(uss.ss_size, &uss_ptr->ss_size);
165 } get_user_catch(err);
166
167 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 return -EFAULT;
169 uss.ss_sp = compat_ptr(ptr);
170 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100171 seg = get_fs();
172 set_fs(KERNEL_DS);
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100173 ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100174 set_fs(seg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 if (ret >= 0 && uoss_ptr) {
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800176 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
177 return -EFAULT;
178
179 put_user_try {
180 put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
181 put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
182 put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
183 } put_user_catch(err);
184
185 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 ret = -EFAULT;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100187 }
188 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189}
190
191/*
192 * Do a signal return; undo the signal stack.
193 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800194#define loadsegment_gs(v) load_gs_index(v)
195#define loadsegment_fs(v) loadsegment(fs, v)
196#define loadsegment_ds(v) loadsegment(ds, v)
197#define loadsegment_es(v) loadsegment(es, v)
198
199#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
200#define set_user_seg(seg, v) loadsegment_##seg(v)
201
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800202#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800203 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204}
205
Hiroshi Shimamoto8801ead2009-02-20 19:00:13 -0800206#define GET_SEG(seg) ({ \
207 unsigned short tmp; \
208 get_user_ex(tmp, &sc->seg); \
209 tmp; \
210})
211
212#define COPY_SEG_CPL3(seg) do { \
213 regs->seg = GET_SEG(seg) | 3; \
214} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800215
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800216#define RELOAD_SEG(seg) { \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800217 unsigned int pre = GET_SEG(seg); \
218 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800219 pre |= 3; \
220 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800221 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800222}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100224static int ia32_restore_sigcontext(struct pt_regs *regs,
225 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800226 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100227{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800228 unsigned int tmpflags, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700229 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100230 u32 tmp;
231
232 /* Always make any pending restarted system calls return -EINTR */
233 current_thread_info()->restart_block.fn = do_no_restart_syscall;
234
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800235 get_user_try {
236 /*
237 * Reload fs and gs if they have changed in the signal
238 * handler. This does not handle long fs/gs base changes in
239 * the handler, but does not clobber them at least in the
240 * normal case.
241 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800242 RELOAD_SEG(gs);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800243 RELOAD_SEG(fs);
244 RELOAD_SEG(ds);
245 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800247 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
248 COPY(dx); COPY(cx); COPY(ip);
249 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800251 COPY_SEG_CPL3(cs);
252 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800254 get_user_ex(tmpflags, &sc->flags);
255 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
256 /* disable syscall checks */
257 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100258
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800259 get_user_ex(tmp, &sc->fpstate);
260 buf = compat_ptr(tmp);
261 err |= restore_i387_xstate_ia32(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800263 get_user_ex(*pax, &sc->ax);
264 } get_user_catch(err);
265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267}
268
269asmlinkage long sys32_sigreturn(struct pt_regs *regs)
270{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800271 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100273 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
276 goto badframe;
277 if (__get_user(set.sig[0], &frame->sc.oldmask)
278 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100279 && __copy_from_user((((char *) &set.sig) + 4),
280 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 sizeof(frame->extramask))))
282 goto badframe;
283
284 sigdelsetmask(&set, ~_BLOCKABLE);
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200285 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100286
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100287 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100289 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291badframe:
292 signal_fault(regs, frame, "32bit sigreturn");
293 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100294}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
297{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800298 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100300 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 struct pt_regs tregs;
302
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800303 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
306 goto badframe;
307 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
308 goto badframe;
309
310 sigdelsetmask(&set, ~_BLOCKABLE);
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200311 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100312
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100313 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 goto badframe;
315
316 tregs = *regs;
317 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
318 goto badframe;
319
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100320 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100323 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100325}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327/*
328 * Set up a signal frame.
329 */
330
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100331static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700332 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100333 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800335 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800337 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800338 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
339 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
340 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
341 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800343 put_user_ex(regs->di, &sc->di);
344 put_user_ex(regs->si, &sc->si);
345 put_user_ex(regs->bp, &sc->bp);
346 put_user_ex(regs->sp, &sc->sp);
347 put_user_ex(regs->bx, &sc->bx);
348 put_user_ex(regs->dx, &sc->dx);
349 put_user_ex(regs->cx, &sc->cx);
350 put_user_ex(regs->ax, &sc->ax);
351 put_user_ex(current->thread.trap_no, &sc->trapno);
352 put_user_ex(current->thread.error_code, &sc->err);
353 put_user_ex(regs->ip, &sc->ip);
354 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
355 put_user_ex(regs->flags, &sc->flags);
356 put_user_ex(regs->sp, &sc->sp_at_signal);
357 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800359 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800361 /* non-iBCS2 extensions.. */
362 put_user_ex(mask, &sc->oldmask);
363 put_user_ex(current->thread.cr2, &sc->cr2);
364 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 return err;
367}
368
369/*
370 * Determine which stack to use..
371 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100372static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700373 size_t frame_size,
Suresh Siddhaab513702008-07-29 10:29:22 -0700374 void **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100376 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100379 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
381 /* This is the X/Open sanctioned signal stack switching. */
382 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100383 if (sas_ss_flags(sp) == 0)
384 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 }
386
387 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800388 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100390 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100391 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700393 if (used_math()) {
394 sp = sp - sig_xstate_ia32_size;
395 *fpstate = (struct _fpstate_ia32 *) sp;
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800396 if (save_i387_xstate_ia32(*fpstate) < 0)
397 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700398 }
399
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100400 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200401 /* Align the stack pointer according to the i386 ABI,
402 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100403 sp = ((sp + 4) & -16ul) - 4;
404 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405}
406
Roland McGrath0928d6e2005-06-23 00:08:37 -0700407int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100408 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800410 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100411 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700413 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100415 /* copy_to_user optimizes that into a single 8 byte store */
416 static const struct {
417 u16 poplmovl;
418 u32 val;
419 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100420 } __attribute__((packed)) code = {
421 0xb858, /* popl %eax ; movl $...,%eax */
422 __NR_ia32_sigreturn,
423 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100424 };
425
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700426 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
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 (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700432 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700434 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700435 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700438 if (__copy_to_user(frame->extramask, &set->sig[1],
439 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700440 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
Roland McGrathaf65d642008-01-30 13:30:43 +0100443 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100444 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100445 } else {
446 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700447 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100448 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
449 sigreturn);
450 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100451 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100452 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100453
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800454 put_user_try {
455 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
456
457 /*
458 * These are actually not used anymore, but left because some
459 * gdb versions depend on them as a marker.
460 */
461 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
462 } put_user_catch(err);
463
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700465 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
467 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100468 regs->sp = (unsigned long) frame;
469 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
Andi Kleen536e3ee2006-09-26 10:52:41 +0200471 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100472 regs->ax = sig;
473 regs->dx = 0;
474 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200475
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700476 loadsegment(ds, __USER32_DS);
477 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100479 regs->cs = __USER32_CS;
480 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Andi Kleen1d001df2006-09-26 10:52:26 +0200482 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483}
484
Roland McGrath0928d6e2005-06-23 00:08:37 -0700485int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100486 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800488 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100489 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700491 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100493 /* __copy_to_user optimizes that into a single 8 byte store */
494 static const struct {
495 u8 movl;
496 u32 val;
497 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800498 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100499 } __attribute__((packed)) code = {
500 0xb8,
501 __NR_ia32_rt_sigreturn,
502 0x80cd,
503 0,
504 };
505
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700506 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700509 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800511 put_user_try {
512 put_user_ex(sig, &frame->sig);
513 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
514 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
515 err |= copy_siginfo_to_user32(&frame->info, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800517 /* Create the ucontext. */
518 if (cpu_has_xsave)
519 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
520 else
521 put_user_ex(0, &frame->uc.uc_flags);
522 put_user_ex(0, &frame->uc.uc_link);
523 put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
524 put_user_ex(sas_ss_flags(regs->sp),
525 &frame->uc.uc_stack.ss_flags);
526 put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
527 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
528 regs, set->sig[0]);
529 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800531 if (ka->sa.sa_flags & SA_RESTORER)
532 restorer = ka->sa.sa_restorer;
533 else
534 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
535 rt_sigreturn);
536 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800538 /*
539 * Not actually used anymore, but left because some gdb
540 * versions need it.
541 */
542 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
543 } put_user_catch(err);
544
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700546 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
548 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100549 regs->sp = (unsigned long) frame;
550 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500552 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100553 regs->ax = sig;
554 regs->dx = (unsigned long) &frame->info;
555 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500556
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700557 loadsegment(ds, __USER32_DS);
558 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100559
560 regs->cs = __USER32_CS;
561 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
Andi Kleen1d001df2006-09-26 10:52:26 +0200563 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564}