static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
			   sigset_t *set, struct pt_regs * regs)
{
	int err = 0;
	rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));

	if (frame == (void __user *) -1UL)
		goto give_sigsegv;

	if (copy_siginfo_to_user32(&frame->info, info))
		goto give_sigsegv;

	/* Create the ucontext.  */
	err |= __put_user(UC_EXTENDED, &frame->uc.uc_flags);
	err |= __put_user(0, &frame->uc.uc_link);
	err |= __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]);
	err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
	err |= save_sigregs_gprs_high(regs, frame->gprs_high);
	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) {
		regs->gprs[14] = (__u64 __force) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
	} else {
		regs->gprs[14] = (__u64 __force) frame->retcode | PSW32_ADDR_AMODE;
		if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
			       (u16 __force __user *)(frame->retcode)))
			goto give_sigsegv;
	}

	/* Set up backchain. */
	if (__put_user(regs->gprs[15], (unsigned int __force __user *) frame))
		goto give_sigsegv;

	/* Set up registers for signal handler */
	regs->gprs[15] = (__force __u64) frame;
	/* Force 31 bit amode and default user address space control. */
	regs->psw.mask = PSW_MASK_BA |
		(PSW_USER_BITS & PSW_MASK_ASC) |
		(regs->psw.mask & ~PSW_MASK_ASC);
	regs->psw.addr = (__u64 __force) ka->sa.sa_handler;

	regs->gprs[2] = map_signal(sig);
	regs->gprs[3] = (__force __u64) &frame->info;
	regs->gprs[4] = (__force __u64) &frame->uc;
	regs->gprs[5] = task_thread_info(current)->last_break;
	return 0;

give_sigsegv:
	force_sigsegv(sig, current);
	return -EFAULT;
}
static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
			   sigset_t *set, struct pt_regs * regs)
{
	int err = 0;
	rt_sigframe32 *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));
	if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32)))
		goto give_sigsegv;

	if (copy_siginfo_to_user32(&frame->info, info))
		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(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
	err |= __put_user(sas_ss_flags(regs->gprs[15]),
	                  &frame->uc.uc_stack.ss_flags);
	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
	err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
	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) {
		regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
	} else {
		regs->gprs[14] = FIX_PSW(frame->retcode);
		err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
		                  (u16 *)(frame->retcode));
	}

	/* Set up backchain. */
	if (__put_user((unsigned int) regs->gprs[15], (unsigned int *) frame))
		goto give_sigsegv;

	/* Set up registers for signal handler */
	regs->gprs[15] = (addr_t)frame;
	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
	regs->psw.mask = _USER_PSW_MASK32;

	regs->gprs[2] = map_signal(sig);
	regs->gprs[3] = (addr_t)&frame->info;
	regs->gprs[4] = (addr_t)&frame->uc;
	return;

give_sigsegv:
	if (sig == SIGSEGV)
		ka->sa.sa_handler = SIG_DFL;
	force_sig(SIGSEGV, current);
}
Esempio n. 3
0
static int setup_frame32(int sig, struct k_sigaction *ka,
			sigset_t *set, struct pt_regs * regs)
{
	sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32));
	if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32)))
		goto give_sigsegv;

	if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32))
		goto give_sigsegv;

	if (save_sigregs32(regs, &frame->sregs))
		goto give_sigsegv;
	if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))
		goto give_sigsegv;

	/* Set up to return from userspace.  If provided, use a stub
	   already in userspace.  */
	if (ka->sa.sa_flags & SA_RESTORER) {
		regs->gprs[14] = (__u64) ka->sa.sa_restorer;
	} else {
		regs->gprs[14] = (__u64) frame->retcode;
		if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
		               (u16 __user *)(frame->retcode)))
			goto give_sigsegv;
        }

	/* Set up backchain. */
	if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
		goto give_sigsegv;

	/* Set up registers for signal handler */
	regs->gprs[15] = (__u64) frame;
	regs->psw.addr = (__u64) ka->sa.sa_handler;

	regs->gprs[2] = map_signal(sig);
	regs->gprs[3] = (__u64) &frame->sc;

	/* We forgot to include these in the sigcontext.
	   To avoid breaking binary compatibility, they are passed as args. */
	regs->gprs[4] = current->thread.trap_no;
	regs->gprs[5] = current->thread.prot_addr;

	/* Place signal number on stack to allow backtrace from handler.  */
	if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
		goto give_sigsegv;
	return 0;

