Blame view

arch/x86/ia32/ia32_signal.c 14.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
  /*
   *  linux/arch/x86_64/ia32/ia32_signal.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
   *
   *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
   *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
   *  2000-12-*   x86-64 compatibility mode signal handling by Andi Kleen
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
   */
  
  #include <linux/sched.h>
  #include <linux/mm.h>
  #include <linux/smp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
21
22
  #include <linux/kernel.h>
  #include <linux/signal.h>
  #include <linux/errno.h>
  #include <linux/wait.h>
  #include <linux/ptrace.h>
  #include <linux/unistd.h>
  #include <linux/stddef.h>
  #include <linux/personality.h>
  #include <linux/compat.h>
9fbbd4dd1   Andi Kleen   [PATCH] x86: Don'...
23
  #include <linux/binfmts.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
  #include <asm/ucontext.h>
  #include <asm/uaccess.h>
  #include <asm/i387.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
  #include <asm/ptrace.h>
  #include <asm/ia32_unistd.h>
  #include <asm/user32.h>
  #include <asm/sigcontext32.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  #include <asm/proto.h>
af65d6484   Roland McGrath   x86 vDSO: consoli...
32
  #include <asm/vdso.h>
d98f9d844   Hiroshi Shimamoto   x86: ia32_signal:...
33
  #include <asm/sigframe.h>
2f06de067   Jaswinder Singh Rajput   x86: introducing ...
34
  #include <asm/sys_ia32.h>
