diff options
Diffstat (limited to 'arch/x86/um/signal.c')
-rw-r--r-- | arch/x86/um/signal.c | 624 |
1 files changed, 624 insertions, 0 deletions
diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c new file mode 100644 index 000000000000..4883b9546016 --- /dev/null +++ b/arch/x86/um/signal.c | |||
@@ -0,0 +1,624 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2003 PathScale, Inc. | ||
3 | * Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | ||
4 | * Licensed under the GPL | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include <linux/personality.h> | ||
9 | #include <linux/ptrace.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <asm/unistd.h> | ||
12 | #include <asm/uaccess.h> | ||
13 | #include <asm/ucontext.h> | ||
14 | #include "frame_kern.h" | ||
15 | #include "skas.h" | ||
16 | |||
17 | #ifdef CONFIG_X86_32 | ||
18 | |||
19 | /* | ||
20 | * FPU tag word conversions. | ||
21 | */ | ||
22 | |||
23 | static inline unsigned short twd_i387_to_fxsr(unsigned short twd) | ||
24 | { | ||
25 | unsigned int tmp; /* to avoid 16 bit prefixes in the code */ | ||
26 | |||
27 | /* Transform each pair of bits into 01 (valid) or 00 (empty) */ | ||
28 | tmp = ~twd; | ||
29 | tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ | ||
30 | /* and move the valid bits to the lower byte. */ | ||
31 | tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ | ||
32 | tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ | ||
33 | tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ | ||
34 | return tmp; | ||
35 | } | ||
36 | |||
37 | static inline unsigned long twd_fxsr_to_i387(struct user_fxsr_struct *fxsave) | ||
38 | { | ||
39 | struct _fpxreg *st = NULL; | ||
40 | unsigned long twd = (unsigned long) fxsave->twd; | ||
41 | unsigned long tag; | ||
42 | unsigned long ret = 0xffff0000; | ||
43 | int i; | ||
44 | |||
45 | #define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16) | ||
46 | |||
47 | for (i = 0; i < 8; i++) { | ||
48 | if (twd & 0x1) { | ||
49 | st = (struct _fpxreg *) FPREG_ADDR(fxsave, i); | ||
50 | |||
51 | switch (st->exponent & 0x7fff) { | ||
52 | case 0x7fff: | ||
53 | tag = 2; /* Special */ | ||
54 | break; | ||
55 | case 0x0000: | ||
56 | if ( !st->significand[0] && | ||
57 | !st->significand[1] && | ||
58 | !st->significand[2] && | ||
59 | !st->significand[3] ) { | ||
60 | tag = 1; /* Zero */ | ||
61 | } else { | ||
62 | tag = 2; /* Special */ | ||
63 | } | ||
64 | break; | ||
65 | default: | ||
66 | if (st->significand[3] & 0x8000) { | ||
67 | tag = 0; /* Valid */ | ||
68 | } else { | ||
69 | tag = 2; /* Special */ | ||
70 | } | ||
71 | break; | ||
72 | } | ||
73 | } else { | ||
74 | tag = 3; /* Empty */ | ||
75 | } | ||
76 | ret |= (tag << (2 * i)); | ||
77 | twd = twd >> 1; | ||
78 | } | ||
79 | return ret; | ||
80 | } | ||
81 | |||
82 | static int convert_fxsr_to_user(struct _fpstate __user *buf, | ||
83 | struct user_fxsr_struct *fxsave) | ||
84 | { | ||
85 | unsigned long env[7]; | ||
86 | struct _fpreg __user *to; | ||
87 | struct _fpxreg *from; | ||
88 | int i; | ||
89 | |||
90 | env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul; | ||
91 | env[1] = (unsigned long)fxsave->swd | 0xffff0000ul; | ||
92 | env[2] = twd_fxsr_to_i387(fxsave); | ||
93 | env[3] = fxsave->fip; | ||
94 | env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16); | ||
95 | env[5] = fxsave->foo; | ||
96 | env[6] = fxsave->fos; | ||
97 | |||
98 | if (__copy_to_user(buf, env, 7 * sizeof(unsigned long))) | ||
99 | return 1; | ||
100 | |||
101 | to = &buf->_st[0]; | ||
102 | from = (struct _fpxreg *) &fxsave->st_space[0]; | ||
103 | for (i = 0; i < 8; i++, to++, from++) { | ||
104 | unsigned long __user *t = (unsigned long __user *)to; | ||
105 | unsigned long *f = (unsigned long *)from; | ||
106 | |||
107 | if (__put_user(*f, t) || | ||
108 | __put_user(*(f + 1), t + 1) || | ||
109 | __put_user(from->exponent, &to->exponent)) | ||
110 | return 1; | ||
111 | } | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int convert_fxsr_from_user(struct user_fxsr_struct *fxsave, | ||
116 | struct _fpstate __user *buf) | ||
117 | { | ||
118 | unsigned long env[7]; | ||
119 | struct _fpxreg *to; | ||
120 | struct _fpreg __user *from; | ||
121 | int i; | ||
122 | |||
123 | if (copy_from_user( env, buf, 7 * sizeof(long))) | ||
124 | return 1; | ||
125 | |||
126 | fxsave->cwd = (unsigned short)(env[0] & 0xffff); | ||
127 | fxsave->swd = (unsigned short)(env[1] & 0xffff); | ||
128 | fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); | ||
129 | fxsave->fip = env[3]; | ||
130 | fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16); | ||
131 | fxsave->fcs = (env[4] & 0xffff); | ||
132 | fxsave->foo = env[5]; | ||
133 | fxsave->fos = env[6]; | ||
134 | |||
135 | to = (struct _fpxreg *) &fxsave->st_space[0]; | ||
136 | from = &buf->_st[0]; | ||
137 | for (i = 0; i < 8; i++, to++, from++) { | ||
138 | unsigned long *t = (unsigned long *)to; | ||
139 | unsigned long __user *f = (unsigned long __user *)from; | ||
140 | |||
141 | if (__get_user(*t, f) || | ||
142 | __get_user(*(t + 1), f + 1) || | ||
143 | __get_user(to->exponent, &from->exponent)) | ||
144 | return 1; | ||
145 | } | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | extern int have_fpx_regs; | ||
150 | |||
151 | #endif | ||
152 | |||
153 | static int copy_sc_from_user(struct pt_regs *regs, | ||
154 | struct sigcontext __user *from) | ||
155 | { | ||
156 | struct sigcontext sc; | ||
157 | int err, pid; | ||
158 | |||
159 | err = copy_from_user(&sc, from, sizeof(sc)); | ||
160 | if (err) | ||
161 | return err; | ||
162 | |||
163 | #define GETREG(regno, regname) regs->regs.gp[HOST_##regno] = sc.regname | ||
164 | |||
165 | #ifdef CONFIG_X86_32 | ||
166 | GETREG(GS, gs); | ||
167 | GETREG(FS, fs); | ||
168 | GETREG(ES, es); | ||
169 | GETREG(DS, ds); | ||
170 | #endif | ||
171 | GETREG(DI, di); | ||
172 | GETREG(SI, si); | ||
173 | GETREG(BP, bp); | ||
174 | GETREG(SP, sp); | ||
175 | GETREG(BX, bx); | ||
176 | GETREG(DX, dx); | ||
177 | GETREG(CX, cx); | ||
178 | GETREG(AX, ax); | ||
179 | GETREG(IP, ip); | ||
180 | |||
181 | #ifdef CONFIG_X86_64 | ||
182 | GETREG(R8, r8); | ||
183 | GETREG(R9, r9); | ||
184 | GETREG(R10, r10); | ||
185 | GETREG(R11, r11); | ||
186 | GETREG(R12, r12); | ||
187 | GETREG(R13, r13); | ||
188 | GETREG(R14, r14); | ||
189 | GETREG(R15, r15); | ||
190 | #endif | ||
191 | |||
192 | GETREG(CS, cs); | ||
193 | GETREG(EFLAGS, flags); | ||
194 | #ifdef CONFIG_X86_32 | ||
195 | GETREG(SS, ss); | ||
196 | #endif | ||
197 | |||
198 | #undef GETREG | ||
199 | |||
200 | pid = userspace_pid[current_thread_info()->cpu]; | ||
201 | #ifdef CONFIG_X86_32 | ||
202 | if (have_fpx_regs) { | ||
203 | struct user_fxsr_struct fpx; | ||
204 | |||
205 | err = copy_from_user(&fpx, | ||
206 | &((struct _fpstate __user *)sc.fpstate)->_fxsr_env[0], | ||
207 | sizeof(struct user_fxsr_struct)); | ||
208 | if (err) | ||
209 | return 1; | ||
210 | |||
211 | err = convert_fxsr_from_user(&fpx, sc.fpstate); | ||
212 | if (err) | ||
213 | return 1; | ||
214 | |||
215 | err = restore_fpx_registers(pid, (unsigned long *) &fpx); | ||
216 | if (err < 0) { | ||
217 | printk(KERN_ERR "copy_sc_from_user - " | ||
218 | "restore_fpx_registers failed, errno = %d\n", | ||
219 | -err); | ||
220 | return 1; | ||
221 | } | ||
222 | } else | ||
223 | #endif | ||
224 | { | ||
225 | struct user_i387_struct fp; | ||
226 | |||
227 | err = copy_from_user(&fp, sc.fpstate, | ||
228 | sizeof(struct user_i387_struct)); | ||
229 | if (err) | ||
230 | return 1; | ||
231 | |||
232 | err = restore_fp_registers(pid, (unsigned long *) &fp); | ||
233 | if (err < 0) { | ||
234 | printk(KERN_ERR "copy_sc_from_user - " | ||
235 | "restore_fp_registers failed, errno = %d\n", | ||
236 | -err); | ||
237 | return 1; | ||
238 | } | ||
239 | } | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int copy_sc_to_user(struct sigcontext __user *to, | ||
244 | struct _fpstate __user *to_fp, struct pt_regs *regs, | ||
245 | unsigned long mask) | ||
246 | { | ||
247 | struct sigcontext sc; | ||
248 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; | ||
249 | int err, pid; | ||
250 | memset(&sc, 0, sizeof(struct sigcontext)); | ||
251 | |||
252 | #define PUTREG(regno, regname) sc.regname = regs->regs.gp[HOST_##regno] | ||
253 | |||
254 | #ifdef CONFIG_X86_32 | ||
255 | PUTREG(GS, gs); | ||
256 | PUTREG(FS, fs); | ||
257 | PUTREG(ES, es); | ||
258 | PUTREG(DS, ds); | ||
259 | #endif | ||
260 | PUTREG(DI, di); | ||
261 | PUTREG(SI, si); | ||
262 | PUTREG(BP, bp); | ||
263 | PUTREG(SP, sp); | ||
264 | PUTREG(BX, bx); | ||
265 | PUTREG(DX, dx); | ||
266 | PUTREG(CX, cx); | ||
267 | PUTREG(AX, ax); | ||
268 | #ifdef CONFIG_X86_64 | ||
269 | PUTREG(R8, r8); | ||
270 | PUTREG(R9, r9); | ||
271 | PUTREG(R10, r10); | ||
272 | PUTREG(R11, r11); | ||
273 | PUTREG(R12, r12); | ||
274 | PUTREG(R13, r13); | ||
275 | PUTREG(R14, r14); | ||
276 | PUTREG(R15, r15); | ||
277 | #endif | ||
278 | |||
279 | sc.cr2 = fi->cr2; | ||
280 | sc.err = fi->error_code; | ||
281 | sc.trapno = fi->trap_no; | ||
282 | PUTREG(IP, ip); | ||
283 | PUTREG(CS, cs); | ||
284 | PUTREG(EFLAGS, flags); | ||
285 | #ifdef CONFIG_X86_32 | ||
286 | PUTREG(SP, sp_at_signal); | ||
287 | PUTREG(SS, ss); | ||
288 | #endif | ||
289 | #undef PUTREG | ||
290 | sc.oldmask = mask; | ||
291 | sc.fpstate = to_fp; | ||
292 | |||
293 | err = copy_to_user(to, &sc, sizeof(struct sigcontext)); | ||
294 | if (err) | ||
295 | return 1; | ||
296 | |||
297 | pid = userspace_pid[current_thread_info()->cpu]; | ||
298 | |||
299 | #ifdef CONFIG_X86_32 | ||
300 | if (have_fpx_regs) { | ||
301 | struct user_fxsr_struct fpx; | ||
302 | |||
303 | err = save_fpx_registers(pid, (unsigned long *) &fpx); | ||
304 | if (err < 0){ | ||
305 | printk(KERN_ERR "copy_sc_to_user - save_fpx_registers " | ||
306 | "failed, errno = %d\n", err); | ||
307 | return 1; | ||
308 | } | ||
309 | |||
310 | err = convert_fxsr_to_user(to_fp, &fpx); | ||
311 | if (err) | ||
312 | return 1; | ||
313 | |||
314 | err |= __put_user(fpx.swd, &to_fp->status); | ||
315 | err |= __put_user(X86_FXSR_MAGIC, &to_fp->magic); | ||
316 | if (err) | ||
317 | return 1; | ||
318 | |||
319 | if (copy_to_user(&to_fp->_fxsr_env[0], &fpx, | ||
320 | sizeof(struct user_fxsr_struct))) | ||
321 | return 1; | ||
322 | } else | ||
323 | #endif | ||
324 | { | ||
325 | struct user_i387_struct fp; | ||
326 | |||
327 | err = save_fp_registers(pid, (unsigned long *) &fp); | ||
328 | if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct))) | ||
329 | return 1; | ||
330 | } | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | #ifdef CONFIG_X86_32 | ||
336 | static int copy_ucontext_to_user(struct ucontext __user *uc, | ||
337 | struct _fpstate __user *fp, sigset_t *set, | ||
338 | unsigned long sp) | ||
339 | { | ||
340 | int err = 0; | ||
341 | |||
342 | err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp); | ||
343 | err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags); | ||
344 | err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size); | ||
345 | err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs, 0); | ||
346 | err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); | ||
347 | return err; | ||
348 | } | ||
349 | |||
350 | struct sigframe | ||
351 | { | ||
352 | char __user *pretcode; | ||
353 | int sig; | ||
354 | struct sigcontext sc; | ||
355 | struct _fpstate fpstate; | ||
356 | unsigned long extramask[_NSIG_WORDS-1]; | ||
357 | char retcode[8]; | ||
358 | }; | ||
359 | |||
360 | struct rt_sigframe | ||
361 | { | ||
362 | char __user *pretcode; | ||
363 | int sig; | ||
364 | struct siginfo __user *pinfo; | ||
365 | void __user *puc; | ||
366 | struct siginfo info; | ||
367 | struct ucontext uc; | ||
368 | struct _fpstate fpstate; | ||
369 | char retcode[8]; | ||
370 | }; | ||
371 | |||
372 | int setup_signal_stack_sc(unsigned long stack_top, int sig, | ||
373 | struct k_sigaction *ka, struct pt_regs *regs, | ||
374 | sigset_t *mask) | ||
375 | { | ||
376 | struct sigframe __user *frame; | ||
377 | void __user *restorer; | ||
378 | int err = 0; | ||
379 | |||
380 | /* This is the same calculation as i386 - ((sp + 4) & 15) == 0 */ | ||
381 | stack_top = ((stack_top + 4) & -16UL) - 4; | ||
382 | frame = (struct sigframe __user *) stack_top - 1; | ||
383 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
384 | return 1; | ||
385 | |||
386 | restorer = frame->retcode; | ||
387 | if (ka->sa.sa_flags & SA_RESTORER) | ||
388 | restorer = ka->sa.sa_restorer; | ||
389 | |||
390 | err |= __put_user(restorer, &frame->pretcode); | ||
391 | err |= __put_user(sig, &frame->sig); | ||
392 | err |= copy_sc_to_user(&frame->sc, &frame->fpstate, regs, mask->sig[0]); | ||
393 | if (_NSIG_WORDS > 1) | ||
394 | err |= __copy_to_user(&frame->extramask, &mask->sig[1], | ||
395 | sizeof(frame->extramask)); | ||
396 | |||
397 | /* | ||
398 | * This is popl %eax ; movl $,%eax ; int $0x80 | ||
399 | * | ||
400 | * WE DO NOT USE IT ANY MORE! It's only left here for historical | ||
401 | * reasons and because gdb uses it as a signature to notice | ||
402 | * signal handler stack frames. | ||
403 | */ | ||
404 | err |= __put_user(0xb858, (short __user *)(frame->retcode+0)); | ||
405 | err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2)); | ||
406 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); | ||
407 | |||
408 | if (err) | ||
409 | return err; | ||
410 | |||
411 | PT_REGS_SP(regs) = (unsigned long) frame; | ||
412 | PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; | ||
413 | PT_REGS_EAX(regs) = (unsigned long) sig; | ||
414 | PT_REGS_EDX(regs) = (unsigned long) 0; | ||
415 | PT_REGS_ECX(regs) = (unsigned long) 0; | ||
416 | |||
417 | if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) | ||
418 | ptrace_notify(SIGTRAP); | ||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | int setup_signal_stack_si(unsigned long stack_top, int sig, | ||
423 | struct k_sigaction *ka, struct pt_regs *regs, | ||
424 | siginfo_t *info, sigset_t *mask) | ||
425 | { | ||
426 | struct rt_sigframe __user *frame; | ||
427 | void __user *restorer; | ||
428 | int err = 0; | ||
429 | |||
430 | stack_top &= -8UL; | ||
431 | frame = (struct rt_sigframe __user *) stack_top - 1; | ||
432 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
433 | return 1; | ||
434 | |||
435 | restorer = frame->retcode; | ||
436 | if (ka->sa.sa_flags & SA_RESTORER) | ||
437 | restorer = ka->sa.sa_restorer; | ||
438 | |||
439 | err |= __put_user(restorer, &frame->pretcode); | ||
440 | err |= __put_user(sig, &frame->sig); | ||
441 | err |= __put_user(&frame->info, &frame->pinfo); | ||
442 | err |= __put_user(&frame->uc, &frame->puc); | ||
443 | err |= copy_siginfo_to_user(&frame->info, info); | ||
444 | err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask, | ||
445 | PT_REGS_SP(regs)); | ||
446 | |||
447 | /* | ||
448 | * This is movl $,%eax ; int $0x80 | ||
449 | * | ||
450 | * WE DO NOT USE IT ANY MORE! It's only left here for historical | ||
451 | * reasons and because gdb uses it as a signature to notice | ||
452 | * signal handler stack frames. | ||
453 | */ | ||
454 | err |= __put_user(0xb8, (char __user *)(frame->retcode+0)); | ||
455 | err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1)); | ||
456 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); | ||
457 | |||
458 | if (err) | ||
459 | return err; | ||
460 | |||
461 | PT_REGS_SP(regs) = (unsigned long) frame; | ||
462 | PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; | ||
463 | PT_REGS_EAX(regs) = (unsigned long) sig; | ||
464 | PT_REGS_EDX(regs) = (unsigned long) &frame->info; | ||
465 | PT_REGS_ECX(regs) = (unsigned long) &frame->uc; | ||
466 | |||
467 | if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) | ||
468 | ptrace_notify(SIGTRAP); | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | long sys_sigreturn(struct pt_regs *regs) | ||
473 | { | ||
474 | unsigned long sp = PT_REGS_SP(¤t->thread.regs); | ||
475 | struct sigframe __user *frame = (struct sigframe __user *)(sp - 8); | ||
476 | sigset_t set; | ||
477 | struct sigcontext __user *sc = &frame->sc; | ||
478 | unsigned long __user *oldmask = &sc->oldmask; | ||
479 | unsigned long __user *extramask = frame->extramask; | ||
480 | int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); | ||
481 | |||
482 | if (copy_from_user(&set.sig[0], oldmask, sizeof(set.sig[0])) || | ||
483 | copy_from_user(&set.sig[1], extramask, sig_size)) | ||
484 | goto segfault; | ||
485 | |||
486 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
487 | set_current_blocked(&set); | ||
488 | |||
489 | if (copy_sc_from_user(¤t->thread.regs, sc)) | ||
490 | goto segfault; | ||
491 | |||
492 | /* Avoid ERESTART handling */ | ||
493 | PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; | ||
494 | return PT_REGS_SYSCALL_RET(¤t->thread.regs); | ||
495 | |||
496 | segfault: | ||
497 | force_sig(SIGSEGV, current); | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | #else | ||
502 | |||
503 | struct rt_sigframe | ||
504 | { | ||
505 | char __user *pretcode; | ||
506 | struct ucontext uc; | ||
507 | struct siginfo info; | ||
508 | struct _fpstate fpstate; | ||
509 | }; | ||
510 | |||
511 | int setup_signal_stack_si(unsigned long stack_top, int sig, | ||
512 | struct k_sigaction *ka, struct pt_regs * regs, | ||
513 | siginfo_t *info, sigset_t *set) | ||
514 | { | ||
515 | struct rt_sigframe __user *frame; | ||
516 | int err = 0; | ||
517 | struct task_struct *me = current; | ||
518 | |||
519 | frame = (struct rt_sigframe __user *) | ||
520 | round_down(stack_top - sizeof(struct rt_sigframe), 16); | ||
521 | /* Subtract 128 for a red zone and 8 for proper alignment */ | ||
522 | frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8); | ||
523 | |||
524 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
525 | goto out; | ||
526 | |||
527 | if (ka->sa.sa_flags & SA_SIGINFO) { | ||
528 | err |= copy_siginfo_to_user(&frame->info, info); | ||
529 | if (err) | ||
530 | goto out; | ||
531 | } | ||
532 | |||
533 | /* Create the ucontext. */ | ||
534 | err |= __put_user(0, &frame->uc.uc_flags); | ||
535 | err |= __put_user(0, &frame->uc.uc_link); | ||
536 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | ||
537 | err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)), | ||
538 | &frame->uc.uc_stack.ss_flags); | ||
539 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
540 | err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs, | ||
541 | set->sig[0]); | ||
542 | err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate); | ||
543 | if (sizeof(*set) == 16) { | ||
544 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); | ||
545 | __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); | ||
546 | } | ||
547 | else | ||
548 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, | ||
549 | sizeof(*set)); | ||
550 | |||
551 | /* | ||
552 | * Set up to return from userspace. If provided, use a stub | ||
553 | * already in userspace. | ||
554 | */ | ||
555 | /* x86-64 should always use SA_RESTORER. */ | ||
556 | if (ka->sa.sa_flags & SA_RESTORER) | ||
557 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | ||
558 | else | ||
559 | /* could use a vstub here */ | ||
560 | return err; | ||
561 | |||
562 | if (err) | ||
563 | return err; | ||
564 | |||
565 | /* Set up registers for signal handler */ | ||
566 | { | ||
567 | struct exec_domain *ed = current_thread_info()->exec_domain; | ||
568 | if (unlikely(ed && ed->signal_invmap && sig < 32)) | ||
569 | sig = ed->signal_invmap[sig]; | ||
570 | } | ||
571 | |||
572 | PT_REGS_SP(regs) = (unsigned long) frame; | ||
573 | PT_REGS_RDI(regs) = sig; | ||
574 | /* In case the signal handler was declared without prototypes */ | ||
575 | PT_REGS_RAX(regs) = 0; | ||
576 | |||
577 | /* | ||
578 | * This also works for non SA_SIGINFO handlers because they expect the | ||
579 | * next argument after the signal number on the stack. | ||
580 | */ | ||
581 | PT_REGS_RSI(regs) = (unsigned long) &frame->info; | ||
582 | PT_REGS_RDX(regs) = (unsigned long) &frame->uc; | ||
583 | PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; | ||
584 | out: | ||
585 | return err; | ||
586 | } | ||
587 | #endif | ||
588 | |||
589 | long sys_rt_sigreturn(struct pt_regs *regs) | ||
590 | { | ||
591 | unsigned long sp = PT_REGS_SP(¤t->thread.regs); | ||
592 | struct rt_sigframe __user *frame = | ||
593 | (struct rt_sigframe __user *)(sp - sizeof(long)); | ||
594 | struct ucontext __user *uc = &frame->uc; | ||
595 | sigset_t set; | ||
596 | |||
597 | if (copy_from_user(&set, &uc->uc_sigmask, sizeof(set))) | ||
598 | goto segfault; | ||
599 | |||
600 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
601 | set_current_blocked(&set); | ||
602 | |||
603 | if (copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) | ||
604 | goto segfault; | ||
605 | |||
606 | /* Avoid ERESTART handling */ | ||
607 | PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; | ||
608 | return PT_REGS_SYSCALL_RET(¤t->thread.regs); | ||
609 | |||
610 | segfault: | ||
611 | force_sig(SIGSEGV, current); | ||
612 | return 0; | ||
613 | } | ||
614 | |||
615 | #ifdef CONFIG_X86_32 | ||
616 | long ptregs_sigreturn(void) | ||
617 | { | ||
618 | return sys_sigreturn(NULL); | ||
619 | } | ||
620 | long ptregs_rt_sigreturn(void) | ||
621 | { | ||
622 | return sys_rt_sigreturn(NULL); | ||
623 | } | ||
624 | #endif | ||