give_sigsegv:
	force_sigsegv(sig, current);
	return -EFAULT;
}
static void setup_frame32(int sig, struct k_sigaction *ka,
			sigset_t *set, struct pt_regs * regs)
{
	sigframe32 *frame = get_sigframe(ka, regs, sizeof(sigframe32));
	if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32)))
		goto give_sigsegv;

	if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32))
		goto give_sigsegv;

	if (save_sigregs32(regs, &frame->sregs))
		goto give_sigsegv;
	if (__put_user(&frame->sregs, &frame->sc.sregs))
		goto give_sigsegv;

	/* Set up to return from userspace.  If provided, use a stub
	   already in userspace.  */
	if (ka->sa.sa_flags & SA_RESTORER) {
		regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
	} else {
		regs->gprs[14] = FIX_PSW(frame->retcode);
		if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
		               (u16 *)(frame->retcode)))
			goto give_sigsegv;
        }

	/* Set up backchain. */
	if (__put_user((unsigned int) regs->gprs[15], (unsigned int *) frame))
		goto give_sigsegv;

	/* Set up registers for signal handler */
	regs->gprs[15] = (addr_t)frame;
	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
	regs->psw.mask = _USER_PSW_MASK32;

	regs->gprs[2] = map_signal(sig);
	regs->gprs[3] = (addr_t)&frame->sc;

	/* We forgot to include these in the sigcontext.
	   To avoid breaking binary compatibility, they are passed as args. */
	regs->gprs[4] = current->thread.trap_no;
	regs->gprs[5] = current->thread.prot_addr;
	return;

give_sigsegv:
	if (sig == SIGSEGV)
		ka->sa.sa_handler = SIG_DFL;
	force_sig(SIGSEGV, current);
}
static int setup_frame32(int sig, struct k_sigaction *ka,
			sigset_t *set, struct pt_regs * regs)
{
	sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32));

	if (frame == (void __user *) -1UL)
		goto give_sigsegv;

	if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32))
		goto give_sigsegv;

	if (save_sigregs32(regs, &frame->sregs))
		goto give_sigsegv;
	if (save_sigregs_gprs_high(regs, frame->gprs_high))
		goto give_sigsegv;
	if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))
		goto give_sigsegv;

	/* Set up to return from userspace.  If provided, use a stub
	   already in userspace.  */
	if (ka->sa.sa_flags & SA_RESTORER) {
		regs->gprs[14] = (__u64 __force) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
	} else {
		regs->gprs[14] = (__u64 __force) frame->retcode | PSW32_ADDR_AMODE;
		if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
			       (u16 __force __user *)(frame->retcode)))
			goto give_sigsegv;
        }

	/* Set up backchain. */
	if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
		goto give_sigsegv;

	/* Set up registers for signal handler */
	regs->gprs[15] = (__force __u64) frame;
	/* Force 31 bit amode and default user address space control. */
	regs->psw.mask = PSW_MASK_BA |
		(psw_user_bits & PSW_MASK_ASC) |
		(regs->psw.mask & ~PSW_MASK_ASC);
	regs->psw.addr = (__force __u64) ka->sa.sa_handler;

	regs->gprs[2] = map_signal(sig);
	regs->gprs[3] = (__force __u64) &frame->sc;

	/* We forgot to include these in the sigcontext.
	   To avoid breaking binary compatibility, they are passed as args. */
	if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
	    sig == SIGTRAP || sig == SIGFPE) {
		/* set extra registers only for synchronous signals */
		regs->gprs[4] = regs->int_code & 127;
		regs->gprs[5] = regs->int_parm_long;
		regs->gprs[6] = task_thread_info(current)->last_break;
	}

	/* Place signal number on stack to allow backtrace from handler.  */
	if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
		goto give_sigsegv;
	return 0;

give_sigsegv:
	force_sigsegv(sig, current);
	return -EFAULT;
}
static int setup_rt_frame32(struct ksignal *ksig, sigset_t *set,
                            struct pt_regs *regs)
{
    compat_sigset_t cset;
    rt_sigframe32 __user *frame;
    unsigned long restorer;
    size_t frame_size;
    u32 uc_flags;

    frame_size = sizeof(*frame) -
                 sizeof(frame->uc.uc_mcontext_ext.__reserved);
    /*
     * gprs_high are always present for 31-bit compat tasks.
     * The space for vector registers is only allocated if
     * the machine supports it
     */
    uc_flags = UC_GPRS_HIGH;
    if (MACHINE_HAS_VX) {
        if (current->thread.vxrs)
            uc_flags |= UC_VXRS;
    } else
        frame_size -= sizeof(frame->uc.uc_mcontext_ext.vxrs_low) +
                      sizeof(frame->uc.uc_mcontext_ext.vxrs_high);
    frame = get_sigframe(&ksig->ka, regs, frame_size);
    if (frame == (void __user *) -1UL)
        return -EFAULT;

    /* Set up backchain. */
    if (__put_user(regs->gprs[15], (unsigned int __force __user *) frame))
        return -EFAULT;

