X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fkernel%2Fsignal.c;h=3843d3bab2ddc4d2e7eb536cc8380ee3d420d5f5;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=d433d47842b6cec73827ff1741c067cb51c4dbc0;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index d433d4784..3843d3bab 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -7,19 +7,20 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include #include #include #include #include -#include +#include +#include #include #include #include #include #include "ptrace.h" +#include "signal.h" #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -29,6 +30,12 @@ #define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)) #define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)) +/* + * With EABI, the syscall number has to be loaded into r7. + */ +#define MOV_R7_NR_SIGRETURN (0xe3a07000 | (__NR_sigreturn - __NR_SYSCALL_BASE)) +#define MOV_R7_NR_RT_SIGRETURN (0xe3a07000 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE)) + /* * For Thumb syscalls, we pass the syscall number via r7. We therefore * need two 16-bit instructions. @@ -36,9 +43,9 @@ #define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE)) #define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE)) -static const unsigned long retcodes[4] = { - SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, - SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN +const unsigned long sigreturn_codes[7] = { + MOV_R7_NR_SIGRETURN, SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, + MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, }; static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); @@ -103,7 +110,7 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, if (act) { old_sigset_t mask; - if (verify_area(VERIFY_READ, act, sizeof(*act)) || + if (!access_ok(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) return -EFAULT; @@ -115,7 +122,7 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { - if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) return -EFAULT; @@ -126,151 +133,138 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, return ret; } -/* - * Do a signal return; undo the signal stack. - */ -struct sigframe +#ifdef CONFIG_CRUNCH +static int preserve_crunch_context(struct crunch_sigframe *frame) { - struct sigcontext sc; - unsigned long extramask[_NSIG_WORDS-1]; - unsigned long retcode; -}; - -struct rt_sigframe -{ - struct siginfo __user *pinfo; - void __user *puc; - struct siginfo info; - struct ucontext uc; - unsigned long retcode; -}; - -#ifdef CONFIG_IWMMXT - -/* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */ -#define IWMMXT_STORAGE_SIZE (0x98 + 8) -#define IWMMXT_MAGIC0 0x12ef842a -#define IWMMXT_MAGIC1 0x1c07ca71 + char kbuf[sizeof(*frame) + 8]; + struct crunch_sigframe *kframe; + + /* the crunch context must be 64 bit aligned */ + kframe = (struct crunch_sigframe *)((unsigned long)(kbuf + 8) & ~7); + kframe->magic = CRUNCH_MAGIC; + kframe->size = CRUNCH_STORAGE_SIZE; + crunch_task_copy(current_thread_info(), &kframe->storage); + return __copy_to_user(frame, kframe, sizeof(*frame)); +} -static int page_present(struct mm_struct *mm, unsigned long addr, int wr) +static int restore_crunch_context(struct crunch_sigframe *frame) { - pgd_t *pgd = pgd_offset(mm, addr); - if (pgd_present(*pgd)) { - pmd_t *pmd = pmd_offset(pgd, addr); - if (pmd_present(*pmd)) { - pte_t *pte = pte_offset_map(pmd, addr); - return (pte_present(*pte) && (!wr || pte_write(*pte))); - } - } + char kbuf[sizeof(*frame) + 8]; + struct crunch_sigframe *kframe; + + /* the crunch context must be 64 bit aligned */ + kframe = (struct crunch_sigframe *)((unsigned long)(kbuf + 8) & ~7); + if (__copy_from_user(kframe, frame, sizeof(*frame))) + return -1; + if (kframe->magic != CRUNCH_MAGIC || + kframe->size != CRUNCH_STORAGE_SIZE) + return -1; + crunch_task_restore(current_thread_info(), &kframe->storage); return 0; } +#endif -static int -preserve_iwmmxt_context(void *iwmmxt_save_area) +#ifdef CONFIG_IWMMXT + +static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame) { - int err = 0; + char kbuf[sizeof(*frame) + 8]; + struct iwmmxt_sigframe *kframe; /* the iWMMXt context must be 64 bit aligned */ - long *iwmmxt_storage = (long *)(((long)iwmmxt_save_area + 4) & ~7); - -again: - __put_user_error(IWMMXT_MAGIC0, iwmmxt_storage+0, err); - __put_user_error(IWMMXT_MAGIC1, iwmmxt_storage+1, err); - /* - * iwmmxt_task_copy() doesn't check user permissions. - * Let's do a dummy write on the upper boundary to ensure - * access to user mem is OK all way up. - */ - __put_user_error(0, iwmmxt_storage+IWMMXT_STORAGE_SIZE/4-1, err); - if (!err) { - /* Let's make sure the user mapping won't disappear under us */ - struct mm_struct *mm = current->mm; - unsigned long addr = (unsigned long)iwmmxt_storage; - spin_lock(&mm->page_table_lock); - if ( !page_present(mm, addr, 1) || - !page_present(mm, addr+IWMMXT_STORAGE_SIZE-1, 1) ) { - /* our user area has gone before grabbing the lock */ - spin_unlock(&mm->page_table_lock); - goto again; - } - iwmmxt_task_copy(current_thread_info(), iwmmxt_storage+2); - spin_unlock(&mm->page_table_lock); - return 0; - } - return err; + kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7); + kframe->magic = IWMMXT_MAGIC; + kframe->size = IWMMXT_STORAGE_SIZE; + iwmmxt_task_copy(current_thread_info(), &kframe->storage); + return __copy_to_user(frame, kframe, sizeof(*frame)); } -static int -restore_iwmmxt_context(void *iwmmxt_save_area) +static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) { - int err = 0; - long *iwmmxt_storage, magic0, magic1, dummy; - - /* the iWMMXt context is 64 bit aligned */ - iwmmxt_storage = (long *)(((long)iwmmxt_save_area + 4) & ~7); + char kbuf[sizeof(*frame) + 8]; + struct iwmmxt_sigframe *kframe; - /* - * Validate iWMMXt context signature. - * Also, iwmmxt_task_restore() doesn't check user permissions. - * Let's do a dummy write on the upper boundary to ensure - * access to user mem is OK all way up. - */ -again: - __get_user_error(magic0, iwmmxt_storage+0, err); - __get_user_error(magic1, iwmmxt_storage+1, err); - if (!err && magic0 == IWMMXT_MAGIC0 && magic1 == IWMMXT_MAGIC1 && - !__get_user(dummy, iwmmxt_storage+IWMMXT_STORAGE_SIZE/4-1)) { - /* Let's make sure the user mapping won't disappear under us */ - struct mm_struct *mm = current->mm; - unsigned long addr = (unsigned long)iwmmxt_storage; - spin_lock(&mm->page_table_lock); - if ( !page_present(mm, addr, 0) || - !page_present(mm, addr+IWMMXT_STORAGE_SIZE-1, 0) ) { - /* our user area has gone before grabbing the lock */ - spin_unlock(&mm->page_table_lock); - goto again; - } - iwmmxt_task_restore(current_thread_info(), iwmmxt_storage+2); - spin_unlock(&mm->page_table_lock); - return 0; - } - return -1; + /* the iWMMXt context must be 64 bit aligned */ + kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7); + if (__copy_from_user(kframe, frame, sizeof(*frame))) + return -1; + if (kframe->magic != IWMMXT_MAGIC || + kframe->size != IWMMXT_STORAGE_SIZE) + return -1; + iwmmxt_task_restore(current_thread_info(), &kframe->storage); + return 0; } #endif -static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) +/* + * Do a signal return; undo the signal stack. These are aligned to 64-bit. + */ +struct sigframe { + struct ucontext uc; + unsigned long retcode[2]; +}; + +struct rt_sigframe { + struct siginfo info; + struct sigframe sig; +}; + +static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) { - int err = 0; + struct aux_sigframe __user *aux; + sigset_t set; + int err; - __get_user_error(regs->ARM_r0, &sc->arm_r0, err); - __get_user_error(regs->ARM_r1, &sc->arm_r1, err); - __get_user_error(regs->ARM_r2, &sc->arm_r2, err); - __get_user_error(regs->ARM_r3, &sc->arm_r3, err); - __get_user_error(regs->ARM_r4, &sc->arm_r4, err); - __get_user_error(regs->ARM_r5, &sc->arm_r5, err); - __get_user_error(regs->ARM_r6, &sc->arm_r6, err); - __get_user_error(regs->ARM_r7, &sc->arm_r7, err); - __get_user_error(regs->ARM_r8, &sc->arm_r8, err); - __get_user_error(regs->ARM_r9, &sc->arm_r9, err); - __get_user_error(regs->ARM_r10, &sc->arm_r10, err); - __get_user_error(regs->ARM_fp, &sc->arm_fp, err); - __get_user_error(regs->ARM_ip, &sc->arm_ip, err); - __get_user_error(regs->ARM_sp, &sc->arm_sp, err); - __get_user_error(regs->ARM_lr, &sc->arm_lr, err); - __get_user_error(regs->ARM_pc, &sc->arm_pc, err); - __get_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err); + err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); + if (err == 0) { + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } + + __get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); + __get_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err); + __get_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err); + __get_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err); + __get_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err); + __get_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err); + __get_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err); + __get_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err); + __get_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err); + __get_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err); + __get_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err); + __get_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err); + __get_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err); + __get_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err); + __get_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err); + __get_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err); + __get_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err); err |= !valid_user_regs(regs); + aux = (struct aux_sigframe __user *) sf->uc.uc_regspace; +#ifdef CONFIG_CRUNCH + if (err == 0) + err |= restore_crunch_context(&aux->crunch); +#endif +#ifdef CONFIG_IWMMXT + if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) + err |= restore_iwmmxt_context(&aux->iwmmxt); +#endif +#ifdef CONFIG_VFP +// if (err == 0) +// err |= vfp_restore_state(&sf->aux.vfp); +#endif + return err; } asmlinkage int sys_sigreturn(struct pt_regs *regs) { struct sigframe __user *frame; - sigset_t set; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; @@ -285,28 +279,12 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) frame = (struct sigframe __user *)regs->ARM_sp; - if (verify_area(VERIFY_READ, frame, sizeof (*frame))) - goto badframe; - if (__get_user(set.sig[0], &frame->sc.oldmask) - || (_NSIG_WORDS > 1 - && __copy_from_user(&set.sig[1], &frame->extramask, - sizeof(frame->extramask)))) + if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) goto badframe; - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if (restore_sigcontext(regs, &frame->sc)) + if (restore_sigframe(regs, frame)) goto badframe; -#ifdef CONFIG_IWMMXT - if (test_thread_flag(TIF_USING_IWMMXT) && restore_iwmmxt_context(frame+1)) - goto badframe; -#endif - /* Send SIGTRAP if we're single-stepping */ if (current->ptrace & PT_SINGLESTEP) { ptrace_cancel_bpt(current); @@ -323,7 +301,6 @@ badframe: asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) { struct rt_sigframe __user *frame; - sigset_t set; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; @@ -338,27 +315,14 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) frame = (struct rt_sigframe __user *)regs->ARM_sp; - if (verify_area(VERIFY_READ, frame, sizeof (*frame))) - goto badframe; - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) + if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) goto badframe; - if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) + if (restore_sigframe(regs, &frame->sig)) goto badframe; -#ifdef CONFIG_IWMMXT - if (test_thread_flag(TIF_USING_IWMMXT) && restore_iwmmxt_context(frame+1)) + if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) goto badframe; -#endif /* Send SIGTRAP if we're single-stepping */ if (current->ptrace & PT_SINGLESTEP) { @@ -374,33 +338,50 @@ badframe: } static int -setup_sigcontext(struct sigcontext __user *sc, /*struct _fpstate *fpstate,*/ - struct pt_regs *regs, unsigned long mask) +setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) { + struct aux_sigframe __user *aux; int err = 0; - __put_user_error(regs->ARM_r0, &sc->arm_r0, err); - __put_user_error(regs->ARM_r1, &sc->arm_r1, err); - __put_user_error(regs->ARM_r2, &sc->arm_r2, err); - __put_user_error(regs->ARM_r3, &sc->arm_r3, err); - __put_user_error(regs->ARM_r4, &sc->arm_r4, err); - __put_user_error(regs->ARM_r5, &sc->arm_r5, err); - __put_user_error(regs->ARM_r6, &sc->arm_r6, err); - __put_user_error(regs->ARM_r7, &sc->arm_r7, err); - __put_user_error(regs->ARM_r8, &sc->arm_r8, err); - __put_user_error(regs->ARM_r9, &sc->arm_r9, err); - __put_user_error(regs->ARM_r10, &sc->arm_r10, err); - __put_user_error(regs->ARM_fp, &sc->arm_fp, err); - __put_user_error(regs->ARM_ip, &sc->arm_ip, err); - __put_user_error(regs->ARM_sp, &sc->arm_sp, err); - __put_user_error(regs->ARM_lr, &sc->arm_lr, err); - __put_user_error(regs->ARM_pc, &sc->arm_pc, err); - __put_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err); - - __put_user_error(current->thread.trap_no, &sc->trap_no, err); - __put_user_error(current->thread.error_code, &sc->error_code, err); - __put_user_error(current->thread.address, &sc->fault_address, err); - __put_user_error(mask, &sc->oldmask, err); + __put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); + __put_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err); + __put_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err); + __put_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err); + __put_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err); + __put_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err); + __put_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err); + __put_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err); + __put_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err); + __put_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err); + __put_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err); + __put_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err); + __put_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err); + __put_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err); + __put_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err); + __put_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err); + __put_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err); + + __put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, err); + __put_user_error(current->thread.error_code, &sf->uc.uc_mcontext.error_code, err); + __put_user_error(current->thread.address, &sf->uc.uc_mcontext.fault_address, err); + __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err); + + err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); + + aux = (struct aux_sigframe __user *) sf->uc.uc_regspace; +#ifdef CONFIG_CRUNCH + if (err == 0) + err |= preserve_crunch_context(&aux->crunch); +#endif +#ifdef CONFIG_IWMMXT + if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) + err |= preserve_iwmmxt_context(&aux->iwmmxt); +#endif +#ifdef CONFIG_VFP +// if (err == 0) +// err |= vfp_save_state(&sf->aux.vfp); +#endif + __put_user_error(0, &aux->end_magic, err); return err; } @@ -411,11 +392,6 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize) unsigned long sp = regs->ARM_sp; void __user *frame; -#ifdef CONFIG_IWMMXT - if (test_thread_flag(TIF_USING_IWMMXT)) - framesize = (framesize + 4 + IWMMXT_STORAGE_SIZE) & ~7; -#endif - /* * This is the X/Open sanctioned signal stack switching. */ @@ -469,22 +445,31 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, if (ka->sa.sa_flags & SA_RESTORER) { retcode = (unsigned long)ka->sa.sa_restorer; } else { - unsigned int idx = thumb; + unsigned int idx = thumb << 1; if (ka->sa.sa_flags & SA_SIGINFO) - idx += 2; + idx += 3; - if (__put_user(retcodes[idx], rc)) + if (__put_user(sigreturn_codes[idx], rc) || + __put_user(sigreturn_codes[idx+1], rc+1)) return 1; - /* - * Ensure that the instruction cache sees - * the return code written onto the stack. - */ - flush_icache_range((unsigned long)rc, - (unsigned long)(rc + 1)); - - retcode = ((unsigned long)rc) + thumb; + if (cpsr & MODE32_BIT) { + /* + * 32-bit code can use the new high-page + * signal return code support. + */ + retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb; + } else { + /* + * Ensure that the instruction cache sees + * the return code written onto the stack. + */ + flush_icache_range((unsigned long)rc, + (unsigned long)(rc + 2)); + + retcode = ((unsigned long)rc) + thumb; + } } regs->ARM_r0 = usig; @@ -505,20 +490,14 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg if (!frame) return 1; - err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); - - if (_NSIG_WORDS > 1) { - err |= __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); - } - -#ifdef CONFIG_IWMMXT - if (test_thread_flag(TIF_USING_IWMMXT)) - err |= preserve_iwmmxt_context(frame+1); -#endif + /* + * Set uc.uc_flags to a value which sc.trap_no would never have. + */ + __put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err); + err |= setup_sigframe(frame, regs, set); if (err == 0) - err = setup_return(regs, ka, &frame->retcode, frame, usig); + err = setup_return(regs, ka, frame->retcode, frame, usig); return err; } @@ -534,30 +513,20 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, if (!frame) return 1; - __put_user_error(&frame->info, &frame->pinfo, err); - __put_user_error(&frame->uc, &frame->puc, err); err |= copy_siginfo_to_user(&frame->info, info); - __put_user_error(0, &frame->uc.uc_flags, err); - __put_user_error(NULL, &frame->uc.uc_link, err); + __put_user_error(0, &frame->sig.uc.uc_flags, err); + __put_user_error(NULL, &frame->sig.uc.uc_link, err); memset(&stack, 0, sizeof(stack)); stack.ss_sp = (void __user *)current->sas_ss_sp; stack.ss_flags = sas_ss_flags(regs->ARM_sp); stack.ss_size = current->sas_ss_size; - err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack)); - - err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/ - regs, set->sig[0]); - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); - -#ifdef CONFIG_IWMMXT - if (test_thread_flag(TIF_USING_IWMMXT)) - err |= preserve_iwmmxt_context(frame+1); -#endif + err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack)); + err |= setup_sigframe(&frame->sig, regs, set); if (err == 0) - err = setup_return(regs, ka, &frame->retcode, frame, usig); + err = setup_return(regs, ka, frame->sig.retcode, frame, usig); if (err == 0) { /* @@ -566,7 +535,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, * -- Peter Maydell 2000-12-06 */ regs->ARM_r1 = (unsigned long)&frame->info; - regs->ARM_r2 = (unsigned long)&frame->uc; + regs->ARM_r2 = (unsigned long)&frame->sig.uc; } return err; @@ -630,22 +599,22 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, */ ret |= !valid_user_regs(regs); + if (ret != 0) { + force_sigsegv(sig, tsk); + return; + } + /* - * Block the signal if we were unsuccessful. + * Block the signal if we were successful. */ - if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(&tsk->sighand->siglock); - sigorsets(&tsk->blocked, &tsk->blocked, - &ka->sa.sa_mask); + spin_lock_irq(&tsk->sighand->siglock); + sigorsets(&tsk->blocked, &tsk->blocked, + &ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(&tsk->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(&tsk->sighand->siglock); - } - - if (ret == 0) - return; + recalc_sigpending(); + spin_unlock_irq(&tsk->sighand->siglock); - force_sigsegv(sig, tsk); } /* @@ -672,10 +641,8 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) if (!user_mode(regs)) return 0; - if (current->flags & PF_FREEZE) { - refrigerator(0); + if (try_to_freeze()) goto no_signal; - } if (current->ptrace & PT_SINGLESTEP) ptrace_cancel_bpt(current); @@ -695,17 +662,33 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) if (syscall) { if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) { if (thumb_mode(regs)) { - regs->ARM_r7 = __NR_restart_syscall; + regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; regs->ARM_pc -= 2; } else { +#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT) + regs->ARM_r7 = __NR_restart_syscall; + regs->ARM_pc -= 4; +#else u32 __user *usp; + u32 swival = __NR_restart_syscall; regs->ARM_sp -= 12; usp = (u32 __user *)regs->ARM_sp; + /* + * Either we supports OABI only, or we have + * EABI with the OABI compat layer enabled. + * In the later case we don't know if user + * space is EABI or not, and if not we must + * not clobber r7. Always using the OABI + * syscall solves that issue and works for + * all those cases. + */ + swival = swival - __NR_SYSCALL_BASE + __NR_OABI_SYSCALL_BASE; + put_user(regs->ARM_pc, &usp[0]); /* swi __NR_restart_syscall */ - put_user(0xef000000 | __NR_restart_syscall, &usp[1]); + put_user(0xef000000 | swival, &usp[1]); /* ldr pc, [sp], #12 */ put_user(0xe49df00c, &usp[2]); @@ -713,6 +696,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) (unsigned long)(usp + 3)); regs->ARM_pc = regs->ARM_sp + 4; +#endif } } if (regs->ARM_r0 == -ERESTARTNOHAND ||