in kernel/signal.c [154:227]
static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
int err = 0, sig = ksig->sig;
unsigned long address = 0;
pmd_t *pmdp;
pte_t *ptep;
frame = get_sigframe(ksig, regs, sizeof(*frame));
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 ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(NULL, &frame->uc.uc_link);
err |= __save_altstack(&frame->uc.uc_stack, regs->r1);
err |= setup_sigcontext(&frame->uc.uc_mcontext,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
/* minus 8 is offset to cater for "rtsd r15,8" */
/* addi r12, r0, __NR_sigreturn */
err |= __put_user(0x31800000 | __NR_rt_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;
address = ((unsigned long)frame->tramp);
pmdp = pmd_off(current->mm, address);
preempt_disable();
ptep = pte_offset_map(pmdp, address);
if (pte_present(*ptep)) {
address = (unsigned long) page_address(pte_page(*ptep));
/* MS: I need add offset in page */
address += ((unsigned long)frame->tramp) & ~PAGE_MASK;
/* MS address is virtual */
address = __virt_to_phys(address);
invalidate_icache_range(address, address + 8);
flush_dcache_range(address, address + 8);
}
pte_unmap(ptep);
preempt_enable();
if (err)
return -EFAULT;
/* Set up registers for signal handler */
regs->r1 = (unsigned long) frame;
/* Signal handler args: */
regs->r5 = sig; /* arg 0: signum */
regs->r6 = (unsigned long) &frame->info; /* arg 1: siginfo */
regs->r7 = (unsigned long) &frame->uc; /* arg2: ucontext */
/* Offset to handle microblaze rtid r14, 0 */
regs->pc = (unsigned long)ksig->ka.sa.sa_handler;
#ifdef DEBUG_SIG
pr_info("SIG deliver (%s:%d): sp=%p pc=%08lx\n",
current->comm, current->pid, frame, regs->pc);
#endif
return 0;
}