    /* Set up to return from userspace.  If provided, use a stub
       already in userspace.  */
    if (ksig->ka.sa.sa_flags & SA_RESTORER) {
        restorer = (unsigned long __force)
                   ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE;
    } else {
        __u16 __user *svc = &frame->svc_insn;
        if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, svc))
            return -EFAULT;
        restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE;
    }

    /* Create siginfo on the signal stack */
    if (copy_siginfo_to_user32(&frame->info, &ksig->info))
        return -EFAULT;

    /* Store registers needed to create the signal frame */
    store_sigregs();

    /* Create ucontext on the signal stack. */
    sigset_to_sigset32(set->sig, cset.sig);
    if (__put_user(uc_flags, &frame->uc.uc_flags) ||
            __put_user(0, &frame->uc.uc_link) ||
            __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]) ||
            save_sigregs32(regs, &frame->uc.uc_mcontext) ||
            __copy_to_user(&frame->uc.uc_sigmask, &cset, sizeof(cset)) ||
            save_sigregs_ext32(regs, &frame->uc.uc_mcontext_ext))
        return -EFAULT;

    /* Set up registers for signal handler */
    regs->gprs[14] = restorer;
    regs->gprs[15] = (__force __u64) frame;
    /* Force 31 bit amode and default user address space control. */
    regs->psw.mask = PSW_MASK_BA |
                     (PSW_USER_BITS & PSW_MASK_ASC) |
                     (regs->psw.mask & ~PSW_MASK_ASC);
    regs->psw.addr = (__u64 __force) ksig->ka.sa.sa_handler;

    regs->gprs[2] = map_signal(ksig->sig);
    regs->gprs[3] = (__force __u64) &frame->info;
    regs->gprs[4] = (__force __u64) &frame->uc;
    regs->gprs[5] = task_thread_info(current)->last_break;
    return 0;
}
static int setup_frame32(struct ksignal *ksig, sigset_t *set,
                         struct pt_regs *regs)
{
    int sig = ksig->sig;
    sigframe32 __user *frame;
    struct sigcontext32 sc;
    unsigned long restorer;
    size_t frame_size;

    /*
     * gprs_high are always present for 31-bit compat tasks.
     * The space for vector registers is only allocated if
     * the machine supports it
     */
    frame_size = sizeof(*frame) - sizeof(frame->sregs_ext.__reserved);
    if (!MACHINE_HAS_VX)
        frame_size -= sizeof(frame->sregs_ext.vxrs_low) +
                      sizeof(frame->sregs_ext.vxrs_high);
    frame = get_sigframe(&ksig->ka, regs, frame_size);
    if (frame == (void __user *) -1UL)
        return -EFAULT;

    /* Set up backchain. */
    if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
        return -EFAULT;

    /* Create struct sigcontext32 on the signal stack */
    sigset_to_sigset32(set->sig, sc.oldmask);
    sc.sregs = (__u32)(unsigned long __force) &frame->sregs;
    if (__copy_to_user(&frame->sc, &sc, sizeof(frame->sc)))
        return -EFAULT;

    /* Store registers needed to create the signal frame */
    store_sigregs();

    /* Create _sigregs32 on the signal stack */
    if (save_sigregs32(regs, &frame->sregs))
        return -EFAULT;

    /* Place signal number on stack to allow backtrace from handler.  */
    if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
        return -EFAULT;

    /* Create _sigregs_ext32 on the signal stack */
    if (save_sigregs_ext32(regs, &frame->sregs_ext))
        return -EFAULT;

    /* Set up to return from userspace.  If provided, use a stub
       already in userspace.  */
    if (ksig->ka.sa.sa_flags & SA_RESTORER) {
        restorer = (unsigned long __force)
                   ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE;
    } else {
        /* Signal frames without vectors registers are short ! */
        __u16 __user *svc = (void *) frame + frame_size - 2;
        if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc))
            return -EFAULT;
        restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE;
    }

    /* Set up registers for signal handler */
    regs->gprs[14] = restorer;
    regs->gprs[15] = (__force __u64) frame;
    /* Force 31 bit amode and default user address space control. */
    regs->psw.mask = PSW_MASK_BA |
                     (PSW_USER_BITS & PSW_MASK_ASC) |
                     (regs->psw.mask & ~PSW_MASK_ASC);
    regs->psw.addr = (__force __u64) ksig->ka.sa.sa_handler;

    regs->gprs[2] = map_signal(sig);
    regs->gprs[3] = (__force __u64) &frame->sc;

    /* We forgot to include these in the sigcontext.
       To avoid breaking binary compatibility, they are passed as args. */
    if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
            sig == SIGTRAP || sig == SIGFPE) {
        /* set extra registers only for synchronous signals */
        regs->gprs[4] = regs->int_code & 127;
        regs->gprs[5] = regs->int_parm_long;
        regs->gprs[6] = task_thread_info(current)->last_break;
    }

    return 0;
}