static int setup_frame()

in kernel/signal.c [341:422]


static int setup_frame(struct ksignal *ksig, sigset_t *set,
		       struct pt_regs *regs)
{
	struct rt_sigframe *frame;
	int err = 0, sig = ksig->sig;
	unsigned long sp, ra, tp, ps;
	unsigned int base;

	sp = regs->areg[1];

	if ((ksig->ka.sa.sa_flags & SA_ONSTACK) != 0 && sas_ss_flags(sp) == 0) {
		sp = current->sas_ss_sp + current->sas_ss_size;
	}

	frame = (void *)((sp - sizeof(*frame)) & -16ul);

	if (regs->depc > 64)
		panic ("Double exception sys_sigreturn\n");

	if (!access_ok(frame, sizeof(*frame))) {
		return -EFAULT;
	}

	if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
		err |= copy_siginfo_to_user(&frame->info, &ksig->info);
	}

	/* Create the user context.  */

	err |= __put_user(0, &frame->uc.uc_flags);
	err |= __put_user(0, &frame->uc.uc_link);
	err |= __save_altstack(&frame->uc.uc_stack, regs->areg[1]);
	err |= setup_sigcontext(frame, regs);
	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));

	if (ksig->ka.sa.sa_flags & SA_RESTORER) {
		ra = (unsigned long)ksig->ka.sa.sa_restorer;
	} else {

		/* Create sys_rt_sigreturn syscall in stack frame */

		err |= gen_return_code(frame->retcode);

		if (err) {
			return -EFAULT;
		}
		ra = (unsigned long) frame->retcode;
	}

	/* 
	 * Create signal handler execution context.
	 * Return context not modified until this point.
	 */

	/* Set up registers for signal handler; preserve the threadptr */
	tp = regs->threadptr;
	ps = regs->ps;
	start_thread(regs, (unsigned long) ksig->ka.sa.sa_handler,
		     (unsigned long) frame);

	/* Set up a stack frame for a call4 if userspace uses windowed ABI */
	if (ps & PS_WOE_MASK) {
		base = 4;
		regs->areg[base] =
			(((unsigned long) ra) & 0x3fffffff) | 0x40000000;
		ps = (ps & ~(PS_CALLINC_MASK | PS_OWB_MASK)) |
			(1 << PS_CALLINC_SHIFT);
	} else {
		base = 0;
		regs->areg[base] = (unsigned long) ra;
	}
	regs->areg[base + 2] = (unsigned long) sig;
	regs->areg[base + 3] = (unsigned long) &frame->info;
	regs->areg[base + 4] = (unsigned long) &frame->uc;
	regs->threadptr = tp;
	regs->ps = ps;

	pr_debug("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08lx\n",
		 current->comm, current->pid, sig, frame, regs->pc);

	return 0;
}