diff options
author | Hiroshi Shimamoto <h-shimamoto@ct.jp.nec.com> | 2008-11-24 21:23:12 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-11-25 23:11:53 -0500 |
commit | bfeb91a9435889ef4fe7bfbb4b673f625e69e790 (patch) | |
tree | 904f16d0eba56b7812b1462de6bc28df6c70371f /arch/x86/kernel/signal_64.c | |
parent | 2601657d223d82053d4e1fe1063091401e6b860a (diff) |
x86: signal: cosmetic unification of __setup_sigframe() and __setup_rt_sigframe()
Impact: cleanup
Add #ifdef directive to unify __setup_sigframe() and __setup_rt_sigframe().
Move them after {setup|restore}_sigcontext() declaration.
Signed-off-by: Hiroshi Shimamoto <h-shimamoto@ct.jp.nec.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/signal_64.c')
-rw-r--r-- | arch/x86/kernel/signal_64.c | 309 |
1 files changed, 256 insertions, 53 deletions
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index 771c8fcc8b0d..2da7e6e60807 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c | |||
@@ -174,80 +174,212 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, | |||
174 | return err; | 174 | return err; |
175 | } | 175 | } |
176 | 176 | ||
177 | /* | ||
178 | * Set up a signal frame. | ||
179 | */ | ||
177 | #ifdef CONFIG_X86_32 | 180 | #ifdef CONFIG_X86_32 |
178 | asmlinkage int sys_sigaltstack(unsigned long bx) | 181 | static const struct { |
182 | u16 poplmovl; | ||
183 | u32 val; | ||
184 | u16 int80; | ||
185 | } __attribute__((packed)) retcode = { | ||
186 | 0xb858, /* popl %eax; movl $..., %eax */ | ||
187 | __NR_sigreturn, | ||
188 | 0x80cd, /* int $0x80 */ | ||
189 | }; | ||
190 | |||
191 | static const struct { | ||
192 | u8 movl; | ||
193 | u32 val; | ||
194 | u16 int80; | ||
195 | u8 pad; | ||
196 | } __attribute__((packed)) rt_retcode = { | ||
197 | 0xb8, /* movl $..., %eax */ | ||
198 | __NR_rt_sigreturn, | ||
199 | 0x80cd, /* int $0x80 */ | ||
200 | 0 | ||
201 | }; | ||
202 | |||
203 | /* | ||
204 | * Determine which stack to use.. | ||
205 | */ | ||
206 | static inline void __user * | ||
207 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | ||
208 | void **fpstate) | ||
179 | { | 209 | { |
210 | unsigned long sp; | ||
211 | |||
212 | /* Default to using normal stack */ | ||
213 | sp = regs->sp; | ||
214 | |||
180 | /* | 215 | /* |
181 | * This is needed to make gcc realize it doesn't own the | 216 | * If we are on the alternate signal stack and would overflow it, don't. |
182 | * "struct pt_regs" | 217 | * Return an always-bogus address instead so we will die with SIGSEGV. |
183 | */ | 218 | */ |
184 | struct pt_regs *regs = (struct pt_regs *)&bx; | 219 | if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) |
185 | const stack_t __user *uss = (const stack_t __user *)bx; | 220 | return (void __user *) -1L; |
186 | stack_t __user *uoss = (stack_t __user *)regs->cx; | ||
187 | 221 | ||
188 | return do_sigaltstack(uss, uoss, regs->sp); | 222 | /* This is the X/Open sanctioned signal stack switching. */ |
189 | } | 223 | if (ka->sa.sa_flags & SA_ONSTACK) { |
190 | #else /* !CONFIG_X86_32 */ | 224 | if (sas_ss_flags(sp) == 0) |
191 | asmlinkage long | 225 | sp = current->sas_ss_sp + current->sas_ss_size; |
192 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 226 | } else { |
193 | struct pt_regs *regs) | 227 | /* This is the legacy signal stack switching. */ |
194 | { | 228 | if ((regs->ss & 0xffff) != __USER_DS && |
195 | return do_sigaltstack(uss, uoss, regs->sp); | 229 | !(ka->sa.sa_flags & SA_RESTORER) && |
230 | ka->sa.sa_restorer) | ||
231 | sp = (unsigned long) ka->sa.sa_restorer; | ||
232 | } | ||
233 | |||
234 | if (used_math()) { | ||
235 | sp = sp - sig_xstate_size; | ||
236 | *fpstate = (struct _fpstate *) sp; | ||
237 | if (save_i387_xstate(*fpstate) < 0) | ||
238 | return (void __user *)-1L; | ||
239 | } | ||
240 | |||
241 | sp -= frame_size; | ||
242 | /* | ||
243 | * Align the stack pointer according to the i386 ABI, | ||
244 | * i.e. so that on function entry ((sp + 4) & 15) == 0. | ||
245 | */ | ||
246 | sp = ((sp + 4) & -16ul) - 4; | ||
247 | |||
248 | return (void __user *) sp; | ||
196 | } | 249 | } |
197 | #endif /* CONFIG_X86_32 */ | ||
198 | 250 | ||
199 | /* | 251 | static int |
200 | * Do a signal return; undo the signal stack. | 252 | __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, |
201 | */ | 253 | struct pt_regs *regs) |
202 | static long do_rt_sigreturn(struct pt_regs *regs) | ||
203 | { | 254 | { |
204 | struct rt_sigframe __user *frame; | 255 | struct sigframe __user *frame; |
205 | unsigned long ax; | 256 | void __user *restorer; |
206 | sigset_t set; | 257 | int err = 0; |
258 | void __user *fpstate = NULL; | ||
207 | 259 | ||
208 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); | 260 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
209 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
210 | goto badframe; | ||
211 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
212 | goto badframe; | ||
213 | 261 | ||
214 | sigdelsetmask(&set, ~_BLOCKABLE); | 262 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
215 | spin_lock_irq(¤t->sighand->siglock); | 263 | return -EFAULT; |
216 | current->blocked = set; | ||
217 | recalc_sigpending(); | ||
218 | spin_unlock_irq(¤t->sighand->siglock); | ||
219 | 264 | ||
220 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) | 265 | if (__put_user(sig, &frame->sig)) |
221 | goto badframe; | 266 | return -EFAULT; |
222 | 267 | ||
223 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) | 268 | if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0])) |
224 | goto badframe; | 269 | return -EFAULT; |
225 | 270 | ||
226 | return ax; | 271 | if (_NSIG_WORDS > 1) { |
272 | if (__copy_to_user(&frame->extramask, &set->sig[1], | ||
273 | sizeof(frame->extramask))) | ||
274 | return -EFAULT; | ||
275 | } | ||
276 | |||
277 | if (current->mm->context.vdso) | ||
278 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, sigreturn); | ||
279 | else | ||
280 | restorer = &frame->retcode; | ||
281 | if (ka->sa.sa_flags & SA_RESTORER) | ||
282 | restorer = ka->sa.sa_restorer; | ||
283 | |||
284 | /* Set up to return from userspace. */ | ||
285 | err |= __put_user(restorer, &frame->pretcode); | ||
286 | |||
287 | /* | ||
288 | * This is popl %eax ; movl $__NR_sigreturn, %eax ; int $0x80 | ||
289 | * | ||
290 | * WE DO NOT USE IT ANY MORE! It's only left here for historical | ||
291 | * reasons and because gdb uses it as a signature to notice | ||
292 | * signal handler stack frames. | ||
293 | */ | ||
294 | err |= __put_user(*((u64 *)&retcode), (u64 *)frame->retcode); | ||
295 | |||
296 | if (err) | ||
297 | return -EFAULT; | ||
298 | |||
299 | /* Set up registers for signal handler */ | ||
300 | regs->sp = (unsigned long)frame; | ||
301 | regs->ip = (unsigned long)ka->sa.sa_handler; | ||
302 | regs->ax = (unsigned long)sig; | ||
303 | regs->dx = 0; | ||
304 | regs->cx = 0; | ||
305 | |||
306 | regs->ds = __USER_DS; | ||
307 | regs->es = __USER_DS; | ||
308 | regs->ss = __USER_DS; | ||
309 | regs->cs = __USER_CS; | ||
227 | 310 | ||
228 | badframe: | ||
229 | signal_fault(regs, frame, "rt_sigreturn"); | ||
230 | return 0; | 311 | return 0; |
231 | } | 312 | } |
232 | 313 | ||
233 | #ifdef CONFIG_X86_32 | 314 | static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
234 | asmlinkage int sys_rt_sigreturn(unsigned long __unused) | 315 | sigset_t *set, struct pt_regs *regs) |
235 | { | 316 | { |
236 | struct pt_regs *regs = (struct pt_regs *)&__unused; | 317 | struct rt_sigframe __user *frame; |
318 | void __user *restorer; | ||
319 | int err = 0; | ||
320 | void __user *fpstate = NULL; | ||
237 | 321 | ||
238 | return do_rt_sigreturn(regs); | 322 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
239 | } | ||
240 | #else /* !CONFIG_X86_32 */ | ||
241 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | ||
242 | { | ||
243 | return do_rt_sigreturn(regs); | ||
244 | } | ||
245 | #endif /* CONFIG_X86_32 */ | ||
246 | 323 | ||
247 | /* | 324 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
248 | * Set up a signal frame. | 325 | return -EFAULT; |
249 | */ | 326 | |
327 | err |= __put_user(sig, &frame->sig); | ||
328 | err |= __put_user(&frame->info, &frame->pinfo); | ||
329 | err |= __put_user(&frame->uc, &frame->puc); | ||
330 | err |= copy_siginfo_to_user(&frame->info, info); | ||
331 | if (err) | ||
332 | return -EFAULT; | ||
333 | |||
334 | /* Create the ucontext. */ | ||
335 | if (cpu_has_xsave) | ||
336 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
337 | else | ||
338 | err |= __put_user(0, &frame->uc.uc_flags); | ||
339 | err |= __put_user(0, &frame->uc.uc_link); | ||
340 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | ||
341 | err |= __put_user(sas_ss_flags(regs->sp), | ||
342 | &frame->uc.uc_stack.ss_flags); | ||
343 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
344 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | ||
345 | regs, set->sig[0]); | ||
346 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
347 | if (err) | ||
348 | return -EFAULT; | ||
349 | |||
350 | /* Set up to return from userspace. */ | ||
351 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); | ||
352 | if (ka->sa.sa_flags & SA_RESTORER) | ||
353 | restorer = ka->sa.sa_restorer; | ||
354 | err |= __put_user(restorer, &frame->pretcode); | ||
355 | |||
356 | /* | ||
357 | * This is movl $__NR_rt_sigreturn, %ax ; int $0x80 | ||
358 | * | ||
359 | * WE DO NOT USE IT ANY MORE! It's only left here for historical | ||
360 | * reasons and because gdb uses it as a signature to notice | ||
361 | * signal handler stack frames. | ||
362 | */ | ||
363 | err |= __put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode); | ||
250 | 364 | ||
365 | if (err) | ||
366 | return -EFAULT; | ||
367 | |||
368 | /* Set up registers for signal handler */ | ||
369 | regs->sp = (unsigned long)frame; | ||
370 | regs->ip = (unsigned long)ka->sa.sa_handler; | ||
371 | regs->ax = (unsigned long)sig; | ||
372 | regs->dx = (unsigned long)&frame->info; | ||
373 | regs->cx = (unsigned long)&frame->uc; | ||
374 | |||
375 | regs->ds = __USER_DS; | ||
376 | regs->es = __USER_DS; | ||
377 | regs->ss = __USER_DS; | ||
378 | regs->cs = __USER_CS; | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | #else /* !CONFIG_X86_32 */ | ||
251 | /* | 383 | /* |
252 | * Determine which stack to use.. | 384 | * Determine which stack to use.. |
253 | */ | 385 | */ |
@@ -337,6 +469,77 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
337 | 469 | ||
338 | return 0; | 470 | return 0; |
339 | } | 471 | } |
472 | #endif /* CONFIG_X86_32 */ | ||
473 | |||
474 | #ifdef CONFIG_X86_32 | ||
475 | asmlinkage int sys_sigaltstack(unsigned long bx) | ||
476 | { | ||
477 | /* | ||
478 | * This is needed to make gcc realize it doesn't own the | ||
479 | * "struct pt_regs" | ||
480 | */ | ||
481 | struct pt_regs *regs = (struct pt_regs *)&bx; | ||
482 | const stack_t __user *uss = (const stack_t __user *)bx; | ||
483 | stack_t __user *uoss = (stack_t __user *)regs->cx; | ||
484 | |||
485 | return do_sigaltstack(uss, uoss, regs->sp); | ||
486 | } | ||
487 | #else /* !CONFIG_X86_32 */ | ||
488 | asmlinkage long | ||
489 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | ||
490 | struct pt_regs *regs) | ||
491 | { | ||
492 | return do_sigaltstack(uss, uoss, regs->sp); | ||
493 | } | ||
494 | #endif /* CONFIG_X86_32 */ | ||
495 | |||
496 | /* | ||
497 | * Do a signal return; undo the signal stack. | ||
498 | */ | ||
499 | static long do_rt_sigreturn(struct pt_regs *regs) | ||
500 | { | ||
501 | struct rt_sigframe __user *frame; | ||
502 | unsigned long ax; | ||
503 | sigset_t set; | ||
504 | |||
505 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); | ||
506 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
507 | goto badframe; | ||
508 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
509 | goto badframe; | ||
510 | |||
511 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
512 | spin_lock_irq(¤t->sighand->siglock); | ||
513 | current->blocked = set; | ||
514 | recalc_sigpending(); | ||
515 | spin_unlock_irq(¤t->sighand->siglock); | ||
516 | |||
517 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) | ||
518 | goto badframe; | ||
519 | |||
520 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) | ||
521 | goto badframe; | ||
522 | |||
523 | return ax; | ||
524 | |||
525 | badframe: | ||
526 | signal_fault(regs, frame, "rt_sigreturn"); | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | #ifdef CONFIG_X86_32 | ||
531 | asmlinkage int sys_rt_sigreturn(unsigned long __unused) | ||
532 | { | ||
533 | struct pt_regs *regs = (struct pt_regs *)&__unused; | ||
534 | |||
535 | return do_rt_sigreturn(regs); | ||
536 | } | ||
537 | #else /* !CONFIG_X86_32 */ | ||
538 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | ||
539 | { | ||
540 | return do_rt_sigreturn(regs); | ||
541 | } | ||
542 | #endif /* CONFIG_X86_32 */ | ||
340 | 543 | ||
341 | /* | 544 | /* |
342 | * OK, we're invoking a handler | 545 | * OK, we're invoking a handler |