blob: 65577698cab2e8f3b9729906fef935a1d114ed94 [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{
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200130 sigset_t blocked;
131
Andi Kleen1d001df2006-09-26 10:52:26 +0200132 current->saved_sigmask = current->blocked;
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200133
134 mask &= _BLOCKABLE;
135 siginitset(&blocked, mask);
136 set_current_blocked(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
Andi Kleen1d001df2006-09-26 10:52:26 +0200138 current->state = TASK_INTERRUPTIBLE;
139 schedule();
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200140
Roland McGrath5a8da0e2008-04-30 00:53:10 -0700141 set_restore_sigmask();
Andi Kleen1d001df2006-09-26 10:52:26 +0200142 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143}
144
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100145asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
146 stack_ia32_t __user *uoss_ptr,
147 struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148{
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100149 stack_t uss, uoss;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800150 int ret, err = 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100151 mm_segment_t seg;
152
153 if (uss_ptr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 u32 ptr;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100155
156 memset(&uss, 0, sizeof(stack_t));
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800157 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)))
158 return -EFAULT;
159
160 get_user_try {
161 get_user_ex(ptr, &uss_ptr->ss_sp);
162 get_user_ex(uss.ss_flags, &uss_ptr->ss_flags);
163 get_user_ex(uss.ss_size, &uss_ptr->ss_size);
164 } get_user_catch(err);
165
166 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 return -EFAULT;
168 uss.ss_sp = compat_ptr(ptr);
169 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100170 seg = get_fs();
171 set_fs(KERNEL_DS);
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100172 ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100173 set_fs(seg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 if (ret >= 0 && uoss_ptr) {
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800175 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
176 return -EFAULT;
177
178 put_user_try {
179 put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
180 put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
181 put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
182 } put_user_catch(err);
183
184 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 ret = -EFAULT;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100186 }
187 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188}
189
190/*
191 * Do a signal return; undo the signal stack.
192 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800193#define loadsegment_gs(v) load_gs_index(v)
194#define loadsegment_fs(v) loadsegment(fs, v)
195#define loadsegment_ds(v) loadsegment(ds, v)
196#define loadsegment_es(v) loadsegment(es, v)
197
198#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
199#define set_user_seg(seg, v) loadsegment_##seg(v)
200
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800201#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800202 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203}
204
Hiroshi Shimamoto8801ead2009-02-20 19:00:13 -0800205#define GET_SEG(seg) ({ \
206 unsigned short tmp; \
207 get_user_ex(tmp, &sc->seg); \
208 tmp; \
209})
210
211#define COPY_SEG_CPL3(seg) do { \
212 regs->seg = GET_SEG(seg) | 3; \
213} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800214
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800215#define RELOAD_SEG(seg) { \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800216 unsigned int pre = GET_SEG(seg); \
217 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800218 pre |= 3; \
219 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800220 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800221}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100223static int ia32_restore_sigcontext(struct pt_regs *regs,
224 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800225 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100226{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800227 unsigned int tmpflags, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700228 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100229 u32 tmp;
230
231 /* Always make any pending restarted system calls return -EINTR */
232 current_thread_info()->restart_block.fn = do_no_restart_syscall;
233
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800234 get_user_try {
235 /*
236 * Reload fs and gs if they have changed in the signal
237 * handler. This does not handle long fs/gs base changes in
238 * the handler, but does not clobber them at least in the
239 * normal case.
240 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800241 RELOAD_SEG(gs);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800242 RELOAD_SEG(fs);
243 RELOAD_SEG(ds);
244 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800246 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
247 COPY(dx); COPY(cx); COPY(ip);
248 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800250 COPY_SEG_CPL3(cs);
251 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800253 get_user_ex(tmpflags, &sc->flags);
254 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
255 /* disable syscall checks */
256 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100257
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800258 get_user_ex(tmp, &sc->fpstate);
259 buf = compat_ptr(tmp);
260 err |= restore_i387_xstate_ia32(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800262 get_user_ex(*pax, &sc->ax);
263 } get_user_catch(err);
264
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266}
267
268asmlinkage long sys32_sigreturn(struct pt_regs *regs)
269{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800270 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100272 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
274 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
275 goto badframe;
276 if (__get_user(set.sig[0], &frame->sc.oldmask)
277 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100278 && __copy_from_user((((char *) &set.sig) + 4),
279 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 sizeof(frame->extramask))))
281 goto badframe;
282
283 sigdelsetmask(&set, ~_BLOCKABLE);
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200284 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100285
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100286 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100288 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290badframe:
291 signal_fault(regs, frame, "32bit sigreturn");
292 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100293}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
296{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800297 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100299 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 struct pt_regs tregs;
301
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800302 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
305 goto badframe;
306 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
307 goto badframe;
308
309 sigdelsetmask(&set, ~_BLOCKABLE);
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200310 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100311
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100312 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 goto badframe;
314
315 tregs = *regs;
316 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
317 goto badframe;
318
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100319 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100322 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100324}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326/*
327 * Set up a signal frame.
328 */
329
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100330static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700331 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100332 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800334 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800336 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800337 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
338 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
339 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
340 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800342 put_user_ex(regs->di, &sc->di);
343 put_user_ex(regs->si, &sc->si);
344 put_user_ex(regs->bp, &sc->bp);
345 put_user_ex(regs->sp, &sc->sp);
346 put_user_ex(regs->bx, &sc->bx);
347 put_user_ex(regs->dx, &sc->dx);
348 put_user_ex(regs->cx, &sc->cx);
349 put_user_ex(regs->ax, &sc->ax);
350 put_user_ex(current->thread.trap_no, &sc->trapno);
351 put_user_ex(current->thread.error_code, &sc->err);
352 put_user_ex(regs->ip, &sc->ip);
353 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
354 put_user_ex(regs->flags, &sc->flags);
355 put_user_ex(regs->sp, &sc->sp_at_signal);
356 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800358 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800360 /* non-iBCS2 extensions.. */
361 put_user_ex(mask, &sc->oldmask);
362 put_user_ex(current->thread.cr2, &sc->cr2);
363 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 return err;
366}
367
368/*
369 * Determine which stack to use..
370 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100371static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700372 size_t frame_size,
Suresh Siddhaab513702008-07-29 10:29:22 -0700373 void **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100375 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
377 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100378 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 /* This is the X/Open sanctioned signal stack switching. */
381 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100382 if (sas_ss_flags(sp) == 0)
383 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 }
385
386 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800387 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100389 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100390 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700392 if (used_math()) {
393 sp = sp - sig_xstate_ia32_size;
394 *fpstate = (struct _fpstate_ia32 *) sp;
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800395 if (save_i387_xstate_ia32(*fpstate) < 0)
396 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700397 }
398
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100399 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200400 /* Align the stack pointer according to the i386 ABI,
401 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100402 sp = ((sp + 4) & -16ul) - 4;
403 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404}
405
Roland McGrath0928d6e2005-06-23 00:08:37 -0700406int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100407 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800409 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100410 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700412 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100414 /* copy_to_user optimizes that into a single 8 byte store */
415 static const struct {
416 u16 poplmovl;
417 u32 val;
418 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100419 } __attribute__((packed)) code = {
420 0xb858, /* popl %eax ; movl $...,%eax */
421 __NR_ia32_sigreturn,
422 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100423 };
424
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700425 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700428 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700430 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700431 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700433 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700434 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700437 if (__copy_to_user(frame->extramask, &set->sig[1],
438 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700439 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
Roland McGrathaf65d642008-01-30 13:30:43 +0100442 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100443 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100444 } else {
445 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700446 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100447 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
448 sigreturn);
449 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100450 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100451 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100452
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800453 put_user_try {
454 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
455
456 /*
457 * These are actually not used anymore, but left because some
458 * gdb versions depend on them as a marker.
459 */
460 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
461 } put_user_catch(err);
462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700464 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100467 regs->sp = (unsigned long) frame;
468 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Andi Kleen536e3ee2006-09-26 10:52:41 +0200470 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100471 regs->ax = sig;
472 regs->dx = 0;
473 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200474
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700475 loadsegment(ds, __USER32_DS);
476 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100478 regs->cs = __USER32_CS;
479 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
Andi Kleen1d001df2006-09-26 10:52:26 +0200481 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482}
483
Roland McGrath0928d6e2005-06-23 00:08:37 -0700484int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100485 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800487 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100488 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700490 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100492 /* __copy_to_user optimizes that into a single 8 byte store */
493 static const struct {
494 u8 movl;
495 u32 val;
496 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800497 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100498 } __attribute__((packed)) code = {
499 0xb8,
500 __NR_ia32_rt_sigreturn,
501 0x80cd,
502 0,
503 };
504
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700505 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700508 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800510 put_user_try {
511 put_user_ex(sig, &frame->sig);
512 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
513 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
514 err |= copy_siginfo_to_user32(&frame->info, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800516 /* Create the ucontext. */
517 if (cpu_has_xsave)
518 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
519 else
520 put_user_ex(0, &frame->uc.uc_flags);
521 put_user_ex(0, &frame->uc.uc_link);
522 put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
523 put_user_ex(sas_ss_flags(regs->sp),
524 &frame->uc.uc_stack.ss_flags);
525 put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
526 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
527 regs, set->sig[0]);
528 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800530 if (ka->sa.sa_flags & SA_RESTORER)
531 restorer = ka->sa.sa_restorer;
532 else
533 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
534 rt_sigreturn);
535 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800537 /*
538 * Not actually used anymore, but left because some gdb
539 * versions need it.
540 */
541 put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
542 } put_user_catch(err);
543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700545 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
547 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100548 regs->sp = (unsigned long) frame;
549 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500551 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100552 regs->ax = sig;
553 regs->dx = (unsigned long) &frame->info;
554 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500555
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700556 loadsegment(ds, __USER32_DS);
557 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100558
559 regs->cs = __USER32_CS;
560 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Andi Kleen1d001df2006-09-26 10:52:26 +0200562 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563}