blob: 9978ea4382bf63cf5871268cf873f418e488f721 [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>
Ingo Molnar78f7f1e2015-04-24 02:54:44 +020024#include <asm/fpu/internal.h>
Ingo Molnarfcbc99c2015-04-30 08:45:02 +020025#include <asm/fpu/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/ptrace.h>
27#include <asm/ia32_unistd.h>
28#include <asm/user32.h>
Ingo Molnardecb4c42015-09-05 09:32:43 +020029#include <uapi/asm/sigcontext.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
Linus Torvalds1da177e2005-04-16 15:20:36 -070037/*
38 * Do a signal return; undo the signal stack.
39 */
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -080040#define loadsegment_gs(v) load_gs_index(v)
41#define loadsegment_fs(v) loadsegment(fs, v)
42#define loadsegment_ds(v) loadsegment(ds, v)
43#define loadsegment_es(v) loadsegment(es, v)
44
45#define get_user_seg(seg) ({ unsigned int v; savesegment(seg, v); v; })
46#define set_user_seg(seg, v) loadsegment_##seg(v)
47
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -080048#define COPY(x) { \
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080049 get_user_ex(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -070050}
51
Hiroshi Shimamoto8801ead2009-02-20 19:00:13 -080052#define GET_SEG(seg) ({ \
53 unsigned short tmp; \
54 get_user_ex(tmp, &sc->seg); \
55 tmp; \
56})
57
58#define COPY_SEG_CPL3(seg) do { \
59 regs->seg = GET_SEG(seg) | 3; \
60} while (0)
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -080061
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -080062#define RELOAD_SEG(seg) { \
Peter Zijlstrade905252019-02-25 12:56:35 +010063 unsigned int pre = (seg) | 3; \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -080064 unsigned int cur = get_user_seg(seg); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -080065 if (pre != cur) \
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -080066 set_user_seg(seg, pre); \
Hiroshi Shimamoto8c6e5ce2008-11-17 15:47:48 -080067}
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010069static int ia32_restore_sigcontext(struct pt_regs *regs,
Ingo Molnar8fcb3462015-09-05 09:32:41 +020070 struct sigcontext_32 __user *sc)
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010071{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -080072 unsigned int tmpflags, err = 0;
Peter Zijlstrade905252019-02-25 12:56:35 +010073 u16 gs, fs, es, ds;
Suresh Siddhaab513702008-07-29 10:29:22 -070074 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010075 u32 tmp;
76
77 /* Always make any pending restarted system calls return -EINTR */
Andy Lutomirskif56141e2015-02-12 15:01:14 -080078 current->restart_block.fn = do_no_restart_syscall;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010079
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080080 get_user_try {
Peter Zijlstrade905252019-02-25 12:56:35 +010081 gs = GET_SEG(gs);
82 fs = GET_SEG(fs);
83 ds = GET_SEG(ds);
84 es = GET_SEG(es);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080086 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
Brian Gerst6a3713f2015-04-04 08:58:23 -040087 COPY(dx); COPY(cx); COPY(ip); COPY(ax);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080088 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080090 COPY_SEG_CPL3(cs);
91 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080093 get_user_ex(tmpflags, &sc->flags);
94 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
95 /* disable syscall checks */
96 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010097
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -080098 get_user_ex(tmp, &sc->fpstate);
99 buf = compat_ptr(tmp);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800100 } get_user_catch(err);
101
Peter Zijlstrade905252019-02-25 12:56:35 +0100102 /*
103 * Reload fs and gs if they have changed in the signal
104 * handler. This does not handle long fs/gs base changes in
105 * the handler, but does not clobber them at least in the
106 * normal case.
107 */
108 RELOAD_SEG(gs);
109 RELOAD_SEG(fs);
110 RELOAD_SEG(ds);
111 RELOAD_SEG(es);
112
Ingo Molnar9dfe99b2015-04-29 20:55:19 +0200113 err |= fpu__restore_sig(buf, 1);
H. Peter Anvin5e883532012-09-21 12:43:15 -0700114
Brian Gerst1daeaa32015-03-21 18:54:21 -0400115 force_iret();
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118}
119
Al Viro3fe26fa2012-11-12 14:32:42 -0500120asmlinkage long sys32_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
Al Viro3fe26fa2012-11-12 14:32:42 -0500122 struct pt_regs *regs = current_pt_regs();
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800123 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 sigset_t set;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
127 goto badframe;
128 if (__get_user(set.sig[0], &frame->sc.oldmask)
129 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100130 && __copy_from_user((((char *) &set.sig) + 4),
131 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 sizeof(frame->extramask))))
133 goto badframe;
134
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200135 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100136
Brian Gerst6a3713f2015-04-04 08:58:23 -0400137 if (ia32_restore_sigcontext(regs, &frame->sc))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 goto badframe;
Brian Gerst6a3713f2015-04-04 08:58:23 -0400139 return regs->ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141badframe:
142 signal_fault(regs, frame, "32bit sigreturn");
143 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100144}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Al Viro3fe26fa2012-11-12 14:32:42 -0500146asmlinkage long sys32_rt_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
Al Viro3fe26fa2012-11-12 14:32:42 -0500148 struct pt_regs *regs = current_pt_regs();
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800149 struct rt_sigframe_ia32 __user *frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 sigset_t set;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800152 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
154 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
155 goto badframe;
156 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
157 goto badframe;
158
Oleg Nesterov905f29e2011-07-10 21:27:24 +0200159 set_current_blocked(&set);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100160
Brian Gerst6a3713f2015-04-04 08:58:23 -0400161 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 goto badframe;
163
Al Viro90268432012-12-14 14:47:53 -0500164 if (compat_restore_altstack(&frame->uc.uc_stack))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 goto badframe;
166
Brian Gerst6a3713f2015-04-04 08:58:23 -0400167 return regs->ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100170 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100172}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
174/*
175 * Set up a signal frame.
176 */
177
Ingo Molnar8fcb3462015-09-05 09:32:41 +0200178static int ia32_setup_sigcontext(struct sigcontext_32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700179 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100180 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181{
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800182 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800184 put_user_try {
Hiroshi Shimamotoa967bb32009-02-20 19:00:54 -0800185 put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
186 put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
187 put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
188 put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800190 put_user_ex(regs->di, &sc->di);
191 put_user_ex(regs->si, &sc->si);
192 put_user_ex(regs->bp, &sc->bp);
193 put_user_ex(regs->sp, &sc->sp);
194 put_user_ex(regs->bx, &sc->bx);
195 put_user_ex(regs->dx, &sc->dx);
196 put_user_ex(regs->cx, &sc->cx);
197 put_user_ex(regs->ax, &sc->ax);
Srikar Dronamraju51e7dc72012-03-12 14:55:55 +0530198 put_user_ex(current->thread.trap_nr, &sc->trapno);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800199 put_user_ex(current->thread.error_code, &sc->err);
200 put_user_ex(regs->ip, &sc->ip);
201 put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
202 put_user_ex(regs->flags, &sc->flags);
203 put_user_ex(regs->sp, &sc->sp_at_signal);
204 put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800206 put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800208 /* non-iBCS2 extensions.. */
209 put_user_ex(mask, &sc->oldmask);
210 put_user_ex(current->thread.cr2, &sc->cr2);
211 } put_user_catch(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213 return err;
214}
215
216/*
217 * Determine which stack to use..
218 */
Al Viro235b8022012-11-09 23:51:47 -0500219static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700220 size_t frame_size,
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200221 void __user **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222{
Ingo Molnarc5bedc62015-04-23 12:49:20 +0200223 struct fpu *fpu = &current->thread.fpu;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100224 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100227 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229 /* This is the X/Open sanctioned signal stack switching. */
Al Viro235b8022012-11-09 23:51:47 -0500230 if (ksig->ka.sa.sa_flags & SA_ONSTACK)
231 sp = sigsp(sp, ksig);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 /* This is the legacy signal stack switching. */
Hiroshi Shimamoto8bee3f02008-12-16 14:04:43 -0800233 else if ((regs->ss & 0xffff) != __USER32_DS &&
Al Viro235b8022012-11-09 23:51:47 -0500234 !(ksig->ka.sa.sa_flags & SA_RESTORER) &&
235 ksig->ka.sa.sa_restorer)
236 sp = (unsigned long) ksig->ka.sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Ingo Molnarc5bedc62015-04-23 12:49:20 +0200238 if (fpu->fpstate_active) {
Suresh Siddha72a671c2012-07-24 16:05:29 -0700239 unsigned long fx_aligned, math_size;
240
Ingo Molnar82c0e452015-04-29 21:09:18 +0200241 sp = fpu__alloc_mathframe(sp, 1, &fx_aligned, &math_size);
Ingo Molnar86e9fc32015-09-05 09:32:36 +0200242 *fpstate = (struct _fpstate_32 __user *) sp;
Ingo Molnarc8e14042015-04-28 11:35:20 +0200243 if (copy_fpstate_to_sigframe(*fpstate, (void __user *)fx_aligned,
Suresh Siddha72a671c2012-07-24 16:05:29 -0700244 math_size) < 0)
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800245 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700246 }
247
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100248 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200249 /* Align the stack pointer according to the i386 ABI,
250 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100251 sp = ((sp + 4) & -16ul) - 4;
252 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253}
254
Al Viro235b8022012-11-09 23:51:47 -0500255int ia32_setup_frame(int sig, struct ksignal *ksig,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100256 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800258 struct sigframe_ia32 __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100259 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700261 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100263 /* copy_to_user optimizes that into a single 8 byte store */
264 static const struct {
265 u16 poplmovl;
266 u32 val;
267 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100268 } __attribute__((packed)) code = {
269 0xb858, /* popl %eax ; movl $...,%eax */
270 __NR_ia32_sigreturn,
271 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100272 };
273
Al Viro235b8022012-11-09 23:51:47 -0500274 frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
276 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700277 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700279 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700280 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700282 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700283 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
285 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700286 if (__copy_to_user(frame->extramask, &set->sig[1],
287 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700288 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Al Viro235b8022012-11-09 23:51:47 -0500291 if (ksig->ka.sa.sa_flags & SA_RESTORER) {
292 restorer = ksig->ka.sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100293 } else {
294 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700295 if (current->mm->context.vdso)
Andy Lutomirski6f121e52014-05-05 12:19:34 -0700296 restorer = current->mm->context.vdso +
Andy Lutomirski0a6d1fa2015-10-05 17:47:56 -0700297 vdso_image_32.sym___kernel_sigreturn;
Roland McGrathaf65d642008-01-30 13:30:43 +0100298 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100299 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100300 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100301
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800302 put_user_try {
303 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
304
305 /*
306 * These are actually not used anymore, but left because some
307 * gdb versions depend on them as a marker.
308 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200309 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800310 } put_user_catch(err);
311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700313 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100316 regs->sp = (unsigned long) frame;
Al Viro235b8022012-11-09 23:51:47 -0500317 regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Andi Kleen536e3ee2006-09-26 10:52:41 +0200319 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100320 regs->ax = sig;
321 regs->dx = 0;
322 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200323
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700324 loadsegment(ds, __USER32_DS);
325 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100327 regs->cs = __USER32_CS;
328 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Andi Kleen1d001df2006-09-26 10:52:26 +0200330 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331}
332
Al Viro235b8022012-11-09 23:51:47 -0500333int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100334 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
Hiroshi Shimamoto3b0d29e2008-12-17 18:51:46 -0800336 struct rt_sigframe_ia32 __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100337 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700339 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100341 /* __copy_to_user optimizes that into a single 8 byte store */
342 static const struct {
343 u8 movl;
344 u32 val;
345 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800346 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100347 } __attribute__((packed)) code = {
348 0xb8,
349 __NR_ia32_rt_sigreturn,
350 0x80cd,
351 0,
352 };
353
Al Viro235b8022012-11-09 23:51:47 -0500354 frame = get_sigframe(ksig, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700357 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800359 put_user_try {
360 put_user_ex(sig, &frame->sig);
361 put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
362 put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800364 /* Create the ucontext. */
Borislav Petkovd366bf72016-04-04 22:25:02 +0200365 if (boot_cpu_has(X86_FEATURE_XSAVE))
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800366 put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
367 else
368 put_user_ex(0, &frame->uc.uc_flags);
369 put_user_ex(0, &frame->uc.uc_link);
Al Virobd1c149a2013-09-01 20:35:01 +0100370 compat_save_altstack_ex(&frame->uc.uc_stack, regs->sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Al Viro235b8022012-11-09 23:51:47 -0500372 if (ksig->ka.sa.sa_flags & SA_RESTORER)
373 restorer = ksig->ka.sa.sa_restorer;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800374 else
Andy Lutomirski6f121e52014-05-05 12:19:34 -0700375 restorer = current->mm->context.vdso +
Andy Lutomirski0a6d1fa2015-10-05 17:47:56 -0700376 vdso_image_32.sym___kernel_rt_sigreturn;
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800377 put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800379 /*
380 * Not actually used anymore, but left because some gdb
381 * versions need it.
382 */
Mathias Krause0ff8fef2012-09-02 23:31:42 +0200383 put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
Hiroshi Shimamoto3b4b7572009-01-23 15:50:38 -0800384 } put_user_catch(err);
385
Dmitry Safonov68463512016-09-05 16:33:08 +0300386 err |= __copy_siginfo_to_user32(&frame->info, &ksig->info, false);
H. Peter Anvin5e883532012-09-21 12:43:15 -0700387 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
388 regs, set->sig[0]);
389 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700392 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
394 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100395 regs->sp = (unsigned long) frame;
Al Viro235b8022012-11-09 23:51:47 -0500396 regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500398 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100399 regs->ax = sig;
400 regs->dx = (unsigned long) &frame->info;
401 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500402
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700403 loadsegment(ds, __USER32_DS);
404 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100405
406 regs->cs = __USER32_CS;
407 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Andi Kleen1d001df2006-09-26 10:52:26 +0200409 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410}