blob: b0460cd7de5a9ce024cae70085bc313753807e5a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/x86_64/ia32/ia32_signal.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
7 * 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
8 * 2000-12-* x86-64 compatibility mode signal handling by Andi Kleen
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10
11#include <linux/sched.h>
12#include <linux/mm.h>
13#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/errno.h>
16#include <linux/wait.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/unistd.h>
18#include <linux/stddef.h>
19#include <linux/personality.h>
20#include <linux/compat.h>
Andi Kleen9fbbd4d2007-02-13 13:26:26 +010021#include <linux/binfmts.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <asm/ucontext.h>
23#include <asm/uaccess.h>
24#include <asm/i387.h>
Linus Torvalds1361b832012-02-21 13:19:22 -080025#include <asm/fpu-internal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/ptrace.h>
27#include <asm/ia32_unistd.h>
28#include <asm/user32.h>
29#include <asm/sigcontext32.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <asm/proto.h>
Roland McGrathaf65d642008-01-30 13:30:43 +010031#include <asm/vdso.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080032#include <asm/sigframe.h>
H. Peter Anvinf28f0c22012-02-19 07:38:43 -080033#include <asm/sighandling.h>
Jaswinder Singh Rajput2f06de02008-12-27 21:37:10 +053034#include <asm/sys_ia32.h>
H. Peter Anvin49b8c692012-09-21 17:18:44 -070035#include <asm/smap.h>
Hiroshi Shimamotod98f9d82008-12-17 18:52:45 -080036
H. Peter Anvinf28f0c22012-02-19 07:38:43 -080037#define FIX_EFLAGS __FIX_EFLAGS
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
40{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080041 int err = 0;
Suresh Siddha0b91f452012-06-14 18:07:15 -070042 bool ia32 = test_thread_flag(TIF_IA32);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010043
44 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 return -EFAULT;
46
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080047 put_user_try {
48 /* If you change siginfo_t structure, please make sure that
49 this code is fixed accordingly.
50 It should never copy any pad contained in the structure
51 to avoid security leaks, but must copy the generic
52 3 ints plus the relevant union member. */
53 put_user_ex(from->si_signo, &to->si_signo);
54 put_user_ex(from->si_errno, &to->si_errno);
55 put_user_ex((short)from->si_code, &to->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080057 if (from->si_code < 0) {
58 put_user_ex(from->si_pid, &to->si_pid);
59 put_user_ex(from->si_uid, &to->si_uid);
60 put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
61 } else {
62 /*
63 * First 32bits of unions are always present:
64 * si_pid === si_band === si_tid === si_addr(LS half)
65 */
66 put_user_ex(from->_sifields._pad[0],
67 &to->_sifields._pad[0]);
68 switch (from->si_code >> 16) {
69 case __SI_FAULT >> 16:
70 break;
Will Drewrya0727e82012-04-12 16:48:00 -050071 case __SI_SYS >> 16:
72 put_user_ex(from->si_syscall, &to->si_syscall);
73 put_user_ex(from->si_arch, &to->si_arch);
74 break;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080075 case __SI_CHLD >> 16:
H. Peter Anvine7084fd2012-03-05 13:40:24 -080076 if (ia32) {
77 put_user_ex(from->si_utime, &to->si_utime);
78 put_user_ex(from->si_stime, &to->si_stime);
79 } else {
80 put_user_ex(from->si_utime, &to->_sifields._sigchld_x32._utime);
81 put_user_ex(from->si_stime, &to->_sifields._sigchld_x32._stime);
82 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080083 put_user_ex(from->si_status, &to->si_status);
84 /* FALL THROUGH */
85 default:
86 case __SI_KILL >> 16:
87 put_user_ex(from->si_uid, &to->si_uid);
88 break;
89 case __SI_POLL >> 16:
90 put_user_ex(from->si_fd, &to->si_fd);
91 break;
92 case __SI_TIMER >> 16:
93 put_user_ex(from->si_overrun, &to->si_overrun);
94 put_user_ex(ptr_to_compat(from->si_ptr),
95 &to->si_ptr);
96 break;
97 /* This is not generated by the kernel as of now. */
98 case __SI_RT >> 16:
99 case __SI_MESGQ >> 16:
100 put_user_ex(from->si_uid, &to->si_uid);
101 put_user_ex(from->si_int, &to->si_int);
102 break;
103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 }
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800105 } put_user_catch(err);
106
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 return err;
108}
109
110int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
111{
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800112 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 u32 ptr32;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100114
115 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 return -EFAULT;
117
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800118 get_user_try {
119 get_user_ex(to->si_signo, &from->si_signo);
120 get_user_ex(to->si_errno, &from->si_errno);
121 get_user_ex(to->si_code, &from->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800123 get_user_ex(to->si_pid, &from->si_pid);
124 get_user_ex(to->si_uid, &from->si_uid);
125 get_user_ex(ptr32, &from->si_ptr);
126 to->si_ptr = compat_ptr(ptr32);
127 } get_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
129 return err;
130}
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132/*
133 * Do a signal return; undo the signal stack.
134 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800135#define loadsegment_gs(v) load_gs_index(v)
136#define loadsegment_fs(v) loadsegment(fs, v)
137#define loadsegment_ds(v) loadsegment(ds, v)
138#define loadsegment_es(v) loadsegment(es, v)
139
140#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
141#define set_user_seg(seg, v) loadsegment_##seg(v)
142
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800143#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800144 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145}
146
Hiroshi Shimamoto8801ead42009-02-20 19:00:13 -0800147#define GET_SEG(seg) ({ \
148 unsigned short tmp; \
149 get_user_ex(tmp, &sc->seg); \
150 tmp; \
151})
152
153#define COPY_SEG_CPL3(seg) do { \
154 regs->seg = GET_SEG(seg) | 3; \
155} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800156
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800157#define RELOAD_SEG(seg) { \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800158 unsigned int pre = GET_SEG(seg); \
159 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800160 pre |= 3; \
161 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800162 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800163}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100165static int ia32_restore_sigcontext(struct pt_regs *regs,
166 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800167 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100168{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800169 unsigned int tmpflags, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700170 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100171 u32 tmp;
172
173 /* Always make any pending restarted system calls return -EINTR */
174 current_thread_info()->restart_block.fn = do_no_restart_syscall;
175
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800176 get_user_try {
177 /*
178 * Reload fs and gs if they have changed in the signal
179 * handler. This does not handle long fs/gs base changes in
180 * the handler, but does not clobber them at least in the
181 * normal case.
182 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800183 RELOAD_SEG(gs);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800184 RELOAD_SEG(fs);
185 RELOAD_SEG(ds);
186 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800188 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
189 COPY(dx); COPY(cx); COPY(ip);
190 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800192 COPY_SEG_CPL3(cs);
193 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800195 get_user_ex(tmpflags, &sc->flags);
196 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
197 /* disable syscall checks */
198 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100199
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800200 get_user_ex(tmp, &sc->fpstate);
201 buf = compat_ptr(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800203 get_user_ex(*pax, &sc->ax);
204 } get_user_catch(err);
205
H. Peter Anvin49b8c692012-09-21 17:18:44 -0700206 err |= restore_xstate_sig(buf, 1);
H. Peter Anvin5e883532012-09-21 12:43:15 -0700207
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209}
210
Al Viro3fe26fa2012-11-12 14:32:42 -0500211asmlinkage long sys32_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212{
Al Viro3fe26fa2012-11-12 14:32:42 -0500213 struct pt_regs *regs = current_pt_regs();
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800214 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100216 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
218 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
219 goto badframe;
220 if (__get_user(set.sig[0], &frame->sc.oldmask)
221 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100222 && __copy_from_user((((char *) &set.sig) + 4),
223 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 sizeof(frame->extramask))))
225 goto badframe;
226
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200227 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100228
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100229 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100231 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233badframe:
234 signal_fault(regs, frame, "32bit sigreturn");
235 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100236}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Al Viro3fe26fa2012-11-12 14:32:42 -0500238asmlinkage long sys32_rt_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239{
Al Viro3fe26fa2012-11-12 14:32:42 -0500240 struct pt_regs *regs = current_pt_regs();
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800241 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100243 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800245 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
247 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
248 goto badframe;
249 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
250 goto badframe;
251
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200252 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100253
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100254 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 goto badframe;
256
Al Viro90268432012-12-14 14:47:53 -0500257 if (compat_restore_altstack(&frame->uc.uc_stack))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 goto badframe;
259
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100260 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100263 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100265}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267/*
268 * Set up a signal frame.
269 */
270
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100271static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700272 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100273 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800275 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800277 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800278 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
279 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
280 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
281 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800283 put_user_ex(regs->di, &sc->di);
284 put_user_ex(regs->si, &sc->si);
285 put_user_ex(regs->bp, &sc->bp);
286 put_user_ex(regs->sp, &sc->sp);
287 put_user_ex(regs->bx, &sc->bx);
288 put_user_ex(regs->dx, &sc->dx);
289 put_user_ex(regs->cx, &sc->cx);
290 put_user_ex(regs->ax, &sc->ax);
Srikar Dronamraju51e7dc72012-03-12 14:55:55 +0530291 put_user_ex(current->thread.trap_nr, &sc->trapno);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800292 put_user_ex(current->thread.error_code, &sc->err);
293 put_user_ex(regs->ip, &sc->ip);
294 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
295 put_user_ex(regs->flags, &sc->flags);
296 put_user_ex(regs->sp, &sc->sp_at_signal);
297 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800299 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800301 /* non-iBCS2 extensions.. */
302 put_user_ex(mask, &sc->oldmask);
303 put_user_ex(current->thread.cr2, &sc->cr2);
304 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306 return err;
307}
308
309/*
310 * Determine which stack to use..
311 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100312static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700313 size_t frame_size,
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200314 void __user **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100316 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100319 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321 /* This is the X/Open sanctioned signal stack switching. */
322 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100323 if (sas_ss_flags(sp) == 0)
324 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 }
326
327 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800328 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100330 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100331 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700333 if (used_math()) {
Suresh Siddha72a671c2012-07-24 16:05:29 -0700334 unsigned long fx_aligned, math_size;
335
336 sp = alloc_mathframe(sp, 1, &fx_aligned, &math_size);
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200337 *fpstate = (struct _fpstate_ia32 __user *) sp;
Suresh Siddha72a671c2012-07-24 16:05:29 -0700338 if (save_xstate_sig(*fpstate, (void __user *)fx_aligned,
339 math_size) < 0)
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800340 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700341 }
342
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100343 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200344 /* Align the stack pointer according to the i386 ABI,
345 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100346 sp = ((sp + 4) & -16ul) - 4;
347 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348}
349
Roland McGrath0928d6e2005-06-23 00:08:37 -0700350int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100351 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800353 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100354 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700356 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100358 /* copy_to_user optimizes that into a single 8 byte store */
359 static const struct {
360 u16 poplmovl;
361 u32 val;
362 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100363 } __attribute__((packed)) code = {
364 0xb858, /* popl %eax ; movl $...,%eax */
365 __NR_ia32_sigreturn,
366 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100367 };
368
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700369 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700372 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700374 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700375 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700377 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700378 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700381 if (__copy_to_user(frame->extramask, &set->sig[1],
382 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700383 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Roland McGrathaf65d642008-01-30 13:30:43 +0100386 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100387 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100388 } else {
389 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700390 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100391 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
392 sigreturn);
393 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100394 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100395 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100396
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800397 put_user_try {
398 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
399
400 /*
401 * These are actually not used anymore, but left because some
402 * gdb versions depend on them as a marker.
403 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200404 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800405 } put_user_catch(err);
406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700408 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
410 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100411 regs->sp = (unsigned long) frame;
412 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Andi Kleen536e3ee2006-09-26 10:52:41 +0200414 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100415 regs->ax = sig;
416 regs->dx = 0;
417 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200418
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700419 loadsegment(ds, __USER32_DS);
420 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100422 regs->cs = __USER32_CS;
423 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
Andi Kleen1d001df2006-09-26 10:52:26 +0200425 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426}
427
Roland McGrath0928d6e2005-06-23 00:08:37 -0700428int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100429 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800431 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100432 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700434 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100436 /* __copy_to_user optimizes that into a single 8 byte store */
437 static const struct {
438 u8 movl;
439 u32 val;
440 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800441 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100442 } __attribute__((packed)) code = {
443 0xb8,
444 __NR_ia32_rt_sigreturn,
445 0x80cd,
446 0,
447 };
448
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700449 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
451 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700452 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800454 put_user_try {
455 put_user_ex(sig, &frame->sig);
456 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
457 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800459 /* Create the ucontext. */
460 if (cpu_has_xsave)
461 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
462 else
463 put_user_ex(0, &frame->uc.uc_flags);
464 put_user_ex(0, &frame->uc.uc_link);
Al Viroc40702c2012-11-20 14:24:26 -0500465 err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800467 if (ka->sa.sa_flags & SA_RESTORER)
468 restorer = ka->sa.sa_restorer;
469 else
470 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
471 rt_sigreturn);
472 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800474 /*
475 * Not actually used anymore, but left because some gdb
476 * versions need it.
477 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200478 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800479 } put_user_catch(err);
480
H. Peter Anvin5e883532012-09-21 12:43:15 -0700481 err |= copy_siginfo_to_user32(&frame->info, info);
482 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
483 regs, set->sig[0]);
484 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700487 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
489 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100490 regs->sp = (unsigned long) frame;
491 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500493 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100494 regs->ax = sig;
495 regs->dx = (unsigned long) &frame->info;
496 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500497
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700498 loadsegment(ds, __USER32_DS);
499 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100500
501 regs->cs = __USER32_CS;
502 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
Andi Kleen1d001df2006-09-26 10:52:26 +0200504 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505}