d98f9d844   Hiroshi Shimamoto   x86: ia32_signal:...
35

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
fbdb7da91   Hiroshi Shimamoto   x86_64: ia32_sign...
37
38
39
40
  #define FIX_EFLAGS	(X86_EFLAGS_AC | X86_EFLAGS_OF | \
  			 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
  			 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
  			 X86_EFLAGS_CF)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
  void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
  
  int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
  {
3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
45
  	int err = 0;
99b9cdf75   Thomas Gleixner   x86: clean up arc...
46
47
  
  	if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  		return -EFAULT;
3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  	put_user_try {
  		/* If you change siginfo_t structure, please make sure that
  		   this code is fixed accordingly.
  		   It should never copy any pad contained in the structure
  		   to avoid security leaks, but must copy the generic
  		   3 ints plus the relevant union member.  */
  		put_user_ex(from->si_signo, &to->si_signo);
  		put_user_ex(from->si_errno, &to->si_errno);
  		put_user_ex((short)from->si_code, &to->si_code);
  
  		if (from->si_code < 0) {
  			put_user_ex(from->si_pid, &to->si_pid);
  			put_user_ex(from->si_uid, &to->si_uid);
  			put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
  		} else {
  			/*
  			 * First 32bits of unions are always present:
  			 * si_pid === si_band === si_tid === si_addr(LS half)
  			 */
  			put_user_ex(from->_sifields._pad[0],
  					  &to->_sifields._pad[0]);
  			switch (from->si_code >> 16) {
  			case __SI_FAULT >> 16:
  				break;
  			case __SI_CHLD >> 16:
  				put_user_ex(from->si_utime, &to->si_utime);
  				put_user_ex(from->si_stime, &to->si_stime);
  				put_user_ex(from->si_status, &to->si_status);
  				/* FALL THROUGH */
  			default:
  			case __SI_KILL >> 16:
  				put_user_ex(from->si_uid, &to->si_uid);
  				break;
  			case __SI_POLL >> 16:
  				put_user_ex(from->si_fd, &to->si_fd);
  				break;
  			case __SI_TIMER >> 16:
  				put_user_ex(from->si_overrun, &to->si_overrun);
  				put_user_ex(ptr_to_compat(from->si_ptr),
  					    &to->si_ptr);
  				break;
  				 /* This is not generated by the kernel as of now.  */
  			case __SI_RT >> 16:
  			case __SI_MESGQ >> 16:
  				put_user_ex(from->si_uid, &to->si_uid);
  				put_user_ex(from->si_int, &to->si_int);
  				break;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  		}
3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
98
  	} put_user_catch(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
103
  	return err;
  }
  
  int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
  {
3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
104
  	int err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  	u32 ptr32;
99b9cdf75   Thomas Gleixner   x86: clean up arc...
106
107
  
  	if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
  		return -EFAULT;
3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
109
110
111
112
  	get_user_try {
  		get_user_ex(to->si_signo, &from->si_signo);
  		get_user_ex(to->si_errno, &from->si_errno);
  		get_user_ex(to->si_code, &from->si_code);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113

3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
114
115
116
117
118
  		get_user_ex(to->si_pid, &from->si_pid);
  		get_user_ex(to->si_uid, &from->si_uid);
  		get_user_ex(ptr32, &from->si_ptr);
  		to->si_ptr = compat_ptr(ptr32);
  	} get_user_catch(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
  
  	return err;
  }
99b9cdf75   Thomas Gleixner   x86: clean up arc...
122
  asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  {
905f29e2a   Oleg Nesterov   x86, signals: Con...
124
  	sigset_t blocked;
1d001df19   Andi Kleen   [PATCH] Add TIF_R...
125
  	current->saved_sigmask = current->blocked;
905f29e2a   Oleg Nesterov   x86, signals: Con...
126
127
128
129
  
  	mask &= _BLOCKABLE;
  	siginitset(&blocked, mask);
  	set_current_blocked(&blocked);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130

1d001df19   Andi Kleen   [PATCH] Add TIF_R...
131
132
  	current->state = TASK_INTERRUPTIBLE;
  	schedule();
905f29e2a   Oleg Nesterov   x86, signals: Con...
133

5a8da0ea8   Roland McGrath   signals: x86 TS_R...
134
  	set_restore_sigmask();
1d001df19   Andi Kleen   [PATCH] Add TIF_R...
135
  	return -ERESTARTNOHAND;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  }
99b9cdf75   Thomas Gleixner   x86: clean up arc...
137
138
139
  asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
  				  stack_ia32_t __user *uoss_ptr,
  				  struct pt_regs *regs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
  {
99b9cdf75   Thomas Gleixner   x86: clean up arc...
141
  	stack_t uss, uoss;
3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
142
  	int ret, err = 0;
99b9cdf75   Thomas Gleixner   x86: clean up arc...
143
144
145
  	mm_segment_t seg;
  
  	if (uss_ptr) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  		u32 ptr;
99b9cdf75   Thomas Gleixner   x86: clean up arc...
147
148
  
  		memset(&uss, 0, sizeof(stack_t));
3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
149
150
151
152
153
154
155
156
157
158
  		if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)))
  			return -EFAULT;
  
  		get_user_try {
  			get_user_ex(ptr, &uss_ptr->ss_sp);
  			get_user_ex(uss.ss_flags, &uss_ptr->ss_flags);
  			get_user_ex(uss.ss_size, &uss_ptr->ss_size);
  		} get_user_catch(err);
  
  		if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
  			return -EFAULT;
  		uss.ss_sp = compat_ptr(ptr);
  	}
99b9cdf75   Thomas Gleixner   x86: clean up arc...
162
163
  	seg = get_fs();
  	set_fs(KERNEL_DS);
65ea5b034   H. Peter Anvin   x86: rename the s...
164
  	ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
99b9cdf75   Thomas Gleixner   x86: clean up arc...
165
  	set_fs(seg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  	if (ret >= 0 && uoss_ptr)  {
3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
167
168
169
170
171
172
173
174
175
176
  		if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
  			return -EFAULT;
  
  		put_user_try {
  			put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
  			put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
  			put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
  		} put_user_catch(err);
  
  		if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  			ret = -EFAULT;
99b9cdf75   Thomas Gleixner   x86: clean up arc...
178
179
  	}
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
  }
  
  /*
   * Do a signal return; undo the signal stack.
   */
