blob: 588a7aa937e145f4d0b6e0eb29860b13298ec363 [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 Torvalds1da177e2005-04-16 15:20:36 -070027#include <asm/ptrace.h>
28#include <asm/ia32_unistd.h>
29#include <asm/user32.h>
30#include <asm/sigcontext32.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <asm/proto.h>
Roland McGrathaf65d642008-01-30 13:30:43 +010032#include <asm/vdso.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080033#include <asm/sigframe.h>
Jaswinder Singh Rajput2f06de02008-12-27 21:37:10 +053034#include <asm/sys_ia32.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080035
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
37
Hiroshi Shimamotofbdb7da2008-07-14 15:34:09 -070038#define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \
39 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
40 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
41 X86_EFLAGS_CF)
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
44
45int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
46{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080047 int err = 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010048
49 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 return -EFAULT;
51
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080052 put_user_try {
53 /* If you change siginfo_t structure, please make sure that
54 this code is fixed accordingly.
55 It should never copy any pad contained in the structure
56 to avoid security leaks, but must copy the generic
57 3 ints plus the relevant union member. */
58 put_user_ex(from->si_signo, &to->si_signo);
59 put_user_ex(from->si_errno, &to->si_errno);
60 put_user_ex((short)from->si_code, &to->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080062 if (from->si_code < 0) {
63 put_user_ex(from->si_pid, &to->si_pid);
64 put_user_ex(from->si_uid, &to->si_uid);
65 put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
66 } else {
67 /*
68 * First 32bits of unions are always present:
69 * si_pid === si_band === si_tid === si_addr(LS half)
70 */
71 put_user_ex(from->_sifields._pad[0],
72 &to->_sifields._pad[0]);
73 switch (from->si_code >> 16) {
74 case __SI_FAULT >> 16:
75 break;
76 case __SI_CHLD >> 16:
77 put_user_ex(from->si_utime, &to->si_utime);
78 put_user_ex(from->si_stime, &to->si_stime);
79 put_user_ex(from->si_status, &to->si_status);
80 /* FALL THROUGH */
81 default:
82 case __SI_KILL >> 16:
83 put_user_ex(from->si_uid, &to->si_uid);
84 break;
85 case __SI_POLL >> 16:
86 put_user_ex(from->si_fd, &to->si_fd);
87 break;
88 case __SI_TIMER >> 16:
89 put_user_ex(from->si_overrun, &to->si_overrun);
90 put_user_ex(ptr_to_compat(from->si_ptr),
91 &to->si_ptr);
92 break;
93 /* This is not generated by the kernel as of now. */
94 case __SI_RT >> 16:
95 case __SI_MESGQ >> 16:
96 put_user_ex(from->si_uid, &to->si_uid);
97 put_user_ex(from->si_int, &to->si_int);
98 break;
99 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800101 } put_user_catch(err);
102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 return err;
104}
105
106int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
107{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800108 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 u32 ptr32;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100110
111 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 return -EFAULT;
113
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800114 get_user_try {
115 get_user_ex(to->si_signo, &from->si_signo);
116 get_user_ex(to->si_errno, &from->si_errno);
117 get_user_ex(to->si_code, &from->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800119 get_user_ex(to->si_pid, &from->si_pid);
120 get_user_ex(to->si_uid, &from->si_uid);
121 get_user_ex(ptr32, &from->si_ptr);
122 to->si_ptr = compat_ptr(ptr32);
123 } get_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125 return err;
126}
127
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100128asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 mask &= _BLOCKABLE;
131 spin_lock_irq(&current->sighand->siglock);
Andi Kleen1d001df2006-09-26 10:52:26 +0200132 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 siginitset(&current->blocked, mask);
134 recalc_sigpending();
135 spin_unlock_irq(&current->sighand->siglock);
136
Andi Kleen1d001df2006-09-26 10:52:26 +0200137 current->state = TASK_INTERRUPTIBLE;
138 schedule();
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);
282 spin_lock_irq(&current->sighand->siglock);
283 current->blocked = set;
284 recalc_sigpending();
285 spin_unlock_irq(&current->sighand->siglock);
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);
311 spin_lock_irq(&current->sighand->siglock);
312 current->blocked = set;
313 recalc_sigpending();
314 spin_unlock_irq(&current->sighand->siglock);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100315
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100316 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 goto badframe;
318
319 tregs = *regs;
320 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
321 goto badframe;
322
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100323 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100326 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100328}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330/*
331 * Set up a signal frame.
332 */
333
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100334static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700335 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100336 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800338 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800340 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800341 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
342 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
343 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
344 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800346 put_user_ex(regs->di, &sc->di);
347 put_user_ex(regs->si, &sc->si);
348 put_user_ex(regs->bp, &sc->bp);
349 put_user_ex(regs->sp, &sc->sp);
350 put_user_ex(regs->bx, &sc->bx);
351 put_user_ex(regs->dx, &sc->dx);
352 put_user_ex(regs->cx, &sc->cx);
353 put_user_ex(regs->ax, &sc->ax);
354 put_user_ex(current->thread.trap_no, &sc->trapno);
355 put_user_ex(current->thread.error_code, &sc->err);
356 put_user_ex(regs->ip, &sc->ip);
357 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
358 put_user_ex(regs->flags, &sc->flags);
359 put_user_ex(regs->sp, &sc->sp_at_signal);
360 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800362 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800364 /* non-iBCS2 extensions.. */
365 put_user_ex(mask, &sc->oldmask);
366 put_user_ex(current->thread.cr2, &sc->cr2);
367 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369 return err;
370}
371
372/*
373 * Determine which stack to use..
374 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100375static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700376 size_t frame_size,
Suresh Siddhaab513702008-07-29 10:29:22 -0700377 void **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100379 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
381 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100382 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 /* This is the X/Open sanctioned signal stack switching. */
385 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100386 if (sas_ss_flags(sp) == 0)
387 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 }
389
390 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800391 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100393 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100394 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700396 if (used_math()) {
397 sp = sp - sig_xstate_ia32_size;
398 *fpstate = (struct _fpstate_ia32 *) sp;
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800399 if (save_i387_xstate_ia32(*fpstate) < 0)
400 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700401 }
402
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100403 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200404 /* Align the stack pointer according to the i386 ABI,
405 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100406 sp = ((sp + 4) & -16ul) - 4;
407 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408}
409
Roland McGrath0928d6e2005-06-23 00:08:37 -0700410int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100411 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800413 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100414 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700416 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100418 /* copy_to_user optimizes that into a single 8 byte store */
419 static const struct {
420 u16 poplmovl;
421 u32 val;
422 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100423 } __attribute__((packed)) code = {
424 0xb858, /* popl %eax ; movl $...,%eax */
425 __NR_ia32_sigreturn,
426 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100427 };
428
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700429 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
431 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
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 (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700435 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700437 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700438 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
440 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700441 if (__copy_to_user(frame->extramask, &set->sig[1],
442 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700443 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Roland McGrathaf65d642008-01-30 13:30:43 +0100446 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100447 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100448 } else {
449 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700450 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100451 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
452 sigreturn);
453 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100454 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100455 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100456
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800457 put_user_try {
458 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
459
460 /*
461 * These are actually not used anymore, but left because some
462 * gdb versions depend on them as a marker.
463 */
464 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
465 } put_user_catch(err);
466
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700468 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100471 regs->sp = (unsigned long) frame;
472 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
Andi Kleen536e3ee2006-09-26 10:52:41 +0200474 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100475 regs->ax = sig;
476 regs->dx = 0;
477 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200478
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700479 loadsegment(ds, __USER32_DS);
480 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100482 regs->cs = __USER32_CS;
483 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Andi Kleen1d001df2006-09-26 10:52:26 +0200485 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486}
487
Roland McGrath0928d6e2005-06-23 00:08:37 -0700488int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100489 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800491 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100492 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700494 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100496 /* __copy_to_user optimizes that into a single 8 byte store */
497 static const struct {
498 u8 movl;
499 u32 val;
500 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800501 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100502 } __attribute__((packed)) code = {
503 0xb8,
504 __NR_ia32_rt_sigreturn,
505 0x80cd,
506 0,
507 };
508
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700509 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
511 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700512 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800514 put_user_try {
515 put_user_ex(sig, &frame->sig);
516 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
517 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
518 err |= copy_siginfo_to_user32(&frame->info, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800520 /* Create the ucontext. */
521 if (cpu_has_xsave)
522 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
523 else
524 put_user_ex(0, &frame->uc.uc_flags);
525 put_user_ex(0, &frame->uc.uc_link);
526 put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
527 put_user_ex(sas_ss_flags(regs->sp),
528 &frame->uc.uc_stack.ss_flags);
529 put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
530 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
531 regs, set->sig[0]);
532 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800534 if (ka->sa.sa_flags & SA_RESTORER)
535 restorer = ka->sa.sa_restorer;
536 else
537 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
538 rt_sigreturn);
539 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800541 /*
542 * Not actually used anymore, but left because some gdb
543 * versions need it.
544 */
545 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
546 } put_user_catch(err);
547
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700549 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
551 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100552 regs->sp = (unsigned long) frame;
553 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500555 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100556 regs->ax = sig;
557 regs->dx = (unsigned long) &frame->info;
558 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500559
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700560 loadsegment(ds, __USER32_DS);
561 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100562
563 regs->cs = __USER32_CS;
564 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Andi Kleen1d001df2006-09-26 10:52:26 +0200566 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567}