diff options
Diffstat (limited to 'arch/mips/kernel/signal32.c')
| -rw-r--r-- | arch/mips/kernel/signal32.c | 114 |
1 files changed, 94 insertions, 20 deletions
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 8ddfbd8d425a..dbe821303125 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | * Copyright (C) 1994 - 2000 Ralf Baechle | 7 | * Copyright (C) 1994 - 2000 Ralf Baechle |
| 8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. | 8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. |
| 9 | */ | 9 | */ |
| 10 | #include <linux/cache.h> | ||
| 10 | #include <linux/sched.h> | 11 | #include <linux/sched.h> |
| 11 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
| 12 | #include <linux/smp.h> | 13 | #include <linux/smp.h> |
| @@ -21,6 +22,7 @@ | |||
| 21 | #include <linux/suspend.h> | 22 | #include <linux/suspend.h> |
| 22 | #include <linux/compiler.h> | 23 | #include <linux/compiler.h> |
| 23 | 24 | ||
| 25 | #include <asm/abi.h> | ||
| 24 | #include <asm/asm.h> | 26 | #include <asm/asm.h> |
| 25 | #include <linux/bitops.h> | 27 | #include <linux/bitops.h> |
| 26 | #include <asm/cacheflush.h> | 28 | #include <asm/cacheflush.h> |
| @@ -29,6 +31,7 @@ | |||
| 29 | #include <asm/ucontext.h> | 31 | #include <asm/ucontext.h> |
| 30 | #include <asm/system.h> | 32 | #include <asm/system.h> |
| 31 | #include <asm/fpu.h> | 33 | #include <asm/fpu.h> |
| 34 | #include <asm/war.h> | ||
| 32 | 35 | ||
| 33 | #define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) | 36 | #define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) |
| 34 | 37 | ||
| @@ -76,8 +79,10 @@ typedef struct compat_siginfo { | |||
| 76 | 79 | ||
| 77 | /* POSIX.1b timers */ | 80 | /* POSIX.1b timers */ |
| 78 | struct { | 81 | struct { |
| 79 | unsigned int _timer1; | 82 | timer_t _tid; /* timer id */ |
| 80 | unsigned int _timer2; | 83 | int _overrun; /* overrun count */ |
| 84 | compat_sigval_t _sigval;/* same as below */ | ||
| 85 | int _sys_private; /* not to be passed to user */ | ||
| 81 | } _timer; | 86 | } _timer; |
| 82 | 87 | ||
| 83 | /* POSIX.1b signals */ | 88 | /* POSIX.1b signals */ |
| @@ -259,11 +264,12 @@ asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act, | |||
| 259 | 264 | ||
| 260 | if (act) { | 265 | if (act) { |
| 261 | old_sigset_t mask; | 266 | old_sigset_t mask; |
| 267 | s32 handler; | ||
| 262 | 268 | ||
| 263 | if (!access_ok(VERIFY_READ, act, sizeof(*act))) | 269 | if (!access_ok(VERIFY_READ, act, sizeof(*act))) |
| 264 | return -EFAULT; | 270 | return -EFAULT; |
| 265 | err |= __get_user((u32)(u64)new_ka.sa.sa_handler, | 271 | err |= __get_user(handler, &act->sa_handler); |
| 266 | &act->sa_handler); | 272 | new_ka.sa.sa_handler = (void*)(s64)handler; |
| 267 | err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); | 273 | err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); |
| 268 | err |= __get_user(mask, &act->sa_mask.sig[0]); | 274 | err |= __get_user(mask, &act->sa_mask.sig[0]); |
| 269 | if (err) | 275 | if (err) |
| @@ -331,8 +337,9 @@ asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs) | |||
| 331 | 337 | ||
| 332 | static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc) | 338 | static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc) |
| 333 | { | 339 | { |
| 340 | u32 used_math; | ||
| 334 | int err = 0; | 341 | int err = 0; |
| 335 | __u32 used_math; | 342 | s32 treg; |
| 336 | 343 | ||
| 337 | /* Always make any pending restarted system calls return -EINTR */ | 344 | /* Always make any pending restarted system calls return -EINTR */ |
| 338 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 345 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
| @@ -340,6 +347,15 @@ static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc) | |||
| 340 | err |= __get_user(regs->cp0_epc, &sc->sc_pc); | 347 | err |= __get_user(regs->cp0_epc, &sc->sc_pc); |
| 341 | err |= __get_user(regs->hi, &sc->sc_mdhi); | 348 | err |= __get_user(regs->hi, &sc->sc_mdhi); |
| 342 | err |= __get_user(regs->lo, &sc->sc_mdlo); | 349 | err |= __get_user(regs->lo, &sc->sc_mdlo); |
| 350 | if (cpu_has_dsp) { | ||
| 351 | err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); | ||
| 352 | err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); | ||
| 353 | err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); | ||
| 354 | err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); | ||
| 355 | err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); | ||
| 356 | err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); | ||
| 357 | err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); | ||
| 358 | } | ||
| 343 | 359 | ||
| 344 | #define restore_gp_reg(i) do { \ | 360 | #define restore_gp_reg(i) do { \ |
| 345 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ | 361 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ |
| @@ -378,16 +394,30 @@ static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc) | |||
| 378 | 394 | ||
| 379 | struct sigframe { | 395 | struct sigframe { |
| 380 | u32 sf_ass[4]; /* argument save space for o32 */ | 396 | u32 sf_ass[4]; /* argument save space for o32 */ |
| 397 | #if ICACHE_REFILLS_WORKAROUND_WAR | ||
| 398 | u32 sf_pad[2]; | ||
| 399 | #else | ||
| 381 | u32 sf_code[2]; /* signal trampoline */ | 400 | u32 sf_code[2]; /* signal trampoline */ |
| 401 | #endif | ||
| 382 | struct sigcontext32 sf_sc; | 402 | struct sigcontext32 sf_sc; |
| 383 | sigset_t sf_mask; | 403 | sigset_t sf_mask; |
| 404 | #if ICACHE_REFILLS_WORKAROUND_WAR | ||
| 405 | u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ | ||
| 406 | #endif | ||
| 384 | }; | 407 | }; |
| 385 | 408 | ||
| 386 | struct rt_sigframe32 { | 409 | struct rt_sigframe32 { |
| 387 | u32 rs_ass[4]; /* argument save space for o32 */ | 410 | u32 rs_ass[4]; /* argument save space for o32 */ |
| 411 | #if ICACHE_REFILLS_WORKAROUND_WAR | ||
| 412 | u32 rs_pad[2]; | ||
| 413 | #else | ||
| 388 | u32 rs_code[2]; /* signal trampoline */ | 414 | u32 rs_code[2]; /* signal trampoline */ |
| 415 | #endif | ||
| 389 | compat_siginfo_t rs_info; | 416 | compat_siginfo_t rs_info; |
| 390 | struct ucontext32 rs_uc; | 417 | struct ucontext32 rs_uc; |
| 418 | #if ICACHE_REFILLS_WORKAROUND_WAR | ||
| 419 | u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */ | ||
| 420 | #endif | ||
| 391 | }; | 421 | }; |
| 392 | 422 | ||
| 393 | int copy_siginfo_to_user32(compat_siginfo_t *to, siginfo_t *from) | 423 | int copy_siginfo_to_user32(compat_siginfo_t *to, siginfo_t *from) |
| @@ -411,6 +441,11 @@ int copy_siginfo_to_user32(compat_siginfo_t *to, siginfo_t *from) | |||
| 411 | err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); | 441 | err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); |
| 412 | else { | 442 | else { |
| 413 | switch (from->si_code >> 16) { | 443 | switch (from->si_code >> 16) { |
| 444 | case __SI_TIMER >> 16: | ||
| 445 | err |= __put_user(from->si_tid, &to->si_tid); | ||
| 446 | err |= __put_user(from->si_overrun, &to->si_overrun); | ||
| 447 | err |= __put_user(from->si_int, &to->si_int); | ||
| 448 | break; | ||
| 414 | case __SI_CHLD >> 16: | 449 | case __SI_CHLD >> 16: |
| 415 | err |= __put_user(from->si_utime, &to->si_utime); | 450 | err |= __put_user(from->si_utime, &to->si_utime); |
| 416 | err |= __put_user(from->si_stime, &to->si_stime); | 451 | err |= __put_user(from->si_stime, &to->si_stime); |
| @@ -480,6 +515,7 @@ __attribute_used__ noinline static void | |||
| 480 | _sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | 515 | _sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) |
| 481 | { | 516 | { |
| 482 | struct rt_sigframe32 *frame; | 517 | struct rt_sigframe32 *frame; |
| 518 | mm_segment_t old_fs; | ||
| 483 | sigset_t set; | 519 | sigset_t set; |
| 484 | stack_t st; | 520 | stack_t st; |
| 485 | s32 sp; | 521 | s32 sp; |
| @@ -510,7 +546,10 @@ _sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | |||
| 510 | 546 | ||
| 511 | /* It is more difficult to avoid calling this function than to | 547 | /* It is more difficult to avoid calling this function than to |
| 512 | call it and ignore errors. */ | 548 | call it and ignore errors. */ |
| 549 | old_fs = get_fs(); | ||
| 550 | set_fs (KERNEL_DS); | ||
| 513 | do_sigaltstack(&st, NULL, regs.regs[29]); | 551 | do_sigaltstack(&st, NULL, regs.regs[29]); |
| 552 | set_fs (old_fs); | ||
| 514 | 553 | ||
| 515 | /* | 554 | /* |
| 516 | * Don't let your children do this ... | 555 | * Don't let your children do this ... |
| @@ -550,8 +589,15 @@ static inline int setup_sigcontext32(struct pt_regs *regs, | |||
| 550 | 589 | ||
| 551 | err |= __put_user(regs->hi, &sc->sc_mdhi); | 590 | err |= __put_user(regs->hi, &sc->sc_mdhi); |
| 552 | err |= __put_user(regs->lo, &sc->sc_mdlo); | 591 | err |= __put_user(regs->lo, &sc->sc_mdlo); |
| 553 | err |= __put_user(regs->cp0_cause, &sc->sc_cause); | 592 | if (cpu_has_dsp) { |
| 554 | err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); | 593 | err |= __put_user(rddsp(DSP_MASK), &sc->sc_hi1); |
| 594 | err |= __put_user(mfhi1(), &sc->sc_hi1); | ||
| 595 | err |= __put_user(mflo1(), &sc->sc_lo1); | ||
| 596 | err |= __put_user(mfhi2(), &sc->sc_hi2); | ||
| 597 | err |= __put_user(mflo2(), &sc->sc_lo2); | ||
| 598 | err |= __put_user(mfhi3(), &sc->sc_hi3); | ||
| 599 | err |= __put_user(mflo3(), &sc->sc_lo3); | ||
| 600 | } | ||
| 555 | 601 | ||
| 556 | err |= __put_user(!!used_math(), &sc->sc_used_math); | 602 | err |= __put_user(!!used_math(), &sc->sc_used_math); |
| 557 | 603 | ||
| @@ -601,7 +647,7 @@ static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
| 601 | return (void *)((sp - frame_size) & ALMASK); | 647 | return (void *)((sp - frame_size) & ALMASK); |
| 602 | } | 648 | } |
| 603 | 649 | ||
| 604 | static inline void setup_frame(struct k_sigaction * ka, struct pt_regs *regs, | 650 | void setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, |
| 605 | int signr, sigset_t *set) | 651 | int signr, sigset_t *set) |
| 606 | { | 652 | { |
| 607 | struct sigframe *frame; | 653 | struct sigframe *frame; |
| @@ -654,9 +700,7 @@ give_sigsegv: | |||
| 654 | force_sigsegv(signr, current); | 700 | force_sigsegv(signr, current); |
| 655 | } | 701 | } |
| 656 | 702 | ||
| 657 | static inline void setup_rt_frame(struct k_sigaction * ka, | 703 | void setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info) |
| 658 | struct pt_regs *regs, int signr, | ||
| 659 | sigset_t *set, siginfo_t *info) | ||
| 660 | { | 704 | { |
| 661 | struct rt_sigframe32 *frame; | 705 | struct rt_sigframe32 *frame; |
| 662 | int err = 0; | 706 | int err = 0; |
| @@ -725,9 +769,11 @@ give_sigsegv: | |||
| 725 | force_sigsegv(signr, current); | 769 | force_sigsegv(signr, current); |
| 726 | } | 770 | } |
| 727 | 771 | ||
| 728 | static inline void handle_signal(unsigned long sig, siginfo_t *info, | 772 | static inline int handle_signal(unsigned long sig, siginfo_t *info, |
| 729 | struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs) | 773 | struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs) |
| 730 | { | 774 | { |
| 775 | int ret; | ||
| 776 | |||
| 731 | switch (regs->regs[0]) { | 777 | switch (regs->regs[0]) { |
| 732 | case ERESTART_RESTARTBLOCK: | 778 | case ERESTART_RESTARTBLOCK: |
| 733 | case ERESTARTNOHAND: | 779 | case ERESTARTNOHAND: |
| @@ -747,9 +793,9 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, | |||
| 747 | regs->regs[0] = 0; /* Don't deal with this again. */ | 793 | regs->regs[0] = 0; /* Don't deal with this again. */ |
| 748 | 794 | ||
| 749 | if (ka->sa.sa_flags & SA_SIGINFO) | 795 | if (ka->sa.sa_flags & SA_SIGINFO) |
| 750 | setup_rt_frame(ka, regs, sig, oldset, info); | 796 | ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info); |
| 751 | else | 797 | else |
| 752 | setup_frame(ka, regs, sig, oldset); | 798 | ret = current->thread.abi->setup_frame(ka, regs, sig, oldset); |
| 753 | 799 | ||
| 754 | spin_lock_irq(¤t->sighand->siglock); | 800 | spin_lock_irq(¤t->sighand->siglock); |
| 755 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 801 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
| @@ -757,6 +803,8 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, | |||
| 757 | sigaddset(¤t->blocked,sig); | 803 | sigaddset(¤t->blocked,sig); |
| 758 | recalc_sigpending(); | 804 | recalc_sigpending(); |
| 759 | spin_unlock_irq(¤t->sighand->siglock); | 805 | spin_unlock_irq(¤t->sighand->siglock); |
| 806 | |||
| 807 | return ret; | ||
| 760 | } | 808 | } |
| 761 | 809 | ||
| 762 | int do_signal32(sigset_t *oldset, struct pt_regs *regs) | 810 | int do_signal32(sigset_t *oldset, struct pt_regs *regs) |
| @@ -780,10 +828,8 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) | |||
| 780 | oldset = ¤t->blocked; | 828 | oldset = ¤t->blocked; |
| 781 | 829 | ||
| 782 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 830 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 783 | if (signr > 0) { | 831 | if (signr > 0) |
| 784 | handle_signal(signr, &info, &ka, oldset, regs); | 832 | return handle_signal(signr, &info, &ka, oldset, regs); |
| 785 | return 1; | ||
| 786 | } | ||
| 787 | 833 | ||
| 788 | no_signal: | 834 | no_signal: |
| 789 | /* | 835 | /* |
| @@ -819,12 +865,13 @@ asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 *act, | |||
| 819 | goto out; | 865 | goto out; |
| 820 | 866 | ||
| 821 | if (act) { | 867 | if (act) { |
| 868 | s32 handler; | ||
| 822 | int err = 0; | 869 | int err = 0; |
| 823 | 870 | ||
| 824 | if (!access_ok(VERIFY_READ, act, sizeof(*act))) | 871 | if (!access_ok(VERIFY_READ, act, sizeof(*act))) |
| 825 | return -EFAULT; | 872 | return -EFAULT; |
| 826 | err |= __get_user((u32)(u64)new_sa.sa.sa_handler, | 873 | err |= __get_user(handler, &act->sa_handler); |
| 827 | &act->sa_handler); | 874 | new_sa.sa.sa_handler = (void*)(s64)handler; |
| 828 | err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags); | 875 | err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags); |
| 829 | err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask); | 876 | err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask); |
| 830 | if (err) | 877 | if (err) |
| @@ -902,3 +949,30 @@ asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t *uinfo) | |||
| 902 | set_fs (old_fs); | 949 | set_fs (old_fs); |
| 903 | return ret; | 950 | return ret; |
| 904 | } | 951 | } |
| 952 | |||
| 953 | asmlinkage long | ||
| 954 | sys32_waitid(int which, compat_pid_t pid, | ||
| 955 | compat_siginfo_t __user *uinfo, int options, | ||
| 956 | struct compat_rusage __user *uru) | ||
| 957 | { | ||
| 958 | siginfo_t info; | ||
| 959 | struct rusage ru; | ||
| 960 | long ret; | ||
| 961 | mm_segment_t old_fs = get_fs(); | ||
| 962 | |||
| 963 | info.si_signo = 0; | ||
| 964 | set_fs (KERNEL_DS); | ||
| 965 | ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options, | ||
| 966 | uru ? (struct rusage __user *) &ru : NULL); | ||
| 967 | set_fs (old_fs); | ||
| 968 | |||
| 969 | if (ret < 0 || info.si_signo == 0) | ||
| 970 | return ret; | ||
| 971 | |||
| 972 | if (uru && (ret = put_compat_rusage(&ru, uru))) | ||
| 973 | return ret; | ||
| 974 | |||
| 975 | BUG_ON(info.si_code & __SI_MASK); | ||
| 976 | info.si_code |= __SI_CHLD; | ||
| 977 | return copy_siginfo_to_user32(uinfo, &info); | ||
| 978 | } | ||
