Esempio n. 1
0
static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
		       int signo, sigset_t *oldset)
{
	struct signal_frame __user *sf;
	int sigframe_size, err, wsaved;
	void __user *tail;

	/* 1. Make sure everything is clean */
	synchronize_user_stack();

	wsaved = current_thread_info()->w_saved;

	sigframe_size = sizeof(*sf);
	if (used_math())
		sigframe_size += sizeof(__siginfo_fpu_t);
	if (wsaved)
		sigframe_size += sizeof(__siginfo_rwin_t);

	sf = (struct signal_frame __user *)
		get_sigframe(&ka->sa, regs, sigframe_size);

	if (invalid_frame_pointer(sf, sigframe_size))
		goto sigill_and_return;

	tail = sf + 1;

	/* 2. Save the current process state */
	err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
	
	err |= __put_user(0, &sf->extra_size);

	if (used_math()) {
		__siginfo_fpu_t __user *fp = tail;
		tail += sizeof(*fp);
		err |= save_fpu_state(regs, fp);
		err |= __put_user(fp, &sf->fpu_save);
	} else {
		err |= __put_user(0, &sf->fpu_save);
	}
	if (wsaved) {
		__siginfo_rwin_t __user *rwp = tail;
		tail += sizeof(*rwp);
		err |= save_rwin_state(wsaved, rwp);
		err |= __put_user(rwp, &sf->rwin_save);
	} else {
		err |= __put_user(0, &sf->rwin_save);
	}

	err |= __put_user(oldset->sig[0], &sf->info.si_mask);
	err |= __copy_to_user(sf->extramask, &oldset->sig[1],
			      (_NSIG_WORDS - 1) * sizeof(unsigned int));
	if (!wsaved) {
		err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
				      sizeof(struct reg_window32));
	} else {
		struct reg_window32 *rp;

		rp = &current_thread_info()->reg_window[wsaved - 1];
		err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
	}
	if (err)
		goto sigsegv;
	
	/* 3. signal handler back-trampoline and parameters */
	regs->u_regs[UREG_FP] = (unsigned long) sf;
	regs->u_regs[UREG_I0] = signo;
	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
	regs->u_regs[UREG_I2] = (unsigned long) &sf->info;

	/* 4. signal handler */
	regs->pc = (unsigned long) ka->sa.sa_handler;
	regs->npc = (regs->pc + 4);

	/* 5. return to kernel instructions */
	if (ka->ka_restorer)
		regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
	else {
		regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);

		/* mov __NR_sigreturn, %g1 */
		err |= __put_user(0x821020d8, &sf->insns[0]);

		/* t 0x10 */
		err |= __put_user(0x91d02010, &sf->insns[1]);
		if (err)
			goto sigsegv;

		/* Flush instruction space. */
		flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
	}
	return 0;

sigill_and_return:
	do_exit(SIGILL);
	return -EINVAL;