a967bb3fb   Hiroshi Shimamoto   x86: ia32_signal:...
185
186
187
188
189
190
191
  #define loadsegment_gs(v)	load_gs_index(v)
  #define loadsegment_fs(v)	loadsegment(fs, v)
  #define loadsegment_ds(v)	loadsegment(ds, v)
  #define loadsegment_es(v)	loadsegment(es, v)
  
  #define get_user_seg(seg)	({ unsigned int v; savesegment(seg, v); v; })
  #define set_user_seg(seg, v)	loadsegment_##seg(v)
b78a5b526   Hiroshi Shimamoto   x86: ia32_signal:...
192
  #define COPY(x)			{		\
3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
193
  	get_user_ex(regs->x, &sc->x);		\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195

8801ead40   Hiroshi Shimamoto   x86: ia32_signal:...
196
197
198
199
200
201
202
203
204
  #define GET_SEG(seg)		({			\
  	unsigned short tmp;				\
  	get_user_ex(tmp, &sc->seg);			\
  	tmp;						\
  })
  
  #define COPY_SEG_CPL3(seg)	do {			\
  	regs->seg = GET_SEG(seg) | 3;			\
  } while (0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205

8c6e5ce0f   Hiroshi Shimamoto   x86: ia32_signal:...
206
  #define RELOAD_SEG(seg)		{		\
a967bb3fb   Hiroshi Shimamoto   x86: ia32_signal:...
207
208
  	unsigned int pre = GET_SEG(seg);	\
  	unsigned int cur = get_user_seg(seg);	\
8c6e5ce0f   Hiroshi Shimamoto   x86: ia32_signal:...
209
210
  	pre |= 3;				\
  	if (pre != cur)				\
a967bb3fb   Hiroshi Shimamoto   x86: ia32_signal:...
211
  		set_user_seg(seg, pre);		\
8c6e5ce0f   Hiroshi Shimamoto   x86: ia32_signal:...
212
  }
99b9cdf75   Thomas Gleixner   x86: clean up arc...
213
214
215
  
  static int ia32_restore_sigcontext(struct pt_regs *regs,
  				   struct sigcontext_ia32 __user *sc,
047ce9358   Hiroshi Shimamoto   x86: ia32_signal:...
216
  				   unsigned int *pax)
