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 | } | ||