blob: a866411a2fccd930cda4f29f5eef941bbb46b87e [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
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100132asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200134 sigset_t blocked;
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200135 siginitset(&blocked, mask);
Al Viro68f3f162012-05-21 21:42:32 -0400136 return sigsuspend(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137}
138
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139/*
140 * Do a signal return; undo the signal stack.
141 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800142#define loadsegment_gs(v) load_gs_index(v)
143#define loadsegment_fs(v) loadsegment(fs, v)
144#define loadsegment_ds(v) loadsegment(ds, v)
145#define loadsegment_es(v) loadsegment(es, v)
146
147#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
148#define set_user_seg(seg, v) loadsegment_##seg(v)
149
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800150#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800151 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152}
153
Hiroshi Shimamoto8801ead2009-02-20 19:00:13 -0800154#define GET_SEG(seg) ({ \
155 unsigned short tmp; \
156 get_user_ex(tmp, &sc->seg); \
157 tmp; \
158})
159
160#define COPY_SEG_CPL3(seg) do { \
161 regs->seg = GET_SEG(seg) | 3; \
162} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800163
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800164#define RELOAD_SEG(seg) { \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800165 unsigned int pre = GET_SEG(seg); \
166 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800167 pre |= 3; \
168 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800169 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -0800170}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100172static int ia32_restore_sigcontext(struct pt_regs *regs,
173 struct sigcontext_ia32 __user *sc,
Hiroshi Shimamoto047ce932008-11-17 15:48:27 -0800174 unsigned int *pax)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100175{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800176 unsigned int tmpflags, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700177 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100178 u32 tmp;
179
180 /* Always make any pending restarted system calls return -EINTR */
181 current_thread_info()->restart_block.fn = do_no_restart_syscall;
182
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800183 get_user_try {
184 /*
185 * Reload fs and gs if they have changed in the signal
186 * handler. This does not handle long fs/gs base changes in
187 * the handler, but does not clobber them at least in the
188 * normal case.
189 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800190 RELOAD_SEG(gs);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800191 RELOAD_SEG(fs);
192 RELOAD_SEG(ds);
193 RELOAD_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800195 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
196 COPY(dx); COPY(cx); COPY(ip);
197 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800199 COPY_SEG_CPL3(cs);
200 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800202 get_user_ex(tmpflags, &sc->flags);
203 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
204 /* disable syscall checks */
205 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100206
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800207 get_user_ex(tmp, &sc->fpstate);
208 buf = compat_ptr(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800210 get_user_ex(*pax, &sc->ax);
211 } get_user_catch(err);
212
H. Peter Anvin49b8c692012-09-21 17:18:44 -0700213 err |= restore_xstate_sig(buf, 1);
H. Peter Anvin5e883532012-09-21 12:43:15 -0700214
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216}
217
218asmlinkage long sys32_sigreturn(struct pt_regs *regs)
219{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800220 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100222 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
224 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
225 goto badframe;
226 if (__get_user(set.sig[0], &frame->sc.oldmask)
227 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100228 && __copy_from_user((((char *) &set.sig) + 4),
229 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 sizeof(frame->extramask))))
231 goto badframe;
232
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200233 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100234
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100235 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100237 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239badframe:
240 signal_fault(regs, frame, "32bit sigreturn");
241 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100242}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
245{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800246 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100248 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800250 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
252 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
253 goto badframe;
254 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
255 goto badframe;
256
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200257 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100258
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100259 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 goto badframe;
261
Al Viro90268432012-12-14 14:47:53 -0500262 if (compat_restore_altstack(&frame->uc.uc_stack))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 goto badframe;
264
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100265 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100268 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100270}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
272/*
273 * Set up a signal frame.
274 */
275
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100276static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700277 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100278 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800280 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800282 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800283 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
284 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
285 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
286 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800288 put_user_ex(regs->di, &sc->di);
289 put_user_ex(regs->si, &sc->si);
290 put_user_ex(regs->bp, &sc->bp);
291 put_user_ex(regs->sp, &sc->sp);
292 put_user_ex(regs->bx, &sc->bx);
293 put_user_ex(regs->dx, &sc->dx);
294 put_user_ex(regs->cx, &sc->cx);
295 put_user_ex(regs->ax, &sc->ax);
Srikar Dronamraju51e7dc72012-03-12 14:55:55 +0530296 put_user_ex(current->thread.trap_nr, &sc->trapno);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800297 put_user_ex(current->thread.error_code, &sc->err);
298 put_user_ex(regs->ip, &sc->ip);
299 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
300 put_user_ex(regs->flags, &sc->flags);
301 put_user_ex(regs->sp, &sc->sp_at_signal);
302 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800304 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800306 /* non-iBCS2 extensions.. */
307 put_user_ex(mask, &sc->oldmask);
308 put_user_ex(current->thread.cr2, &sc->cr2);
309 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 return err;
312}
313
314/*
315 * Determine which stack to use..
316 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100317static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700318 size_t frame_size,
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200319 void __user **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100321 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100324 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 /* This is the X/Open sanctioned signal stack switching. */
327 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100328 if (sas_ss_flags(sp) == 0)
329 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 }
331
332 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800333 else if ((regs->ss & 0xffff) != __USER32_DS &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100335 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100336 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700338 if (used_math()) {
Suresh Siddha72a671c2012-07-24 16:05:29 -0700339 unsigned long fx_aligned, math_size;
340
341 sp = alloc_mathframe(sp, 1, &fx_aligned, &math_size);
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200342 *fpstate = (struct _fpstate_ia32 __user *) sp;
Suresh Siddha72a671c2012-07-24 16:05:29 -0700343 if (save_xstate_sig(*fpstate, (void __user *)fx_aligned,
344 math_size) < 0)
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800345 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700346 }
347
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100348 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200349 /* Align the stack pointer according to the i386 ABI,
350 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100351 sp = ((sp + 4) & -16ul) - 4;
352 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353}
354
Roland McGrath0928d6e2005-06-23 00:08:37 -0700355int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100356 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800358 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100359 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700361 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100363 /* copy_to_user optimizes that into a single 8 byte store */
364 static const struct {
365 u16 poplmovl;
366 u32 val;
367 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100368 } __attribute__((packed)) code = {
369 0xb858, /* popl %eax ; movl $...,%eax */
370 __NR_ia32_sigreturn,
371 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100372 };
373
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700374 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700377 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700379 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700380 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700382 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700383 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700386 if (__copy_to_user(frame->extramask, &set->sig[1],
387 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700388 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Roland McGrathaf65d642008-01-30 13:30:43 +0100391 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100392 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100393 } else {
394 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700395 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100396 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
397 sigreturn);
398 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100399 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100400 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100401
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800402 put_user_try {
403 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
404
405 /*
406 * These are actually not used anymore, but left because some
407 * gdb versions depend on them as a marker.
408 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200409 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800410 } put_user_catch(err);
411
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700413 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100416 regs->sp = (unsigned long) frame;
417 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Andi Kleen536e3ee2006-09-26 10:52:41 +0200419 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100420 regs->ax = sig;
421 regs->dx = 0;
422 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200423
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700424 loadsegment(ds, __USER32_DS);
425 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100427 regs->cs = __USER32_CS;
428 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
Andi Kleen1d001df2006-09-26 10:52:26 +0200430 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431}
432
Roland McGrath0928d6e2005-06-23 00:08:37 -0700433int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100434 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800436 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100437 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700439 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100441 /* __copy_to_user optimizes that into a single 8 byte store */
442 static const struct {
443 u8 movl;
444 u32 val;
445 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800446 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100447 } __attribute__((packed)) code = {
448 0xb8,
449 __NR_ia32_rt_sigreturn,
450 0x80cd,
451 0,
452 };
453
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700454 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700457 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800459 put_user_try {
460 put_user_ex(sig, &frame->sig);
461 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
462 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800464 /* Create the ucontext. */
465 if (cpu_has_xsave)
466 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
467 else
468 put_user_ex(0, &frame->uc.uc_flags);
469 put_user_ex(0, &frame->uc.uc_link);
470 put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
471 put_user_ex(sas_ss_flags(regs->sp),
472 &frame->uc.uc_stack.ss_flags);
473 put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800475 if (ka->sa.sa_flags & SA_RESTORER)
476 restorer = ka->sa.sa_restorer;
477 else
478 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
479 rt_sigreturn);
480 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800482 /*
483 * Not actually used anymore, but left because some gdb
484 * versions need it.
485 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200486 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800487 } put_user_catch(err);
488
H. Peter Anvin5e883532012-09-21 12:43:15 -0700489 err |= copy_siginfo_to_user32(&frame->info, info);
490 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
491 regs, set->sig[0]);
492 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
493
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700495 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
497 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100498 regs->sp = (unsigned long) frame;
499 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500501 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100502 regs->ax = sig;
503 regs->dx = (unsigned long) &frame->info;
504 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500505
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700506 loadsegment(ds, __USER32_DS);
507 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100508
509 regs->cs = __USER32_CS;
510 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Andi Kleen1d001df2006-09-26 10:52:26 +0200512 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513}