blob: fe44c314c9c0aa031291ee053d683c243613f6e1 [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>
27#include <asm/ia32.h>
28#include <asm/ptrace.h>
29#include <asm/ia32_unistd.h>
30#include <asm/user32.h>
31#include <asm/sigcontext32.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/proto.h>
Roland McGrathaf65d642008-01-30 13:30:43 +010033#include <asm/vdso.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35#define DEBUG_SIG 0
36
37#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
38
Hiroshi Shimamotofbdb7da2008-07-14 15:34:09 -070039#define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \
40 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
41 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
42 X86_EFLAGS_CF)
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
45void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
46
47int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
48{
49 int err;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010050
51 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 return -EFAULT;
53
54 /* If you change siginfo_t structure, please make sure that
55 this code is fixed accordingly.
56 It should never copy any pad contained in the structure
57 to avoid security leaks, but must copy the generic
58 3 ints plus the relevant union member. */
59 err = __put_user(from->si_signo, &to->si_signo);
60 err |= __put_user(from->si_errno, &to->si_errno);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010061 err |= __put_user((short)from->si_code, &to->si_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63 if (from->si_code < 0) {
64 err |= __put_user(from->si_pid, &to->si_pid);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010065 err |= __put_user(from->si_uid, &to->si_uid);
66 err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 } else {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010068 /*
69 * First 32bits of unions are always present:
70 * si_pid === si_band === si_tid === si_addr(LS half)
71 */
72 err |= __put_user(from->_sifields._pad[0],
73 &to->_sifields._pad[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 switch (from->si_code >> 16) {
75 case __SI_FAULT >> 16:
76 break;
77 case __SI_CHLD >> 16:
78 err |= __put_user(from->si_utime, &to->si_utime);
79 err |= __put_user(from->si_stime, &to->si_stime);
80 err |= __put_user(from->si_status, &to->si_status);
81 /* FALL THROUGH */
82 default:
83 case __SI_KILL >> 16:
84 err |= __put_user(from->si_uid, &to->si_uid);
85 break;
86 case __SI_POLL >> 16:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010087 err |= __put_user(from->si_fd, &to->si_fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 break;
89 case __SI_TIMER >> 16:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010090 err |= __put_user(from->si_overrun, &to->si_overrun);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 err |= __put_user(ptr_to_compat(from->si_ptr),
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010092 &to->si_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 break;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +010094 /* This is not generated by the kernel as of now. */
95 case __SI_RT >> 16:
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 case __SI_MESGQ >> 16:
97 err |= __put_user(from->si_uid, &to->si_uid);
98 err |= __put_user(from->si_int, &to->si_int);
99 break;
100 }
101 }
102 return err;
103}
104
105int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
106{
107 int err;
108 u32 ptr32;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100109
110 if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 return -EFAULT;
112
113 err = __get_user(to->si_signo, &from->si_signo);
114 err |= __get_user(to->si_errno, &from->si_errno);
115 err |= __get_user(to->si_code, &from->si_code);
116
117 err |= __get_user(to->si_pid, &from->si_pid);
118 err |= __get_user(to->si_uid, &from->si_uid);
119 err |= __get_user(ptr32, &from->si_ptr);
120 to->si_ptr = compat_ptr(ptr32);
121
122 return err;
123}
124
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100125asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 mask &= _BLOCKABLE;
128 spin_lock_irq(&current->sighand->siglock);
Andi Kleen1d001df2006-09-26 10:52:26 +0200129 current->saved_sigmask = current->blocked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 siginitset(&current->blocked, mask);
131 recalc_sigpending();
132 spin_unlock_irq(&current->sighand->siglock);
133
Andi Kleen1d001df2006-09-26 10:52:26 +0200134 current->state = TASK_INTERRUPTIBLE;
135 schedule();
Roland McGrath5a8da0e2008-04-30 00:53:10 -0700136 set_restore_sigmask();
Andi Kleen1d001df2006-09-26 10:52:26 +0200137 return -ERESTARTNOHAND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138}
139
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100140asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
141 stack_ia32_t __user *uoss_ptr,
142 struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143{
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100144 stack_t uss, uoss;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 int ret;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100146 mm_segment_t seg;
147
148 if (uss_ptr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 u32 ptr;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100150
151 memset(&uss, 0, sizeof(stack_t));
152 if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 __get_user(ptr, &uss_ptr->ss_sp) ||
154 __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
155 __get_user(uss.ss_size, &uss_ptr->ss_size))
156 return -EFAULT;
157 uss.ss_sp = compat_ptr(ptr);
158 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100159 seg = get_fs();
160 set_fs(KERNEL_DS);
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100161 ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100162 set_fs(seg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 if (ret >= 0 && uoss_ptr) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100164 if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
166 __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
167 __put_user(uoss.ss_size, &uoss_ptr->ss_size))
168 ret = -EFAULT;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100169 }
170 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171}
172
173/*
174 * Do a signal return; undo the signal stack.
175 */
176
177struct sigframe
178{
179 u32 pretcode;
180 int sig;
181 struct sigcontext_ia32 sc;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700182 struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 unsigned int extramask[_COMPAT_NSIG_WORDS-1];
184 char retcode[8];
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700185 /* fp state follows here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186};
187
188struct rt_sigframe
189{
190 u32 pretcode;
191 int sig;
192 u32 pinfo;
193 u32 puc;
194 compat_siginfo_t info;
195 struct ucontext_ia32 uc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 char retcode[8];
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700197 /* fp state follows here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198};
199
Hiroshi Shimamotob78a5b52008-11-17 15:44:50 -0800200#define COPY(x) { \
201 err |= __get_user(regs->x, &sc->x); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202}
203
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800204#define COPY_SEG_CPL3(seg) { \
205 unsigned short tmp; \
206 err |= __get_user(tmp, &sc->seg); \
207 regs->seg = tmp | 3; \
208}
209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210#define RELOAD_SEG(seg,mask) \
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100211 { unsigned int cur; \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 unsigned short pre; \
213 err |= __get_user(pre, &sc->seg); \
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700214 savesegment(seg, cur); \
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100215 pre |= mask; \
216 if (pre != cur) loadsegment(seg, pre); }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100218static int ia32_restore_sigcontext(struct pt_regs *regs,
219 struct sigcontext_ia32 __user *sc,
220 unsigned int *peax)
221{
222 unsigned int tmpflags, gs, oldgs, err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700223 void __user *buf;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100224 u32 tmp;
225
226 /* Always make any pending restarted system calls return -EINTR */
227 current_thread_info()->restart_block.fn = do_no_restart_syscall;
228
229#if DEBUG_SIG
230 printk(KERN_DEBUG "SIG restore_sigcontext: "
231 "sc=%p err(%x) eip(%x) cs(%x) flg(%x)\n",
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100232 sc, sc->err, sc->ip, sc->cs, sc->flags);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100233#endif
234
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 */
241 err |= __get_user(gs, &sc->gs);
242 gs |= 3;
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700243 savesegment(gs, oldgs);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100244 if (gs != oldgs)
245 load_gs_index(gs);
246
247 RELOAD_SEG(fs, 3);
248 RELOAD_SEG(ds, 3);
249 RELOAD_SEG(es, 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251 COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
252 COPY(dx); COPY(cx); COPY(ip);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100253 /* Don't touch extended registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Hiroshi Shimamotod71a68d2008-11-17 15:47:06 -0800255 COPY_SEG_CPL3(cs);
256 COPY_SEG_CPL3(ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
H. Peter Anvin742fa542008-01-30 13:30:56 +0100258 err |= __get_user(tmpflags, &sc->flags);
Hiroshi Shimamotofbdb7da2008-07-14 15:34:09 -0700259 regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100260 /* disable syscall checks */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100261 regs->orig_ax = -1;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100262
263 err |= __get_user(tmp, &sc->fpstate);
264 buf = compat_ptr(tmp);
Suresh Siddhaab513702008-07-29 10:29:22 -0700265 err |= restore_i387_xstate_ia32(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
H. Peter Anvin742fa542008-01-30 13:30:56 +0100267 err |= __get_user(tmp, &sc->ax);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100268 *peax = tmp;
269
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271}
272
273asmlinkage long sys32_sigreturn(struct pt_regs *regs)
274{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100275 struct sigframe __user *frame = (struct sigframe __user *)(regs->sp-8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100277 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
280 goto badframe;
281 if (__get_user(set.sig[0], &frame->sc.oldmask)
282 || (_COMPAT_NSIG_WORDS > 1
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100283 && __copy_from_user((((char *) &set.sig) + 4),
284 &frame->extramask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 sizeof(frame->extramask))))
286 goto badframe;
287
288 sigdelsetmask(&set, ~_BLOCKABLE);
289 spin_lock_irq(&current->sighand->siglock);
290 current->blocked = set;
291 recalc_sigpending();
292 spin_unlock_irq(&current->sighand->siglock);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100293
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100294 if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 goto badframe;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100296 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298badframe:
299 signal_fault(regs, frame, "32bit sigreturn");
300 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100301}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
304{
305 struct rt_sigframe __user *frame;
306 sigset_t set;
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100307 unsigned int ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 struct pt_regs tregs;
309
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100310 frame = (struct rt_sigframe __user *)(regs->sp - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
313 goto badframe;
314 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
315 goto badframe;
316
317 sigdelsetmask(&set, ~_BLOCKABLE);
318 spin_lock_irq(&current->sighand->siglock);
319 current->blocked = set;
320 recalc_sigpending();
321 spin_unlock_irq(&current->sighand->siglock);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100322
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100323 if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 goto badframe;
325
326 tregs = *regs;
327 if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
328 goto badframe;
329
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100330 return ax;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332badframe:
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100333 signal_fault(regs, frame, "32bit rt sigreturn");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 return 0;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100335}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
337/*
338 * Set up a signal frame.
339 */
340
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100341static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
Suresh Siddhaab513702008-07-29 10:29:22 -0700342 void __user *fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100343 struct pt_regs *regs, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
345 int tmp, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700347 savesegment(gs, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700349 savesegment(fs, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700351 savesegment(ds, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 err |= __put_user(tmp, (unsigned int __user *)&sc->ds);
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700353 savesegment(es, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 err |= __put_user(tmp, (unsigned int __user *)&sc->es);
355
Hiroshi Shimamotobff0aa42008-09-30 20:28:20 -0700356 err |= __put_user(regs->di, &sc->di);
357 err |= __put_user(regs->si, &sc->si);
358 err |= __put_user(regs->bp, &sc->bp);
359 err |= __put_user(regs->sp, &sc->sp);
360 err |= __put_user(regs->bx, &sc->bx);
361 err |= __put_user(regs->dx, &sc->dx);
362 err |= __put_user(regs->cx, &sc->cx);
363 err |= __put_user(regs->ax, &sc->ax);
364 err |= __put_user(regs->cs, &sc->cs);
365 err |= __put_user(regs->ss, &sc->ss);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 err |= __put_user(current->thread.trap_no, &sc->trapno);
367 err |= __put_user(current->thread.error_code, &sc->err);
Hiroshi Shimamotobff0aa42008-09-30 20:28:20 -0700368 err |= __put_user(regs->ip, &sc->ip);
369 err |= __put_user(regs->flags, &sc->flags);
370 err |= __put_user(regs->sp, &sc->sp_at_signal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800372 err |= __put_user(ptr_to_compat(fpstate), &sc->fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374 /* non-iBCS2 extensions.. */
375 err |= __put_user(mask, &sc->oldmask);
376 err |= __put_user(current->thread.cr2, &sc->cr2);
377
378 return err;
379}
380
381/*
382 * Determine which stack to use..
383 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100384static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700385 size_t frame_size,
Suresh Siddhaab513702008-07-29 10:29:22 -0700386 void **fpstate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387{
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100388 unsigned long sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
390 /* Default to using normal stack */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100391 sp = regs->sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
393 /* This is the X/Open sanctioned signal stack switching. */
394 if (ka->sa.sa_flags & SA_ONSTACK) {
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100395 if (sas_ss_flags(sp) == 0)
396 sp = current->sas_ss_sp + current->sas_ss_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 }
398
399 /* This is the legacy signal stack switching. */
400 else if ((regs->ss & 0xffff) != __USER_DS &&
401 !(ka->sa.sa_flags & SA_RESTORER) &&
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100402 ka->sa.sa_restorer)
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100403 sp = (unsigned long) ka->sa.sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700405 if (used_math()) {
406 sp = sp - sig_xstate_ia32_size;
407 *fpstate = (struct _fpstate_ia32 *) sp;
Hiroshi Shimamoto99ea1b932008-11-05 18:32:54 -0800408 if (save_i387_xstate_ia32(*fpstate) < 0)
409 return (void __user *) -1L;
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700410 }
411
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100412 sp -= frame_size;
Markus F.X.J. Oberhumerd347f372005-10-09 18:54:23 +0200413 /* Align the stack pointer according to the i386 ABI,
414 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100415 sp = ((sp + 4) & -16ul) - 4;
416 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417}
418
Roland McGrath0928d6e2005-06-23 00:08:37 -0700419int ia32_setup_frame(int sig, struct k_sigaction *ka,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100420 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421{
422 struct sigframe __user *frame;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100423 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700425 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100427 /* copy_to_user optimizes that into a single 8 byte store */
428 static const struct {
429 u16 poplmovl;
430 u32 val;
431 u16 int80;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100432 } __attribute__((packed)) code = {
433 0xb858, /* popl %eax ; movl $...,%eax */
434 __NR_ia32_sigreturn,
435 0x80cd, /* int $0x80 */
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100436 };
437
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700438 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
440 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700441 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700443 if (__put_user(sig, &frame->sig))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700444 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700446 if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700447 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
449 if (_COMPAT_NSIG_WORDS > 1) {
Hiroshi Shimamoto2ba48e12008-09-12 17:02:53 -0700450 if (__copy_to_user(frame->extramask, &set->sig[1],
451 sizeof(frame->extramask)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700452 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
Roland McGrathaf65d642008-01-30 13:30:43 +0100455 if (ka->sa.sa_flags & SA_RESTORER) {
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100456 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100457 } else {
458 /* Return stub is in 32bit vsyscall page */
Roland McGrath1a3e4ca2008-04-09 01:29:27 -0700459 if (current->mm->context.vdso)
Roland McGrathaf65d642008-01-30 13:30:43 +0100460 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
461 sigreturn);
462 else
Jan Engelhardtade1af72008-01-30 13:33:23 +0100463 restorer = &frame->retcode;
Roland McGrathaf65d642008-01-30 13:30:43 +0100464 }
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100465 err |= __put_user(ptr_to_compat(restorer), &frame->pretcode);
466
467 /*
468 * These are actually not used anymore, but left because some
469 * gdb versions depend on them as a marker.
470 */
471 err |= __copy_to_user(frame->retcode, &code, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700473 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
475 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100476 regs->sp = (unsigned long) frame;
477 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Andi Kleen536e3ee2006-09-26 10:52:41 +0200479 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100480 regs->ax = sig;
481 regs->dx = 0;
482 regs->cx = 0;
Andi Kleen536e3ee2006-09-26 10:52:41 +0200483
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700484 loadsegment(ds, __USER32_DS);
485 loadsegment(es, __USER32_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100487 regs->cs = __USER32_CS;
488 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490#if DEBUG_SIG
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100491 printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n",
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100492 current->comm, current->pid, frame, regs->ip, frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493#endif
494
Andi Kleen1d001df2006-09-26 10:52:26 +0200495 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496}
497
Roland McGrath0928d6e2005-06-23 00:08:37 -0700498int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100499 compat_sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
501 struct rt_sigframe __user *frame;
Roland McGrathaf65d642008-01-30 13:30:43 +0100502 void __user *restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 int err = 0;
Suresh Siddhaab513702008-07-29 10:29:22 -0700504 void __user *fpstate = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100506 /* __copy_to_user optimizes that into a single 8 byte store */
507 static const struct {
508 u8 movl;
509 u32 val;
510 u16 int80;
Hiroshi Shimamoto9cc3c492008-11-11 19:11:39 -0800511 u8 pad;
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100512 } __attribute__((packed)) code = {
513 0xb8,
514 __NR_ia32_rt_sigreturn,
515 0x80cd,
516 0,
517 };
518
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700519 frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
521 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700522 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Hiroshi Shimamoto812b1212008-07-16 19:21:31 -0700524 err |= __put_user(sig, &frame->sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo);
526 err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc);
527 err |= copy_siginfo_to_user32(&frame->info, info);
528 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700529 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531 /* Create the ucontext. */
Suresh Siddhac37b5ef2008-07-29 10:29:25 -0700532 if (cpu_has_xsave)
533 err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
534 else
535 err |= __put_user(0, &frame->uc.uc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 err |= __put_user(0, &frame->uc.uc_link);
537 err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100538 err |= __put_user(sas_ss_flags(regs->sp),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 &frame->uc.uc_stack.ss_flags);
540 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
Suresh Siddha3c1c7f12008-07-29 10:29:21 -0700541 err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100542 regs, set->sig[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
544 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700545 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100547 if (ka->sa.sa_flags & SA_RESTORER)
548 restorer = ka->sa.sa_restorer;
Roland McGrathaf65d642008-01-30 13:30:43 +0100549 else
550 restorer = VDSO32_SYMBOL(current->mm->context.vdso,
551 rt_sigreturn);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100552 err |= __put_user(ptr_to_compat(restorer), &frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100554 /*
555 * Not actually used anymore, but left because some gdb
556 * versions need it.
557 */
558 err |= __copy_to_user(frame->retcode, &code, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 if (err)
Hiroshi Shimamoto3d0aedd2008-09-12 17:01:09 -0700560 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
562 /* Set up registers for signal handler */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100563 regs->sp = (unsigned long) frame;
564 regs->ip = (unsigned long) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500566 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100567 regs->ax = sig;
568 regs->dx = (unsigned long) &frame->info;
569 regs->cx = (unsigned long) &frame->uc;
Albert Cahalana7aacdf2006-10-29 22:26:17 -0500570
Albert Cahalan8e3de532006-12-07 02:14:06 +0100571 /* Make -mregparm=3 work */
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100572 regs->ax = sig;
573 regs->dx = (unsigned long) &frame->info;
574 regs->cx = (unsigned long) &frame->uc;
Albert Cahalan8e3de532006-12-07 02:14:06 +0100575
Jeremy Fitzhardingeb6edbb12008-08-19 13:04:19 -0700576 loadsegment(ds, __USER32_DS);
577 loadsegment(es, __USER32_DS);
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100578
579 regs->cs = __USER32_CS;
580 regs->ss = __USER32_DS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582#if DEBUG_SIG
Thomas Gleixner99b9cdf2008-01-30 13:30:07 +0100583 printk(KERN_DEBUG "SIG deliver (%s:%d): sp=%p pc=%lx ra=%u\n",
H. Peter Anvin65ea5b02008-01-30 13:30:56 +0100584 current->comm, current->pid, frame, regs->ip, frame->pretcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585#endif
586
Andi Kleen1d001df2006-09-26 10:52:26 +0200587 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588}