aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/kernel')
-rw-r--r--arch/m68k/kernel/signal.c173
1 files changed, 61 insertions, 112 deletions
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index 16ea319d1ed5..d5f4a82515f3 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -286,36 +286,10 @@ out:
286 return err; 286 return err;
287} 287}
288 288
289static inline int 289static int mangle_kernel_stack(struct pt_regs *regs, int formatvec,
290restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp, 290 void __user *fp)
291 int *pd0)
292{ 291{
293 int fsize, formatvec; 292 int fsize = frame_extra_sizes[formatvec >> 12];
294 struct sigcontext context;
295 int err;
296
297 /* Always make any pending restarted system calls return -EINTR */
298 current_thread_info()->restart_block.fn = do_no_restart_syscall;
299
300 /* get previous context */
301 if (copy_from_user(&context, usc, sizeof(context)))
302 goto badframe;
303
304 /* restore passed registers */
305 regs->d1 = context.sc_d1;
306 regs->a0 = context.sc_a0;
307 regs->a1 = context.sc_a1;
308 regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
309 regs->pc = context.sc_pc;
310 regs->orig_d0 = -1; /* disable syscall checks */
311 wrusp(context.sc_usp);
312 formatvec = context.sc_formatvec;
313 regs->format = formatvec >> 12;
314 regs->vector = formatvec & 0xfff;
315
316 err = restore_fpu_state(&context);
317
318 fsize = frame_extra_sizes[regs->format];
319 if (fsize < 0) { 293 if (fsize < 0) {
320 /* 294 /*
321 * user process trying to return with weird frame format 295 * user process trying to return with weird frame format
@@ -323,16 +297,22 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __u
323#ifdef DEBUG 297#ifdef DEBUG
324 printk("user process returning with weird frame format\n"); 298 printk("user process returning with weird frame format\n");
325#endif 299#endif
326 goto badframe; 300 return 1;
327 } 301 }
302 if (!fsize) {
303 regs->format = formatvec >> 12;
304 regs->vector = formatvec & 0xfff;
305 } else {
306 struct switch_stack *sw = (struct switch_stack *)regs - 1;
307 unsigned long buf[fsize / 2]; /* yes, twice as much */
328 308
329 /* OK. Make room on the supervisor stack for the extra junk, 309 /* that'll make sure that expansion won't crap over data */
330 * if necessary. 310 if (copy_from_user(buf + fsize / 4, fp, fsize))
331 */ 311 return 1;
332 312
333 if (fsize) { 313 /* point of no return */
334 struct switch_stack *sw = (struct switch_stack *)regs - 1; 314 regs->format = formatvec >> 12;
335 regs->d0 = context.sc_d0; 315 regs->vector = formatvec & 0xfff;
336#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) 316#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
337 __asm__ __volatile__ 317 __asm__ __volatile__
338 (" movel %0,%/a0\n\t" 318 (" movel %0,%/a0\n\t"
@@ -344,30 +324,50 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __u
344 " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ 324 " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
345 " lsrl #2,%1\n\t" 325 " lsrl #2,%1\n\t"
346 " subql #1,%1\n\t" 326 " subql #1,%1\n\t"
347 "2: movesl %4@+,%2\n\t" 327 /* copy to the gap we'd made */
348 "3: movel %2,%/a0@+\n\t" 328 "2: movel %4@+,%/a0@+\n\t"
349 " dbra %1,2b\n\t" 329 " dbra %1,2b\n\t"
350 " bral ret_from_signal\n" 330 " bral ret_from_signal\n"
351 "4:\n"
352 ".section __ex_table,\"a\"\n"
353 " .align 4\n"
354 " .long 2b,4b\n"
355 " .long 3b,4b\n"
356 ".previous"
357 : /* no outputs, it doesn't ever return */ 331 : /* no outputs, it doesn't ever return */
358 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), 332 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
359 "n" (frame_offset), "a" (fp) 333 "n" (frame_offset), "a" (buf + fsize/4)
360 : "a0"); 334 : "a0");
361#undef frame_offset 335#undef frame_offset
362 /*
363 * If we ever get here an exception occurred while
364 * building the above stack-frame.
365 */
366 goto badframe;
367 } 336 }
337 return 0;
338}
368 339
369 *pd0 = context.sc_d0; 340static inline int
370 return err; 341restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp)
342{
343 int formatvec;
344 struct sigcontext context;
345 int err;
346
347 /* Always make any pending restarted system calls return -EINTR */
348 current_thread_info()->restart_block.fn = do_no_restart_syscall;
349
350 /* get previous context */
351 if (copy_from_user(&context, usc, sizeof(context)))
352 goto badframe;
353
354 /* restore passed registers */
355 regs->d0 = context.sc_d0;
356 regs->d1 = context.sc_d1;
357 regs->a0 = context.sc_a0;
358 regs->a1 = context.sc_a1;
359 regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
360 regs->pc = context.sc_pc;
361 regs->orig_d0 = -1; /* disable syscall checks */
362 wrusp(context.sc_usp);
363 formatvec = context.sc_formatvec;
364
365 err = restore_fpu_state(&context);
366
367 if (err || mangle_kernel_stack(regs, formatvec, fp))
368 goto badframe;
369
370 return 0;
371 371
372badframe: 372badframe:
373 return 1; 373 return 1;
@@ -375,9 +375,9 @@ badframe:
375 375
376static inline int 376static inline int
377rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, 377rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
378 struct ucontext __user *uc, int *pd0) 378 struct ucontext __user *uc)
379{ 379{
380 int fsize, temp; 380 int temp;
381 greg_t __user *gregs = uc->uc_mcontext.gregs; 381 greg_t __user *gregs = uc->uc_mcontext.gregs;
382 unsigned long usp; 382 unsigned long usp;
383 int err; 383 int err;
@@ -411,65 +411,16 @@ rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
411 regs->sr = (regs->sr & 0xff00) | (temp & 0xff); 411 regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
412 regs->orig_d0 = -1; /* disable syscall checks */ 412 regs->orig_d0 = -1; /* disable syscall checks */
413 err |= __get_user(temp, &uc->uc_formatvec); 413 err |= __get_user(temp, &uc->uc_formatvec);
414 regs->format = temp >> 12;
415 regs->vector = temp & 0xfff;
416 414
417 err |= rt_restore_fpu_state(uc); 415 err |= rt_restore_fpu_state(uc);
418 416
419 if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) 417 if (err || do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
420 goto badframe; 418 goto badframe;
421 419
422 fsize = frame_extra_sizes[regs->format]; 420 if (mangle_kernel_stack(regs, temp, &uc->uc_extra))
423 if (fsize < 0) {
424 /*
425 * user process trying to return with weird frame format
426 */
427#ifdef DEBUG
428 printk("user process returning with weird frame format\n");
429#endif
430 goto badframe; 421 goto badframe;
431 }
432 422
433 /* OK. Make room on the supervisor stack for the extra junk, 423 return 0;
434 * if necessary.
435 */
436
437 if (fsize) {
438#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
439 __asm__ __volatile__
440 (" movel %0,%/a0\n\t"
441 " subl %1,%/a0\n\t" /* make room on stack */
442 " movel %/a0,%/sp\n\t" /* set stack pointer */
443 /* move switch_stack and pt_regs */
444 "1: movel %0@+,%/a0@+\n\t"
445 " dbra %2,1b\n\t"
446 " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
447 " lsrl #2,%1\n\t"
448 " subql #1,%1\n\t"
449 "2: movesl %4@+,%2\n\t"
450 "3: movel %2,%/a0@+\n\t"
451 " dbra %1,2b\n\t"
452 " bral ret_from_signal\n"
453 "4:\n"
454 ".section __ex_table,\"a\"\n"
455 " .align 4\n"
456 " .long 2b,4b\n"
457 " .long 3b,4b\n"
458 ".previous"
459 : /* no outputs, it doesn't ever return */
460 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
461 "n" (frame_offset), "a" (&uc->uc_extra)
462 : "a0");
463#undef frame_offset
464 /*
465 * If we ever get here an exception occurred while
466 * building the above stack-frame.
467 */
468 goto badframe;
469 }
470
471 *pd0 = regs->d0;
472 return err;
473 424
474badframe: 425badframe:
475 return 1; 426 return 1;
@@ -482,7 +433,6 @@ asmlinkage int do_sigreturn(unsigned long __unused)
482 unsigned long usp = rdusp(); 433 unsigned long usp = rdusp();
483 struct sigframe __user *frame = (struct sigframe __user *)(usp - 4); 434 struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
484 sigset_t set; 435 sigset_t set;
485 int d0;
486 436
487 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 437 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
488 goto badframe; 438 goto badframe;
@@ -496,9 +446,9 @@ asmlinkage int do_sigreturn(unsigned long __unused)
496 current->blocked = set; 446 current->blocked = set;
497 recalc_sigpending(); 447 recalc_sigpending();
498 448
499 if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0)) 449 if (restore_sigcontext(regs, &frame->sc, frame + 1))
500 goto badframe; 450 goto badframe;
501 return d0; 451 return regs->d0;
502 452
503badframe: 453badframe:
504 force_sig(SIGSEGV, current); 454 force_sig(SIGSEGV, current);
@@ -512,7 +462,6 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused)
512 unsigned long usp = rdusp(); 462 unsigned long usp = rdusp();
513 struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4); 463 struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4);
514 sigset_t set; 464 sigset_t set;
515 int d0;
516 465
517 if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 466 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
518 goto badframe; 467 goto badframe;
@@ -523,9 +472,9 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused)
523 current->blocked = set; 472 current->blocked = set;
524 recalc_sigpending(); 473 recalc_sigpending();
525 474
526 if (rt_restore_ucontext(regs, sw, &frame->uc, &d0)) 475 if (rt_restore_ucontext(regs, sw, &frame->uc))
527 goto badframe; 476 goto badframe;
528 return d0; 477 return regs->d0;
529 478
530badframe: 479badframe:
531 force_sig(SIGSEGV, current); 480 force_sig(SIGSEGV, current);