/* * Re-start a thread when doing execve() */ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) { regs->pc = pc; regs->ps = 8; wrusp(sp); }
static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { unsigned int err = 0; unsigned long old_usp; current_thread_info()->restart_block.fn = do_no_restart_syscall; if (__copy_from_user(regs, sc, sizeof(struct pt_regs))) goto badframe; regs->dccr |= 1 << 8; err |= __get_user(old_usp, &sc->usp); wrusp(old_usp); return err; badframe: return 1; }
int vmadump_restore_cpu(struct vmadump_map_ctx *ctx, struct file *file, struct pt_regs *regs) { struct pt_regs regtmp; struct switch_stack *ss, sstmp; unsigned long usp; int r; r = read_kern(ctx, file, ®tmp, sizeof(regtmp)); if (r != sizeof(regtmp)) goto bad_read; /* Read extra reg info for alpha */ ss = ((struct switch_stack *)regs)-1; r = read_kern(ctx, file, &sstmp, sizeof(sstmp)); if (r != sizeof(sstmp)) goto bad_read; r = read_kern(ctx, file, &usp, sizeof(usp)); if (r != sizeof(usp)) goto bad_read; /* These are the tid-bits we don't want to restore */ regtmp.ps = 8; /* Processor status 8 = user space */ regtmp.hae = regs->hae; /* XXX What is this reg? */ sstmp.r26 = ss->r26; /* Not actually the user r26(ra). That * one is in struct pt_regs. */ /* Ok, do restore */ memcpy(regs, ®tmp, sizeof(regtmp)); memcpy(ss, &sstmp, sizeof(sstmp)); /* Restores FP regs + saved regs */ wrusp(usp); return 0; bad_read: if (r >= 0) r = -EIO; return r; }
static inline int restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, int *pd0) { int err = 0; unsigned int ccr; unsigned int usp; unsigned int er0; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; #define COPY(r) err |= __get_user(regs->r, &usc->sc_##r) /* restore passed registers */ COPY(er1); COPY(er2); COPY(er3); COPY(er5); COPY(pc); ccr = regs->ccr & 0x10; COPY(ccr); #undef COPY regs->ccr &= 0xef; regs->ccr |= ccr; regs->orig_er0 = -1; /* disable syscall checks */ err |= __get_user(usp, &usc->sc_usp); wrusp(usp); err |= __get_user(er0, &usc->sc_er0); *pd0 = er0; return err; }
static inline int rt_restore_ucontext(struct pt_regs *regs, struct ucontext *uc, int *pd0) { int temp; greg_t *gregs = uc->uc_mcontext.gregs; unsigned long usp; int err; err = __get_user(temp, &uc->uc_mcontext.version); if (temp != MCONTEXT_VERSION) goto badframe; /* restore passed registers */ err |= __get_user(regs->er0, &gregs[0]); err |= __get_user(regs->er1, &gregs[1]); err |= __get_user(regs->er2, &gregs[2]); err |= __get_user(regs->er3, &gregs[3]); err |= __get_user(regs->er4, &gregs[4]); err |= __get_user(regs->er5, &gregs[5]); err |= __get_user(regs->er6, &gregs[6]); err |= __get_user(usp, &gregs[7]); wrusp(usp); err |= __get_user(regs->pc, &gregs[8]); err |= __get_user(temp, &gregs[9]); regs->ccr = (regs->ccr & 0x10) | (temp & 0xef); regs->orig_er0 = -1; /* disable syscall checks */ if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) goto badframe; *pd0 = regs->er0; return err; badframe: return 1; }
static inline int restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp, int *pd0) { struct sigcontext context; int err = 0; /* get previous context */ if (copy_from_user(&context, usc, sizeof(context))) goto badframe; /* restore passed registers */ regs->er1 = context.sc_er1; regs->er2 = context.sc_er2; regs->er3 = context.sc_er3; regs->er5 = context.sc_er5; regs->ccr = (regs->ccr & 0x10)|(context.sc_ccr & 0xef); regs->pc = context.sc_pc; regs->orig_er0 = -1; /* disable syscall checks */ wrusp(context.sc_usp); *pd0 = context.sc_er0; return err; badframe: return 1; }
static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) { unsigned long oldsp, r26, err = 0; struct sigframe *frame; oldsp = rdusp(); frame = get_sigframe(ka, oldsp, sizeof(*frame)); if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); if (_NSIG_WORDS > 1) { err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); } if (err) goto give_sigsegv; /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->ka_restorer) { r26 = (unsigned long) ka->ka_restorer; } else { err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); err |= __put_user(INSN_CALLSYS, frame->retcode+2); imb(); r26 = (unsigned long) frame->retcode; } /* Check that everything was written properly. */ if (err) goto give_sigsegv; /* "Return" to the handler */ regs->r26 = r26; regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; regs->r16 = sig; /* a0: signal number */ regs->r17 = 0; /* a1: exception code */ regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */ wrusp((unsigned long) frame); #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->pc, regs->r26); #endif return; give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); }
static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { unsigned long oldsp, r26, err = 0; struct rt_sigframe __user *frame; oldsp = rdusp(); frame = get_sigframe(ka, oldsp, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) return -EFAULT; err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); err |= __save_altstack(&frame->uc.uc_stack, oldsp); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], oldsp); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) return -EFAULT; /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->ka_restorer) { r26 = (unsigned long) ka->ka_restorer; } else { err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn, frame->retcode+1); err |= __put_user(INSN_CALLSYS, frame->retcode+2); imb(); r26 = (unsigned long) frame->retcode; } if (err) return -EFAULT; /* "Return" to the handler */ regs->r26 = r26; regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; regs->r16 = sig; /* a0: signal number */ regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */ regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */ wrusp((unsigned long) frame); #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->pc, regs->r26); #endif return 0; }
static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) { struct sigframe __user *frame; unsigned long return_ip; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); if (err) goto give_sigsegv; if (_NSIG_WORDS > 1) { err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); } if (err) goto give_sigsegv; /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa.sa_flags & SA_RESTORER) { return_ip = (unsigned long)ka->sa.sa_restorer; } else { /* trampoline - the desired return ip is the retcode itself */ return_ip = (unsigned long)&frame->retcode; /* This is movu.w __NR_sigreturn, r9; break 13; */ err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0)); err |= __put_user(__NR_sigreturn, (short __user*)(frame->retcode+2)); err |= __put_user(0xe93d, (short __user*)(frame->retcode+4)); } if (err) goto give_sigsegv; /* Set up registers for signal handler */ regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */ regs->srp = return_ip; /* what we enter LATER */ regs->r10 = sig; /* first argument is signo */ /* actually move the usp to reflect the stacked frame */ wrusp((unsigned long)frame); return 0; give_sigsegv: force_sigsegv(sig, current); return -EFAULT; }
static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info, sigset_t * set, struct pt_regs *regs) { struct rt_sigframe *frame; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); err |= __put_user((current_thread_info()->exec_domain && current_thread_info()->exec_domain->signal_invmap && sig < 32 ? current_thread_info()->exec_domain-> signal_invmap[sig] : sig), &frame->sig); err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(rdusp()), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= rt_setup_sigcontext(&frame->uc.uc_mcontext, regs); err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) goto give_sigsegv; /* Set up registers for signal handler */ wrusp((unsigned long)frame); if (current->personality & FDPIC_FUNCPTRS) { struct fdpic_func_descriptor __user *funcptr = (struct fdpic_func_descriptor *) ka->sa.sa_handler; __get_user(regs->pc, &funcptr->text); __get_user(regs->p3, &funcptr->GOT); } else regs->pc = (unsigned long)ka->sa.sa_handler; regs->rets = SIGRETURN_STUB; regs->r0 = frame->sig; regs->r1 = (unsigned long)(&frame->info); regs->r2 = (unsigned long)(&frame->uc); return 0; give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); return -EFAULT; }
static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) { struct sigframe __user *frame; unsigned long return_ip; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); if (err) goto give_sigsegv; if (_NSIG_WORDS > 1) { err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); } if (err) goto give_sigsegv; if (ka->sa.sa_flags & SA_RESTORER) { return_ip = (unsigned long)ka->sa.sa_restorer; } else { return_ip = (unsigned long)&frame->retcode; err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0)); err |= __put_user(__NR_sigreturn, (short __user*)(frame->retcode+2)); err |= __put_user(0xe93d, (short __user*)(frame->retcode+4)); } if (err) goto give_sigsegv; regs->irp = (unsigned long) ka->sa.sa_handler; regs->srp = return_ip; regs->r10 = sig; wrusp((unsigned long)frame); return 0; give_sigsegv: force_sigsegv(sig, current); return -EFAULT; }
static long restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, struct switch_stack *sw) { unsigned long usp; long i, err = __get_user(regs->pc, &sc->sc_pc); current_thread_info()->restart_block.fn = do_no_restart_syscall; sw->r26 = (unsigned long) ret_from_sys_call; err |= __get_user(regs->r0, sc->sc_regs+0); err |= __get_user(regs->r1, sc->sc_regs+1); err |= __get_user(regs->r2, sc->sc_regs+2); err |= __get_user(regs->r3, sc->sc_regs+3); err |= __get_user(regs->r4, sc->sc_regs+4); err |= __get_user(regs->r5, sc->sc_regs+5); err |= __get_user(regs->r6, sc->sc_regs+6); err |= __get_user(regs->r7, sc->sc_regs+7); err |= __get_user(regs->r8, sc->sc_regs+8); err |= __get_user(sw->r9, sc->sc_regs+9); err |= __get_user(sw->r10, sc->sc_regs+10); err |= __get_user(sw->r11, sc->sc_regs+11); err |= __get_user(sw->r12, sc->sc_regs+12); err |= __get_user(sw->r13, sc->sc_regs+13); err |= __get_user(sw->r14, sc->sc_regs+14); err |= __get_user(sw->r15, sc->sc_regs+15); err |= __get_user(regs->r16, sc->sc_regs+16); err |= __get_user(regs->r17, sc->sc_regs+17); err |= __get_user(regs->r18, sc->sc_regs+18); err |= __get_user(regs->r19, sc->sc_regs+19); err |= __get_user(regs->r20, sc->sc_regs+20); err |= __get_user(regs->r21, sc->sc_regs+21); err |= __get_user(regs->r22, sc->sc_regs+22); err |= __get_user(regs->r23, sc->sc_regs+23); err |= __get_user(regs->r24, sc->sc_regs+24); err |= __get_user(regs->r25, sc->sc_regs+25); err |= __get_user(regs->r26, sc->sc_regs+26); err |= __get_user(regs->r27, sc->sc_regs+27); err |= __get_user(regs->r28, sc->sc_regs+28); err |= __get_user(regs->gp, sc->sc_regs+29); err |= __get_user(usp, sc->sc_regs+30); wrusp(usp); for (i = 0; i < 31; i++) err |= __get_user(sw->fp[i], sc->sc_fpregs+i); err |= __get_user(sw->fp[31], &sc->sc_fpcr); return err; }
/* * Do necessary setup to start up a newly executed thread. * * pass the data segment into user programs if it exists, * it can't hurt anything as far as I can tell */ void start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) { regs->pc = new_ip; if (current->mm) regs->p5 = current->mm->start_data; #ifndef CONFIG_SMP task_thread_info(current)->l1_task_info.stack_start = (void *)current->mm->context.stack_start; task_thread_info(current)->l1_task_info.lowest_sp = (void *)new_sp; memcpy(L1_SCRATCH_TASK_INFO, &task_thread_info(current)->l1_task_info, sizeof(*L1_SCRATCH_TASK_INFO)); #endif wrusp(new_sp); }
static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) { struct rt_sigframe *frame; int err = 0; unsigned char *ret; frame = get_sigframe(ksig, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) return -EFAULT; if (ksig->ka.sa.sa_flags & SA_SIGINFO) err |= copy_siginfo_to_user(&frame->info, &ksig->info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __save_altstack(&frame->uc.uc_stack, rdusp()); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) return -EFAULT; /* Set up to return from userspace. */ ret = frame->retcode; if (ksig->ka.sa.sa_flags & SA_RESTORER) ret = (unsigned char *)(ksig->ka.sa.sa_restorer); else { /* sub.l er0,er0; mov.b #__NR_rt_sigreturn,r0l; trapa #0 */ err |= __put_user(0x1a80f800 + (__NR_rt_sigreturn & 0xff), (unsigned long *)(frame->retcode + 0)); err |= __put_user(0x5700, (unsigned short *)(frame->retcode + 4)); } err |= __put_user(ret, &frame->pretcode); if (err) return -EFAULT; /* Set up registers for signal handler */ wrusp((unsigned long) frame); regs->pc = (unsigned long) ksig->ka.sa.sa_handler; regs->er0 = ksig->sig; regs->er1 = (unsigned long)&(frame->info); regs->er2 = (unsigned long)&frame->uc; regs->er5 = current->mm->start_data; /* GOT base */ return 0; }
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; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(rdusp()), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= rt_setup_ucontext(&frame->uc, regs); err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); /* Set up to return from userspace. */ err |= __put_user(frame->retcode, &frame->pretcode); /* sub.l er0,er0; mov.b #__NR_rt_sigreturn,r0l; trapa #0 */ err != __put_user(0x1a80f800 + (__NR_rt_sigreturn & 0xff), (long *)(frame->retcode + 0)); err |= __put_user(0x5700, (short *)(frame->retcode + 4)); if (err) goto give_sigsegv; /* Set up registers for signal handler */ wrusp ((unsigned long) frame); regs->pc = (unsigned long) ka->sa.sa_handler; regs->er0 = (current_thread_info()->exec_domain && current_thread_info()->exec_domain->signal_invmap && sig < 32 ? current_thread_info()->exec_domain->signal_invmap[sig] : sig); regs->er1 = (unsigned long)&(frame->info); regs->er2 = (unsigned long)&frame->uc; regs->er5 = current->mm->start_data; /* GOT base */ return; give_sigsegv: force_sigsegv(sig, current); }
asmlinkage int do_sigreturn(unsigned long __unused) { struct sigcontext_struct context; struct pt_regs *regs; struct switch_stack *sw; int fsize = 0; unsigned long fp; unsigned long usp = rdusp(); #ifdef DEBUG printk("sys_sigreturn, usp=%08x\n", (unsigned) usp); #endif /* get stack frame pointer */ sw = (struct switch_stack *) &__unused; regs = (struct pt_regs *) (sw + 1); /* get previous context (including pointer to possible extra junk) */ if (verify_area(VERIFY_READ, (void *)usp, sizeof(context))) goto badframe; memcpy_fromfs(&context,(void *)usp, sizeof(context)); fp = usp + sizeof (context); /* restore signal mask */ current->blocked = context.sc_mask & _BLOCKABLE; /* restore passed registers */ regs->d0 = context.sc_d0; regs->d1 = context.sc_d1; regs->a0 = context.sc_a0; regs->a1 = context.sc_a1; regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); regs->pc = context.sc_pc; regs->orig_d0 = -1; /* disable syscall checks */ wrusp(context.sc_usp); if (context.sc_usp != fp+fsize) { #ifdef DEBUG printk("Stack off by %d\n",context.sc_usp - (fp+fsize)); #endif current->flags &= ~PF_ONSIGSTK; } return regs->d0; badframe: do_exit(SIGSEGV); }
static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) { unsigned long oldsp, r26, err = 0; struct sigframe __user *frame; oldsp = rdusp(); frame = get_sigframe(ka, oldsp, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) return -EFAULT; err |= setup_sigcontext(&frame->sc, regs, set->sig[0], oldsp); if (err) return -EFAULT; /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->ka_restorer) { r26 = (unsigned long) ka->ka_restorer; } else { err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); err |= __put_user(INSN_CALLSYS, frame->retcode+2); imb(); r26 = (unsigned long) frame->retcode; } /* Check that everything was written properly. */ if (err) return err; /* "Return" to the handler */ regs->r26 = r26; regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; regs->r16 = sig; /* a0: signal number */ regs->r17 = 0; /* a1: exception code */ regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */ wrusp((unsigned long) frame); #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->pc, regs->r26); #endif return 0; }
static void setup_frame (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) { struct sigframe *frame; struct sigcontext context; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); if (_NSIG_WORDS > 1) err |= copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); setup_sigcontext(&context, regs, set->sig[0]); err |= copy_to_user (&frame->sc, &context, sizeof(context)); /* Set up to return from userspace. */ err |= __put_user(frame->retcode, &frame->pretcode); /* sub.l er0,er0; mov.b #__NR_sigreturn,r0l; trapa #0 */ err != __put_user(0x1a80f800 + (__NR_sigreturn & 0xff), (unsigned long *)(frame->retcode + 0)); err |= __put_user(0x5700, (unsigned short *)(frame->retcode + 4)); if (err) goto give_sigsegv; /* Set up registers for signal handler */ wrusp ((unsigned long) frame); regs->pc = (unsigned long) ka->sa.sa_handler; regs->er0 = (current_thread_info()->exec_domain && current_thread_info()->exec_domain->signal_invmap && sig < 32 ? current_thread_info()->exec_domain->signal_invmap[sig] : sig); regs->er1 = (unsigned long)&(frame->sc); regs->er5 = current->mm->start_data; /* GOT base */ return; give_sigsegv: force_sigsegv(sig, current); }
static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { unsigned int err = 0; unsigned long old_usp; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; /* restore the regs from &sc->regs (same as sc, since regs is first) * (sc is already checked for VERIFY_READ since the sigframe was * checked in sys_sigreturn previously) */ if (__copy_from_user(regs, sc, sizeof(struct pt_regs))) goto badframe; /* make sure the U-flag is set so user-mode cannot fool us */ regs->dccr |= 1 << 8; /* restore the old USP as it was before we stacked the sc etc. * (we cannot just pop the sigcontext since we aligned the sp and * stuff after pushing it) */ err |= __get_user(old_usp, &sc->usp); wrusp(old_usp); /* TODO: the other ports use regs->orig_XX to disable syscall checks * after this completes, but we don't use that mechanism. maybe we can * use it now ? */ return err; badframe: return 1; }
static inline int rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *pr0) { unsigned long usp = 0; int err = 0; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; #define RESTORE(x) err |= __get_user(regs->x, &sc->sc_##x) /* restore passed registers */ RESTORE(r0); RESTORE(r1); RESTORE(r2); RESTORE(r3); RESTORE(r4); RESTORE(r5); RESTORE(r6); RESTORE(r7); RESTORE(p0); RESTORE(p1); RESTORE(p2); RESTORE(p3); RESTORE(p4); RESTORE(p5); err |= __get_user(usp, &sc->sc_usp); wrusp(usp); RESTORE(a0w); RESTORE(a1w); RESTORE(a0x); RESTORE(a1x); RESTORE(astat); RESTORE(rets); RESTORE(pc); RESTORE(retx); RESTORE(fp); RESTORE(i0); RESTORE(i1); RESTORE(i2); RESTORE(i3); RESTORE(m0); RESTORE(m1); RESTORE(m2); RESTORE(m3); RESTORE(l0); RESTORE(l1); RESTORE(l2); RESTORE(l3); RESTORE(b0); RESTORE(b1); RESTORE(b2); RESTORE(b3); RESTORE(lc0); RESTORE(lc1); RESTORE(lt0); RESTORE(lt1); RESTORE(lb0); RESTORE(lb1); RESTORE(seqstat); regs->orig_p0 = -1; /* disable syscall checks */ *pr0 = regs->r0; return err; }
static inline int rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *pr0) { unsigned long usp = 0; int err = 0; #define RESTORE(x) err |= __get_user(regs->x, &sc->sc_##x) /* restore passed registers */ RESTORE(r0); RESTORE(r1); RESTORE(r2); RESTORE(r3); RESTORE(r4); RESTORE(r5); RESTORE(r6); RESTORE(r7); RESTORE(p0); RESTORE(p1); RESTORE(p2); RESTORE(p3); RESTORE(p4); RESTORE(p5); err |= __get_user(usp, &sc->sc_usp); wrusp(usp); RESTORE(a0w); RESTORE(a1w); RESTORE(a0x); RESTORE(a1x); RESTORE(astat); RESTORE(rets); RESTORE(pc); RESTORE(retx); RESTORE(fp); RESTORE(i0); RESTORE(i1); RESTORE(i2); RESTORE(i3); RESTORE(m0); RESTORE(m1); RESTORE(m2); RESTORE(m3); RESTORE(l0); RESTORE(l1); RESTORE(l2); RESTORE(l3); RESTORE(b0); RESTORE(b1); RESTORE(b2); RESTORE(b3); RESTORE(lc0); RESTORE(lc1); RESTORE(lt0); RESTORE(lt1); RESTORE(lb0); RESTORE(lb1); RESTORE(seqstat); regs->orig_p0 = -1; /* disable syscall checks */ *pr0 = regs->r0; return err; }
static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { struct rt_sigframe __user *frame; unsigned long return_ip; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); if (err) goto give_sigsegv; /* Clear all the bits of the ucontext we don't use. */ err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) goto give_sigsegv; /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa.sa_flags & SA_RESTORER) { return_ip = (unsigned long)ka->sa.sa_restorer; } else { /* trampoline - the desired return ip is the retcode itself */ return_ip = (unsigned long)&frame->retcode; /* This is movu.w __NR_rt_sigreturn, r9; break 13; */ err |= __put_user(0x9c5f, (short __user *)(frame->retcode+0)); err |= __put_user(__NR_rt_sigreturn, (short __user *)(frame->retcode+2)); err |= __put_user(0xe93d, (short __user *)(frame->retcode+4)); } if (err) goto give_sigsegv; /* TODO what is the current->exec_domain stuff and invmap ? */ /* Set up registers for signal handler */ /* What we enter NOW */ regs->irp = (unsigned long) ka->sa.sa_handler; /* What we enter LATER */ regs->srp = return_ip; /* First argument is signo */ regs->r10 = sig; /* Second argument is (siginfo_t *) */ regs->r11 = (unsigned long)&frame->info; /* Third argument is unused */ regs->r12 = 0; /* Actually move the usp to reflect the stacked frame */ wrusp((unsigned long)frame); return 0; give_sigsegv: force_sigsegv(sig, current); return -EFAULT; }
static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { struct rt_sigframe __user *frame; unsigned long return_ip; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); if (err) goto give_sigsegv; err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) goto give_sigsegv; if (ka->sa.sa_flags & SA_RESTORER) { return_ip = (unsigned long)ka->sa.sa_restorer; } else { return_ip = (unsigned long)&frame->retcode; err |= __put_user(0x9c5f, (short __user *)(frame->retcode+0)); err |= __put_user(__NR_rt_sigreturn, (short __user *)(frame->retcode+2)); err |= __put_user(0xe93d, (short __user *)(frame->retcode+4)); } if (err) goto give_sigsegv; regs->irp = (unsigned long) ka->sa.sa_handler; regs->srp = return_ip; regs->r10 = sig; regs->r11 = (unsigned long)&frame->info; regs->r12 = 0; wrusp((unsigned long)frame); return 0; give_sigsegv: force_sigsegv(sig, current); return -EFAULT; }
static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { struct rt_sigframe *frame; int err = 0; int usig; unsigned char *ret; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; usig = current_thread_info()->exec_domain && current_thread_info()->exec_domain->signal_invmap && sig < 32 ? current_thread_info()->exec_domain->signal_invmap[sig] : sig; err |= __put_user(usig, &frame->sig); if (err) goto give_sigsegv; err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); if (err) goto give_sigsegv; /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(rdusp()), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) goto give_sigsegv; /* Set up to return from userspace. */ ret = frame->retcode; if (ka->sa.sa_flags & SA_RESTORER) ret = (unsigned char *)(ka->sa.sa_restorer); else { /* sub.l er0,er0; mov.b #__NR_sigreturn,r0l; trapa #0 */ err |= __put_user(0x1a80f800 + (__NR_sigreturn & 0xff), (unsigned long *)(frame->retcode + 0)); err |= __put_user(0x5700, (unsigned short *)(frame->retcode + 4)); } err |= __put_user(ret, &frame->pretcode); if (err) goto give_sigsegv; /* Set up registers for signal handler */ wrusp ((unsigned long) frame); regs->pc = (unsigned long) ka->sa.sa_handler; regs->er0 = (current_thread_info()->exec_domain && current_thread_info()->exec_domain->signal_invmap && sig < 32 ? current_thread_info()->exec_domain->signal_invmap[sig] : sig); regs->er1 = (unsigned long)&(frame->info); regs->er2 = (unsigned long)&frame->uc; regs->er5 = current->mm->start_data; /* GOT base */ return 0; give_sigsegv: force_sigsegv(sig, current); return -EFAULT; }
static void setup_frame (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) { struct sigframe *frame; int err = 0; int usig; unsigned char *ret; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; usig = current_thread_info()->exec_domain && current_thread_info()->exec_domain->signal_invmap && sig < 32 ? current_thread_info()->exec_domain->signal_invmap[sig] : sig; err |= __put_user(usig, &frame->sig); if (err) goto give_sigsegv; err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); if (err) goto give_sigsegv; if (_NSIG_WORDS > 1) { err |= copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); if (err) goto give_sigsegv; } ret = frame->retcode; if (ka->sa.sa_flags & SA_RESTORER) ret = (unsigned char *)(ka->sa.sa_restorer); else { /* sub.l er0,er0; mov.b #__NR_sigreturn,r0l; trapa #0 */ err != __put_user(0x1a80f800 + (__NR_sigreturn & 0xff), (unsigned long *)(frame->retcode + 0)); err |= __put_user(0x5700, (unsigned short *)(frame->retcode + 4)); } /* Set up to return from userspace. */ err |= __put_user(ret, &frame->pretcode); if (err) goto give_sigsegv; /* Set up registers for signal handler */ wrusp ((unsigned long) frame); regs->pc = (unsigned long) ka->sa.sa_handler; regs->er0 = (current_thread_info()->exec_domain && current_thread_info()->exec_domain->signal_invmap && sig < 32 ? current_thread_info()->exec_domain->signal_invmap[sig] : sig); regs->er1 = (unsigned long)&(frame->sc); regs->er5 = current->mm->start_data; /* GOT base */ return; give_sigsegv: force_sigsegv(sig, current); }
static void setup_frame (struct sigaction * sa, struct pt_regs *regs, int signr, unsigned long oldmask) { struct sigcontext_struct context; unsigned long *frame, *tframe; #define fsize 0 frame = (unsigned long *)rdusp(); if (!(current->flags & PF_ONSIGSTK) && (sa->sa_flags & SA_STACK)) { frame = (unsigned long *)sa->sa_restorer; current->flags |= PF_ONSIGSTK; } #ifdef DEBUG printk("setup_frame: usp %.8x\n",frame); #endif frame -= UFRAME_SIZE(fsize); #ifdef DEBUG printk("setup_frame: frame %.8x\n",frame); #endif if (verify_area(VERIFY_WRITE,frame,UFRAME_SIZE(fsize)*4)) do_exit(SIGSEGV); if (fsize) { memcpy_tofs (frame + UFRAME_SIZE(0), regs + 1, fsize); regs->stkadj = fsize; } /* set up the "normal" stack seen by the signal handler */ tframe = frame; /* return address points to code on stack */ put_user((ulong)(frame+4), tframe); tframe++; if (current->exec_domain && current->exec_domain->signal_invmap) put_user(current->exec_domain->signal_invmap[signr], tframe); else put_user(signr, tframe); tframe++; tframe++; /* "scp" parameter. points to sigcontext */ put_user((ulong)(frame+6), tframe); tframe++; /* set up the return code... */ put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */ put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */ /* setup and copy the sigcontext structure */ context.sc_mask = oldmask; context.sc_usp = rdusp(); context.sc_d0 = regs->d0; context.sc_d1 = regs->d1; context.sc_a0 = regs->a0; context.sc_a1 = regs->a1; context.sc_sr = regs->sr; context.sc_pc = regs->pc; memcpy_tofs (tframe, &context, sizeof(context)); #ifdef DEBUG printk("setup_frame: top tframe %.8x\n",tframe + sizeof(context)); #endif /* Set up registers for signal handler */ wrusp ((unsigned long) frame); regs->pc = (unsigned long) sa->sa_handler; /* Prepare to skip over the extra stuff in the exception frame. */ if (regs->stkadj) { struct pt_regs *tregs = (struct pt_regs *)((ulong)regs + regs->stkadj); #ifdef DEBUG printk("Performing stackadjust=%04x\n", regs->stkadj); #endif /* This must be copied with decreasing addresses to handle overlaps. */ tregs->pc = regs->pc; tregs->sr = regs->sr; } }