99b9cdf75   Thomas Gleixner   x86: clean up arc...
217
  {
a967bb3fb   Hiroshi Shimamoto   x86: ia32_signal:...
218
  	unsigned int tmpflags, err = 0;
ab5137015   Suresh Siddha   x86, xsave: reorg...
219
  	void __user *buf;
99b9cdf75   Thomas Gleixner   x86: clean up arc...
220
221
222
223
  	u32 tmp;
  
  	/* Always make any pending restarted system calls return -EINTR */
  	current_thread_info()->restart_block.fn = do_no_restart_syscall;
3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
224
225
226
227
228
229
230
  	get_user_try {
  		/*
  		 * Reload fs and gs if they have changed in the signal
  		 * handler.  This does not handle long fs/gs base changes in
  		 * the handler, but does not clobber them at least in the
  		 * normal case.
  		 */
a967bb3fb   Hiroshi Shimamoto   x86: ia32_signal:...
231
  		RELOAD_SEG(gs);
3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
  		RELOAD_SEG(fs);
  		RELOAD_SEG(ds);
  		RELOAD_SEG(es);
  
  		COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
  		COPY(dx); COPY(cx); COPY(ip);
  		/* Don't touch extended registers */
  
  		COPY_SEG_CPL3(cs);
  		COPY_SEG_CPL3(ss);
  
  		get_user_ex(tmpflags, &sc->flags);
  		regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
  		/* disable syscall checks */
  		regs->orig_ax = -1;
  
  		get_user_ex(tmp, &sc->fpstate);
  		buf = compat_ptr(tmp);
  		err |= restore_i387_xstate_ia32(buf);
  
  		get_user_ex(*pax, &sc->ax);
  	} get_user_catch(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
258
  }
  
  asmlinkage long sys32_sigreturn(struct pt_regs *regs)
  {
3b0d29ee1   Hiroshi Shimamoto   x86: ia32_signal:...
259
  	struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
  	sigset_t set;
65ea5b034   H. Peter Anvin   x86: rename the s...
261
  	unsigned int ax;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
266
  
  	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
  		goto badframe;
  	if (__get_user(set.sig[0], &frame->sc.oldmask)
  	    || (_COMPAT_NSIG_WORDS > 1
99b9cdf75   Thomas Gleixner   x86: clean up arc...
267
268
  		&& __copy_from_user((((char *) &set.sig) + 4),
  				    &frame->extramask,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
271
272
  				    sizeof(frame->extramask))))
  		goto badframe;
  
  	sigdelsetmask(&set, ~_BLOCKABLE);
905f29e2a   Oleg Nesterov   x86, signals: Con...
273
  	set_current_blocked(&set);
99b9cdf75   Thomas Gleixner   x86: clean up arc...
274

65ea5b034   H. Peter Anvin   x86: rename the s...
275
  	if (ia32_restore_sigcontext(regs, &frame->sc, &ax))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  		goto badframe;
65ea5b034   H. Peter Anvin   x86: rename the s...
277
  	return ax;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
281
  
  badframe:
  	signal_fault(regs, frame, "32bit sigreturn");
  	return 0;
99b9cdf75   Thomas Gleixner   x86: clean up arc...
282
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
  
  asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
  {
3b0d29ee1   Hiroshi Shimamoto   x86: ia32_signal:...
286
  	struct rt_sigframe_ia32 __user *frame;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  	sigset_t set;
65ea5b034   H. Peter Anvin   x86: rename the s...
288
  	unsigned int ax;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  	struct pt_regs tregs;
3b0d29ee1   Hiroshi Shimamoto   x86: ia32_signal:...
290
  	frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
295
296
297
  
  	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
  		goto badframe;
  	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
  		goto badframe;
  
  	sigdelsetmask(&set, ~_BLOCKABLE);
905f29e2a   Oleg Nesterov   x86, signals: Con...
298
  	set_current_blocked(&set);
99b9cdf75   Thomas Gleixner   x86: clean up arc...
299

65ea5b034   H. Peter Anvin   x86: rename the s...
300
  	if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
305
  		goto badframe;
  
  	tregs = *regs;
  	if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
  		goto badframe;
65ea5b034   H. Peter Anvin   x86: rename the s...
306
  	return ax;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
  
  badframe:
99b9cdf75   Thomas Gleixner   x86: clean up arc...
309
  	signal_fault(regs, frame, "32bit rt sigreturn");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  	return 0;
99b9cdf75   Thomas Gleixner   x86: clean up arc...
311
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
314
315
  
  /*
   * Set up a signal frame.
   */
99b9cdf75   Thomas Gleixner   x86: clean up arc...
316
  static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
ab5137015   Suresh Siddha   x86, xsave: reorg...
317
  				 void __user *fpstate,
99b9cdf75   Thomas Gleixner   x86: clean up arc...
318
  				 struct pt_regs *regs, unsigned int mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  {
a967bb3fb   Hiroshi Shimamoto   x86: ia32_signal:...
320
  	int err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321

3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
322
  	put_user_try {
a967bb3fb   Hiroshi Shimamoto   x86: ia32_signal:...
323
324
325
326
  		put_user_ex(get_user_seg(gs), (unsigned int __user *)&sc->gs);
  		put_user_ex(get_user_seg(fs), (unsigned int __user *)&sc->fs);
  		put_user_ex(get_user_seg(ds), (unsigned int __user *)&sc->ds);
  		put_user_ex(get_user_seg(es), (unsigned int __user *)&sc->es);
3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  
  		put_user_ex(regs->di, &sc->di);
  		put_user_ex(regs->si, &sc->si);
  		put_user_ex(regs->bp, &sc->bp);
  		put_user_ex(regs->sp, &sc->sp);
  		put_user_ex(regs->bx, &sc->bx);
  		put_user_ex(regs->dx, &sc->dx);
  		put_user_ex(regs->cx, &sc->cx);
  		put_user_ex(regs->ax, &sc->ax);
  		put_user_ex(current->thread.trap_no, &sc->trapno);
  		put_user_ex(current->thread.error_code, &sc->err);
  		put_user_ex(regs->ip, &sc->ip);
  		put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
  		put_user_ex(regs->flags, &sc->flags);
  		put_user_ex(regs->sp, &sc->sp_at_signal);
  		put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
  
  		put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
  
  		/* non-iBCS2 extensions.. */
  		put_user_ex(mask, &sc->oldmask);
  		put_user_ex(current->thread.cr2, &sc->cr2);
  	} put_user_catch(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
354
355
356
  
  	return err;
  }
  
  /*
   * Determine which stack to use..
   */
99b9cdf75   Thomas Gleixner   x86: clean up arc...
357
  static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
3c1c7f101   Suresh Siddha   x86, xsave: dynam...
358
  				 size_t frame_size,
ab5137015   Suresh Siddha   x86, xsave: reorg...
359
  				 void **fpstate)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  {
65ea5b034   H. Peter Anvin   x86: rename the s...
361
  	unsigned long sp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
  
  	/* Default to using normal stack */
65ea5b034   H. Peter Anvin   x86: rename the s...
364
  	sp = regs->sp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
  
  	/* This is the X/Open sanctioned signal stack switching.  */
  	if (ka->sa.sa_flags & SA_ONSTACK) {
65ea5b034   H. Peter Anvin   x86: rename the s...
368
369
  		if (sas_ss_flags(sp) == 0)
  			sp = current->sas_ss_sp + current->sas_ss_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
  	}
  
  	/* This is the legacy signal stack switching. */
8bee3f0a6   Hiroshi Shimamoto   x86: ia32_signal:...
373
  	else if ((regs->ss & 0xffff) != __USER32_DS &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  		!(ka->sa.sa_flags & SA_RESTORER) &&
99b9cdf75   Thomas Gleixner   x86: clean up arc...
375
  		 ka->sa.sa_restorer)
65ea5b034   H. Peter Anvin   x86: rename the s...
376
  		sp = (unsigned long) ka->sa.sa_restorer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377

3c1c7f101   Suresh Siddha   x86, xsave: dynam...
378
379
380
  	if (used_math()) {
  		sp = sp - sig_xstate_ia32_size;
  		*fpstate = (struct _fpstate_ia32 *) sp;
99ea1b93b   Hiroshi Shimamoto   x86: ia32_signal:...
381
382
  		if (save_i387_xstate_ia32(*fpstate) < 0)
  			return (void __user *) -1L;
3c1c7f101   Suresh Siddha   x86, xsave: dynam...
383
  	}
65ea5b034   H. Peter Anvin   x86: rename the s...
384
  	sp -= frame_size;
d347f3722   Markus F.X.J. Oberhumer   [PATCH] i386: fix...
385
386
  	/* Align the stack pointer according to the i386 ABI,
  	 * i.e. so that on function entry ((sp + 4) & 15) == 0. */
65ea5b034   H. Peter Anvin   x86: rename the s...
387
388
  	sp = ((sp + 4) & -16ul) - 4;
  	return (void __user *) sp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
  }
0928d6ef7   Roland McGrath   [PATCH] x86_64: n...
390
  int ia32_setup_frame(int sig, struct k_sigaction *ka,
99b9cdf75   Thomas Gleixner   x86: clean up arc...
391
  		     compat_sigset_t *set, struct pt_regs *regs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  {
3b0d29ee1   Hiroshi Shimamoto   x86: ia32_signal:...
393
  	struct sigframe_ia32 __user *frame;
99b9cdf75   Thomas Gleixner   x86: clean up arc...
394
  	void __user *restorer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
  	int err = 0;
ab5137015   Suresh Siddha   x86, xsave: reorg...
396
  	void __user *fpstate = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397

99b9cdf75   Thomas Gleixner   x86: clean up arc...
398
399
400
401
402
  	/* copy_to_user optimizes that into a single 8 byte store */
  	static const struct {
  		u16 poplmovl;
  		u32 val;
  		u16 int80;
99b9cdf75   Thomas Gleixner   x86: clean up arc...
403
404
405
406
  	} __attribute__((packed)) code = {
  		0xb858,		 /* popl %eax ; movl $...,%eax */
  		__NR_ia32_sigreturn,
  		0x80cd,		/* int $0x80 */
99b9cdf75   Thomas Gleixner   x86: clean up arc...
407
  	};
3c1c7f101   Suresh Siddha   x86, xsave: dynam...
408
  	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
  
  	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
3d0aedd95   Hiroshi Shimamoto   x86: signal: put ...
411
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412

2ba48e16e   Hiroshi Shimamoto   x86: signal: remo...
413
  	if (__put_user(sig, &frame->sig))
3d0aedd95   Hiroshi Shimamoto   x86: signal: put ...
414
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415

2ba48e16e   Hiroshi Shimamoto   x86: signal: remo...
416
  	if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
3d0aedd95   Hiroshi Shimamoto   x86: signal: put ...
417
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
  
  	if (_COMPAT_NSIG_WORDS > 1) {
2ba48e16e   Hiroshi Shimamoto   x86: signal: remo...
420
421
  		if (__copy_to_user(frame->extramask, &set->sig[1],
  				   sizeof(frame->extramask)))
3d0aedd95   Hiroshi Shimamoto   x86: signal: put ...
422
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424

af65d6484   Roland McGrath   x86 vDSO: consoli...
425
  	if (ka->sa.sa_flags & SA_RESTORER) {
99b9cdf75   Thomas Gleixner   x86: clean up arc...
426
  		restorer = ka->sa.sa_restorer;
af65d6484   Roland McGrath   x86 vDSO: consoli...
427
428
  	} else {
  		/* Return stub is in 32bit vsyscall page */
1a3e4ca41   Roland McGrath   x86 vDSO: don't u...
429
  		if (current->mm->context.vdso)
af65d6484   Roland McGrath   x86 vDSO: consoli...
430
431
432
  			restorer = VDSO32_SYMBOL(current->mm->context.vdso,
  						 sigreturn);
  		else
ade1af771   Jan Engelhardt   x86: remove unned...
433
  			restorer = &frame->retcode;
af65d6484   Roland McGrath   x86 vDSO: consoli...
434
  	}
99b9cdf75   Thomas Gleixner   x86: clean up arc...
435

3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
436
437
438
439
440
441
442
443
444
  	put_user_try {
  		put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
  
  		/*
  		 * These are actually not used anymore, but left because some
  		 * gdb versions depend on them as a marker.
  		 */
  		put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
  	} put_user_catch(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
  	if (err)
3d0aedd95   Hiroshi Shimamoto   x86: signal: put ...
446
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
448
  
  	/* Set up registers for signal handler */
65ea5b034   H. Peter Anvin   x86: rename the s...
449
450
  	regs->sp = (unsigned long) frame;
  	regs->ip = (unsigned long) ka->sa.sa_handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451

536e3ee4f   Andi Kleen   [PATCH] Initializ...
452
  	/* Make -mregparm=3 work */
65ea5b034   H. Peter Anvin   x86: rename the s...
453
454
455
  	regs->ax = sig;
  	regs->dx = 0;
  	regs->cx = 0;
536e3ee4f   Andi Kleen   [PATCH] Initializ...
456

b6edbb1e0   Jeremy Fitzhardinge   x86_64: use save/...
457
458
  	loadsegment(ds, __USER32_DS);
  	loadsegment(es, __USER32_DS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459

99b9cdf75   Thomas Gleixner   x86: clean up arc...
460
461
  	regs->cs = __USER32_CS;
  	regs->ss = __USER32_DS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462

1d001df19   Andi Kleen   [PATCH] Add TIF_R...
463
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  }
0928d6ef7   Roland McGrath   [PATCH] x86_64: n...
465
  int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
99b9cdf75   Thomas Gleixner   x86: clean up arc...
466
  			compat_sigset_t *set, struct pt_regs *regs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
  {
3b0d29ee1   Hiroshi Shimamoto   x86: ia32_signal:...
468
  	struct rt_sigframe_ia32 __user *frame;
af65d6484   Roland McGrath   x86 vDSO: consoli...
469
  	void __user *restorer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  	int err = 0;
ab5137015   Suresh Siddha   x86, xsave: reorg...
471
  	void __user *fpstate = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472

99b9cdf75   Thomas Gleixner   x86: clean up arc...
473
474
475
476
477
  	/* __copy_to_user optimizes that into a single 8 byte store */
  	static const struct {
  		u8 movl;
  		u32 val;
  		u16 int80;
9cc3c49ed   Hiroshi Shimamoto   x86: ia32_signal:...
478
  		u8  pad;
99b9cdf75   Thomas Gleixner   x86: clean up arc...
479
480
481
482
483
484
  	} __attribute__((packed)) code = {
  		0xb8,
  		__NR_ia32_rt_sigreturn,
  		0x80cd,
  		0,
  	};
3c1c7f101   Suresh Siddha   x86, xsave: dynam...
485
  	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
  
  	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
3d0aedd95   Hiroshi Shimamoto   x86: signal: put ...
488
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489

3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
490
491
492
493
494
  	put_user_try {
  		put_user_ex(sig, &frame->sig);
  		put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
  		put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
  		err |= copy_siginfo_to_user32(&frame->info, info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495

3b4b75700   Hiroshi Shimamoto   x86: ia32_signal:...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
  		/* Create the ucontext.  */
  		if (cpu_has_xsave)
  			put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
  		else
  			put_user_ex(0, &frame->uc.uc_flags);
  		put_user_ex(0, &frame->uc.uc_link);
  		put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
  		put_user_ex(sas_ss_flags(regs->sp),
  			    &frame->uc.uc_stack.ss_flags);
  		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
  		err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
  					     regs, set->sig[0]);
  		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
  
  		if (ka->sa.sa_flags & SA_RESTORER)
  			restorer = ka->sa.sa_restorer;
  		else
  			restorer = VDSO32_SYMBOL(current->mm->context.vdso,
  						 rt_sigreturn);
  		put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
  
  		/*
  		 * Not actually used anymore, but left because some gdb
  		 * versions need it.
  		 */
  		put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
  	} put_user_catch(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  	if (err)
3d0aedd95   Hiroshi Shimamoto   x86: signal: put ...
525
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
  
  	/* Set up registers for signal handler */
65ea5b034   H. Peter Anvin   x86: rename the s...
528
529
  	regs->sp = (unsigned long) frame;
  	regs->ip = (unsigned long) ka->sa.sa_handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530

a7aacdf9e   Albert Cahalan   [PATCH] fix i386 ...
531
  	/* Make -mregparm=3 work */
65ea5b034   H. Peter Anvin   x86: rename the s...
532
533
534
  	regs->ax = sig;
  	regs->dx = (unsigned long) &frame->info;
  	regs->cx = (unsigned long) &frame->uc;
a7aacdf9e   Albert Cahalan   [PATCH] fix i386 ...
535

b6edbb1e0   Jeremy Fitzhardinge   x86_64: use save/...
536
537
  	loadsegment(ds, __USER32_DS);
  	loadsegment(es, __USER32_DS);
99b9cdf75   Thomas Gleixner   x86: clean up arc...
538
539
540
  
  	regs->cs = __USER32_CS;
  	regs->ss = __USER32_DS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541

1d001df19   Andi Kleen   [PATCH] Add TIF_R...
542
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
  }