sigsegv:
	force_sigsegv(signo, current);
	return -EFAULT;
}
Esempio n. 2
0
static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
			  int signo, sigset_t *oldset, siginfo_t *info)
{
	struct rt_signal_frame __user *sf;
	int sigframe_size, wsaved;
	void __user *tail;
	unsigned int psr;
	int err;

	synchronize_user_stack();
	wsaved = current_thread_info()->w_saved;
	sigframe_size = sizeof(*sf);
	if (used_math())
		sigframe_size += sizeof(__siginfo_fpu_t);
	if (wsaved)
		sigframe_size += sizeof(__siginfo_rwin_t);
	sf = (struct rt_signal_frame __user *)
		get_sigframe(&ka->sa, regs, sigframe_size);
	if (invalid_frame_pointer(sf, sigframe_size))
		goto sigill;

	tail = sf + 1;
	err  = __put_user(regs->pc, &sf->regs.pc);
	err |= __put_user(regs->npc, &sf->regs.npc);
	err |= __put_user(regs->y, &sf->regs.y);
	psr = regs->psr;
	if (used_math())
		psr |= PSR_EF;
	err |= __put_user(psr, &sf->regs.psr);
	err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs));
	err |= __put_user(0, &sf->extra_size);

	if (psr & PSR_EF) {
		__siginfo_fpu_t *fp = tail;
		tail += sizeof(*fp);
		err |= save_fpu_state(regs, fp);
		err |= __put_user(fp, &sf->fpu_save);
	} else {
		err |= __put_user(0, &sf->fpu_save);
	}
	if (wsaved) {
		__siginfo_rwin_t *rwp = tail;
		tail += sizeof(*rwp);
		err |= save_rwin_state(wsaved, rwp);
		err |= __put_user(rwp, &sf->rwin_save);
	} else {
		err |= __put_user(0, &sf->rwin_save);
	}
	err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
	
	/* Setup sigaltstack */
	err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
	err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
	err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
	
	if (!wsaved) {
		err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
				      sizeof(struct reg_window32));
	} else {
		struct reg_window32 *rp;

		rp = &current_thread_info()->reg_window[wsaved - 1];
		err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
	}

	err |= copy_siginfo_to_user(&sf->info, info);

	if (err)
		goto sigsegv;

	regs->u_regs[UREG_FP] = (unsigned long) sf;
	regs->u_regs[UREG_I0] = signo;
	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
	regs->u_regs[UREG_I2] = (unsigned long) &sf->regs;

	regs->pc = (unsigned long) ka->sa.sa_handler;
	regs->npc = (regs->pc + 4);

	if (ka->ka_restorer)
		regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
	else {
		regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);

		/* mov __NR_sigreturn, %g1 */
		err |= __put_user(0x821020d8, &sf->insns[0]);

		/* t 0x10 */
		err |= __put_user(0x91d02010, &sf->insns[1]);
		if (err)
			goto sigsegv;

		/* Flush instruction space. */
		flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
	}
	return 0;

sigill:
	do_exit(SIGILL);
	return -EINVAL;

sigsegv:
	force_sigsegv(signo, current);
	return -EFAULT;
}
Esempio n. 3
0
File: signal.c Progetto: 274914765/C
static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
            int signo, sigset_t *oldset)
{
    struct signal_frame __user *sf;
    int sigframe_size, err;

    /* 1. Make sure everything is clean */
    synchronize_user_stack();

    sigframe_size = SF_ALIGNEDSZ;
    if (!used_math())
        sigframe_size -= sizeof(__siginfo_fpu_t);

    sf = (struct signal_frame __user *)
        get_sigframe(&ka->sa, regs, sigframe_size);

    if (invalid_frame_pointer(sf, sigframe_size))
        goto sigill_and_return;

    if (current_thread_info()->w_saved != 0)
        goto sigill_and_return;

    /* 2. Save the current process state */
    err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
    
    err |= __put_user(0, &sf->extra_size);

    if (used_math()) {
        err |= save_fpu_state(regs, &sf->fpu_state);
        err |= __put_user(&sf->fpu_state, &sf->fpu_save);
    } else {
        err |= __put_user(0, &sf->fpu_save);
    }

    err |= __put_user(oldset->sig[0], &sf->info.si_mask);
    err |= __copy_to_user(sf->extramask, &oldset->sig[1],
                  (_NSIG_WORDS - 1) * sizeof(unsigned int));
    err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
                  sizeof(struct reg_window));
    if (err)
        goto sigsegv;
    
    /* 3. signal handler back-trampoline and parameters */
    regs->u_regs[UREG_FP] = (unsigned long) sf;
    regs->u_regs[UREG_I0] = signo;
    regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
    regs->u_regs[UREG_I2] = (unsigned long) &sf->info;

    /* 4. signal handler */
    regs->pc = (unsigned long) ka->sa.sa_handler;
    regs->npc = (regs->pc + 4);

    /* 5. return to kernel instructions */
    if (ka->ka_restorer)
        regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
    else {
        regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);

        /* mov __NR_sigreturn, %g1 */
        err |= __put_user(0x821020d8, &sf->insns[0]);

        /* t 0x10 */
        err |= __put_user(0x91d02010, &sf->insns[1]);
        if (err)
            goto sigsegv;

        /* Flush instruction space. */
        flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
    }
    return;

sigill_and_return:
    do_exit(SIGILL);
sigsegv:
    force_sigsegv(signo, current);
}