diff options
Diffstat (limited to 'arch/microblaze/kernel/signal.c')
-rw-r--r-- | arch/microblaze/kernel/signal.c | 109 |
1 files changed, 21 insertions, 88 deletions
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 40d3693..4c0e652 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -152,8 +152,8 @@ struct rt_sigframe { unsigned long tramp[2]; /* signal trampoline */ }; -static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *rval_p) +static int restore_sigcontext(struct pt_regs *regs, + struct sigcontext __user *sc, int *rval_p) { unsigned int err = 0; @@ -211,11 +211,10 @@ badframe: asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) { - struct rt_sigframe *frame = - (struct rt_sigframe *)(regs->r1 + STATE_SAVE_ARG_SPACE); + struct rt_sigframe __user *frame = + (struct rt_sigframe __user *)(regs->r1 + STATE_SAVE_ARG_SPACE); sigset_t set; - stack_t st; int rval; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -233,11 +232,10 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval)) goto badframe; - if (__copy_from_user((void *)&st, &frame->uc.uc_stack, sizeof(st))) - goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs->r1); + if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->r1)) + goto badframe; return rval; @@ -251,7 +249,7 @@ badframe: */ static int -setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, +setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask) { int err = 0; @@ -278,7 +276,7 @@ setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, /* * Determine which stack to use.. */ -static inline void * +static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) { /* Default to using normal stack */ @@ -287,87 +285,13 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp)) sp = current->sas_ss_sp + current->sas_ss_size; - return (void *)((sp - frame_size) & -8UL); -} - -static void setup_frame(int sig, struct k_sigaction *ka, - sigset_t *set, struct pt_regs *regs) -{ - struct sigframe *frame; - int err = 0; - int signal; - - frame = get_sigframe(ka, regs, sizeof(*frame)); - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; - - signal = current_thread_info()->exec_domain - && current_thread_info()->exec_domain->signal_invmap - && sig < 32 - ? current_thread_info()->exec_domain->signal_invmap[sig] - : sig; - - err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); - - if (_NSIG_WORDS > 1) { - err |= __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); - } - - /* Set up to return from userspace. If provided, use a stub - already in userspace. */ - /* minus 8 is offset to cater for "rtsd r15,8" offset */ - if (ka->sa.sa_flags & SA_RESTORER) { - regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8; - } else { - /* Note, these encodings are _big endian_! */ - - /* addi r12, r0, __NR_sigreturn */ - err |= __put_user(0x31800000 | __NR_sigreturn , - frame->tramp + 0); - /* brki r14, 0x8 */ - err |= __put_user(0xb9cc0008, frame->tramp + 1); - - /* Return from sighandler will jump to the tramp. - Negative 8 offset because return is rtsd r15, 8 */ - regs->r15 = ((unsigned long)frame->tramp)-8; - - __invalidate_cache_sigtramp((unsigned long)frame->tramp); - } - - if (err) - goto give_sigsegv; - - /* Set up registers for signal handler */ - regs->r1 = (unsigned long) frame - STATE_SAVE_ARG_SPACE; - - /* Signal handler args: */ - regs->r5 = signal; /* Arg 0: signum */ - regs->r6 = (unsigned long) &frame->sc; /* arg 1: sigcontext */ - - /* Offset of 4 to handle microblaze rtid r14, 0 */ - regs->pc = (unsigned long)ka->sa.sa_handler; - - set_fs(USER_DS); - -#ifdef DEBUG_SIG - printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n", - current->comm, current->pid, frame, regs->pc); -#endif - - return; - -give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + return (void __user *)((sp - frame_size) & -8UL); } static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { - struct rt_sigframe *frame; + struct rt_sigframe __user *frame; int err = 0; int signal; @@ -382,7 +306,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ? current_thread_info()->exec_domain->signal_invmap[sig] : sig; - err |= copy_siginfo_to_user(&frame->info, info); + if (info) + err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); @@ -463,7 +388,15 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) case -ERESTARTNOINTR: do_restart: /* offset of 4 bytes to re-execute trap (brki) instruction */ +#ifndef CONFIG_MMU regs->pc -= 4; +#else + /* offset of 8 bytes required = 4 for rtbd + offset, plus 4 for size of + "brki r14,8" + instruction. */ + regs->pc -= 8; +#endif break; } } @@ -480,7 +413,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, if (ka->sa.sa_flags & SA_SIGINFO) setup_rt_frame(sig, ka, info, oldset, regs); else - setup_frame(sig, ka, oldset, regs); + setup_rt_frame(sig, ka, NULL, oldset, regs); if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; |