コード例 #1
0
asmlinkage int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
{
    int err = 0;

    /* Always make any pending restarted system calls return -EINTR */
    current_thread_info()->restart_block.fn = do_no_restart_syscall;

    err |= __get_user(regs->cp0_epc, &sc->sc_pc);
    err |= __get_user(regs->hi, &sc->sc_mdhi);
    err |= __get_user(regs->lo, &sc->sc_mdlo);

#define restore_gp_reg(i) do {						\
	err |= __get_user(regs->regs[i], &sc->sc_regs[i]);		\
} while(0)
    restore_gp_reg( 1);
    restore_gp_reg( 2);
    restore_gp_reg( 3);
    restore_gp_reg( 4);
    restore_gp_reg( 5);
    restore_gp_reg( 6);
    restore_gp_reg( 7);
    restore_gp_reg( 8);
    restore_gp_reg( 9);
    restore_gp_reg(10);
    restore_gp_reg(11);
    restore_gp_reg(12);
    restore_gp_reg(13);
    restore_gp_reg(14);
    restore_gp_reg(15);
    restore_gp_reg(16);
    restore_gp_reg(17);
    restore_gp_reg(18);
    restore_gp_reg(19);
    restore_gp_reg(20);
    restore_gp_reg(21);
    restore_gp_reg(22);
    restore_gp_reg(23);
    restore_gp_reg(24);
    restore_gp_reg(25);
    restore_gp_reg(26);
    restore_gp_reg(27);
    restore_gp_reg(28);
    restore_gp_reg(29);
    restore_gp_reg(30);
    restore_gp_reg(31);
#undef restore_gp_reg

    err |= __get_user(current->used_math, &sc->sc_used_math);

    if (current->used_math) {
        /* restore fpu context if we have used it before */
        own_fpu();
        err |= restore_fp_context(sc);
    } else {
        /* signal handler may have used FPU.  Give it up. */
        lose_fpu();
    }

    return err;
}
コード例 #2
0
ファイル: signal.c プロジェクト: 0x000000FF/edison-linux
static int protected_restore_fp_context(struct sigcontext __user *sc)
{
	int err, tmp __maybe_unused;
#ifndef CONFIG_EVA
	while (1) {
		lock_fpu_owner();
		if (is_fpu_owner()) {
			err = restore_fp_context(sc);
			unlock_fpu_owner();
		} else {
			unlock_fpu_owner();
			err = copy_fp_from_sigcontext(sc);
		}
		if (likely(!err))
			break;
		/* touch the sigcontext and try again */
		err = __get_user(tmp, &sc->sc_fpregs[0]) |
			__get_user(tmp, &sc->sc_fpregs[31]) |
			__get_user(tmp, &sc->sc_fpc_csr);
		if (err)
			break;	/* really bad sigcontext */
	}
#else
	/*
	 * EVA does not have FPU EVA instructions so restoring fpu context
	 * directly does not work.
	 */
	lose_fpu(0);
	err = restore_fp_context(sc); /* this might fail */
#endif
	return err;
}
コード例 #3
0
ファイル: signal.c プロジェクト: 0x000000FF/edison-linux
/*
 * Helper routines
 */
static int protected_save_fp_context(struct sigcontext __user *sc)
{
	int err;
#ifndef CONFIG_EVA
	while (1) {
		lock_fpu_owner();
		if (is_fpu_owner()) {
			err = save_fp_context(sc);
			unlock_fpu_owner();
		} else {
			unlock_fpu_owner();
			err = copy_fp_to_sigcontext(sc);
		}
		if (likely(!err))
			break;
		/* touch the sigcontext and try again */
		err = __put_user(0, &sc->sc_fpregs[0]) |
			__put_user(0, &sc->sc_fpregs[31]) |
			__put_user(0, &sc->sc_fpc_csr);
		if (err)
			break;	/* really bad sigcontext */
	}
#else
	/*
	 * EVA does not have FPU EVA instructions so saving fpu context directly
	 * does not work.
	 */
	lose_fpu(1);
	err = save_fp_context(sc); /* this might fail */
#endif
	return err;
}
コード例 #4
0
ファイル: signal32.c プロジェクト: FatSunHYS/OSCourseDesign
static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc)
{
	u32 used_math;
	int err = 0;
	s32 treg;

	/* Always make any pending restarted system calls return -EINTR */
	current_thread_info()->restart_block.fn = do_no_restart_syscall;

	err |= __get_user(regs->cp0_epc, &sc->sc_pc);
	err |= __get_user(regs->hi, &sc->sc_mdhi);
	err |= __get_user(regs->lo, &sc->sc_mdlo);
	if (cpu_has_dsp) {
		err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
		err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
		err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
		err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
		err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
		err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
		err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
	}

#define restore_gp_reg(i) do {						\
	err |= __get_user(regs->regs[i], &sc->sc_regs[i]);		\
} while(0)
	restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
	restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
	restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
	restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
	restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
	restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
	restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
	restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
	restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
	restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
	restore_gp_reg(31);
#undef restore_gp_reg

	err |= __get_user(used_math, &sc->sc_used_math);
	conditional_used_math(used_math);

	preempt_disable();

	if (used_math()) {
		/* restore fpu context if we have used it before */
		own_fpu();
		err |= restore_fp_context32(sc);
	} else {
		/* signal handler may have used FPU.  Give it up. */
		lose_fpu();
	}

	preempt_enable();

	return err;
}
コード例 #5
0
ファイル: signal.c プロジェクト: lishaman/minispeaker
int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
{
	unsigned int used_math;
	unsigned long treg;
	int err = 0;
	int i;

	/* Always make any pending restarted system calls return -EINTR */
	current_thread_info()->restart_block.fn = do_no_restart_syscall;

	err |= __get_user(regs->cp0_epc, &sc->sc_pc);

#ifdef CONFIG_CPU_HAS_SMARTMIPS
	err |= __get_user(regs->acx, &sc->sc_acx);
#endif
	err |= __get_user(regs->hi, &sc->sc_mdhi);
	err |= __get_user(regs->lo, &sc->sc_mdlo);
	if (cpu_has_dsp) {
		err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
		err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
		err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
		err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
		err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
		err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
		err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
	}

	for (i = 1; i < 32; i++)
		err |= __get_user(regs->regs[i], &sc->sc_regs[i]);

	err |= __get_user(used_math, &sc->sc_used_math);
	conditional_used_math(used_math);

	if (used_math) {
		/* restore fpu context if we have used it before */
		if (!err)
			err = check_and_restore_fp_context(sc);
	} else {
		/* signal handler may have used FPU.  Give it up. */
		lose_fpu(0);
	}
	
	if (cpu_has_mxu) {
		unsigned int regs[NUM_MXU_REGS];
		for (i = 0; i < NUM_MXU_REGS; i++){
			err |= __get_user(regs[i], &sc->sc_mxu[i]);
		}
		__let_mxu_regs(current,regs);
	}

	return err;
}
コード例 #6
0
ファイル: signal.c プロジェクト: 24hours/linux
static int protected_restore_fp_context(struct sigcontext __user *sc,
					unsigned used_math)
{
	int err, tmp __maybe_unused;
	bool restore_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
#ifndef CONFIG_EVA
	while (1) {
		lock_fpu_owner();
		if (is_fpu_owner()) {
			err = restore_fp_context(sc);
			if (restore_msa && !err) {
				enable_msa();
				err = _restore_msa_context(sc);
			} else {
				/* signal handler may have used MSA */
				disable_msa();
			}
			unlock_fpu_owner();
		} else {
			unlock_fpu_owner();
			err = copy_fp_from_sigcontext(sc);
			if (!err && (used_math & USEDMATH_MSA))
				err = copy_msa_from_sigcontext(sc);
		}
		if (likely(!err))
			break;
		/* touch the sigcontext and try again */
		err = __get_user(tmp, &sc->sc_fpregs[0]) |
			__get_user(tmp, &sc->sc_fpregs[31]) |
			__get_user(tmp, &sc->sc_fpc_csr);
		if (err)
			break;	/* really bad sigcontext */
	}
#else
	/*
	 * EVA does not have FPU EVA instructions so restoring fpu context
	 * directly does not work.
	 */
	enable_msa();
	lose_fpu(0);
	err = restore_fp_context(sc); /* this might fail */
	if (restore_msa && !err)
		err = copy_msa_from_sigcontext(sc);
#endif
	return err;
}
コード例 #7
0
ファイル: signal32.c プロジェクト: 24hours/linux
static int restore_sigcontext32(struct pt_regs *regs,
				struct sigcontext32 __user *sc)
{
	u32 used_math;
	int err = 0;
	s32 treg;
	int i;

	/* Always make any pending restarted system calls return -EINTR */
	current_thread_info()->restart_block.fn = do_no_restart_syscall;

	err |= __get_user(regs->cp0_epc, &sc->sc_pc);
	err |= __get_user(regs->hi, &sc->sc_mdhi);
	err |= __get_user(regs->lo, &sc->sc_mdlo);
	if (cpu_has_dsp) {
		err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
		err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
		err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
		err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
		err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
		err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
		err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
	}

	for (i = 1; i < 32; i++)
		err |= __get_user(regs->regs[i], &sc->sc_regs[i]);

	err |= __get_user(used_math, &sc->sc_used_math);
	conditional_used_math(used_math);

	if (used_math) {
		/* restore fpu context if we have used it before */
		if (!err)
			err = check_and_restore_fp_context32(sc, used_math);
	} else {
		/* signal handler may have used FPU or MSA. Disable them. */
		disable_msa();
		lose_fpu(0);
	}

	return err;
}
コード例 #8
0
ファイル: signal.c プロジェクト: NieHao/Tomato-RAF
static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
{
	int err = 0;
	u64 reg;

	err |= __get_user(regs->cp0_epc, &sc->sc_pc);

	err |= __get_user(reg, &sc->sc_mdhi);
	regs->hi = (int) reg;
	err |= __get_user(reg, &sc->sc_mdlo);
	regs->lo = (int) reg;

#define restore_gp_reg(i) do {						\
	err |= __get_user(reg, &sc->sc_regs[i]);			\
	regs->regs[i] = reg;						\
} while(0)
	restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
	restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
	restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
	restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
	restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
	restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
	restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
	restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
	restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
	restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
	restore_gp_reg(31);
#undef restore_gp_reg

	err |= __get_user(current->used_math, &sc->sc_used_math);

	if (current->used_math) {
		/* restore fpu context if we have used it before */
		own_fpu();
		err |= restore_fp_context(sc);
	} else {
		/* signal handler may have used FPU.  Give it up. */
		lose_fpu();
	}

	return err;
}
コード例 #9
0
ファイル: process.c プロジェクト: 1x23/unifi-gpl
void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
{
	unsigned long status;

	/* New thread loses kernel privileges. */
	status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|KU_MASK);
#ifdef CONFIG_64BIT
	status &= ~ST0_FR;
	status |= (current->thread.mflags & MF_32BIT_REGS) ? 0 : ST0_FR;
#endif
	status |= KU_USER;
	regs->cp0_status = status;
	clear_used_math();
	lose_fpu();
	if (cpu_has_dsp)
		__init_dsp();
	regs->cp0_epc = pc;
	regs->regs[29] = sp;
	current_thread_info()->addr_limit = USER_DS;
}
コード例 #10
0
ファイル: signal.c プロジェクト: 24hours/linux
/*
 * Helper routines
 */
static int protected_save_fp_context(struct sigcontext __user *sc,
				     unsigned used_math)
{
	int err;
	bool save_msa = cpu_has_msa && (used_math & USEDMATH_MSA);
#ifndef CONFIG_EVA
	while (1) {
		lock_fpu_owner();
		if (is_fpu_owner()) {
			err = save_fp_context(sc);
			if (save_msa && !err)
				err = _save_msa_context(sc);
			unlock_fpu_owner();
		} else {
			unlock_fpu_owner();
			err = copy_fp_to_sigcontext(sc);
			if (save_msa && !err)
				err = copy_msa_to_sigcontext(sc);
		}
		if (likely(!err))
			break;
		/* touch the sigcontext and try again */
		err = __put_user(0, &sc->sc_fpregs[0]) |
			__put_user(0, &sc->sc_fpregs[31]) |
			__put_user(0, &sc->sc_fpc_csr);
		if (err)
			break;	/* really bad sigcontext */
	}
#else
	/*
	 * EVA does not have FPU EVA instructions so saving fpu context directly
	 * does not work.
	 */
	disable_msa();
	lose_fpu(1);
	err = save_fp_context(sc); /* this might fail */
	if (save_msa && !err)
		err = copy_msa_to_sigcontext(sc);
#endif
	return err;
}
コード例 #11
0
ファイル: unaligned.c プロジェクト: garyvan/openwrt-1.6
static void emulate_load_store_microMIPS(struct pt_regs *regs,
					 void __user *addr)
{
	unsigned long value;
	unsigned int res;
	int i;
	unsigned int reg = 0, rvar;
	unsigned long orig31;
	u16 __user *pc16;
	u16 halfword;
	unsigned int word;
	unsigned long origpc, contpc;
	union mips_instruction insn;
	struct mm_decoded_insn mminsn;
	void __user *fault_addr = NULL;

	origpc = regs->cp0_epc;
	orig31 = regs->regs[31];

	mminsn.micro_mips_mode = 1;

	/*
	 * This load never faults.
	 */
	pc16 = (unsigned short __user *)msk_isa16_mode(regs->cp0_epc);
	__get_user(halfword, pc16);
	pc16++;
	contpc = regs->cp0_epc + 2;
	word = ((unsigned int)halfword << 16);
	mminsn.pc_inc = 2;

	if (!mm_insn_16bit(halfword)) {
		__get_user(halfword, pc16);
		pc16++;
		contpc = regs->cp0_epc + 4;
		mminsn.pc_inc = 4;
		word |= halfword;
	}
	mminsn.insn = word;

	if (get_user(halfword, pc16))
		goto fault;
	mminsn.next_pc_inc = 2;
	word = ((unsigned int)halfword << 16);

	if (!mm_insn_16bit(halfword)) {
		pc16++;
		if (get_user(halfword, pc16))
			goto fault;
		mminsn.next_pc_inc = 4;
		word |= halfword;
	}
	mminsn.next_insn = word;

	insn = (union mips_instruction)(mminsn.insn);
	if (mm_isBranchInstr(regs, mminsn, &contpc))
		insn = (union mips_instruction)(mminsn.next_insn);

	/*  Parse instruction to find what to do */

	switch (insn.mm_i_format.opcode) {

	case mm_pool32a_op:
		switch (insn.mm_x_format.func) {
		case mm_lwxs_op:
			reg = insn.mm_x_format.rd;
			goto loadW;
		}

		goto sigbus;

	case mm_pool32b_op:
		switch (insn.mm_m_format.func) {
		case mm_lwp_func:
			reg = insn.mm_m_format.rd;
			if (reg == 31)
				goto sigbus;

			if (!access_ok(VERIFY_READ, addr, 8))
				goto sigbus;

			LoadW(addr, value, res);
			if (res)
				goto fault;
			regs->regs[reg] = value;
			addr += 4;
			LoadW(addr, value, res);
			if (res)
				goto fault;
			regs->regs[reg + 1] = value;
			goto success;

		case mm_swp_func:
			reg = insn.mm_m_format.rd;
			if (reg == 31)
				goto sigbus;

			if (!access_ok(VERIFY_WRITE, addr, 8))
				goto sigbus;

			value = regs->regs[reg];
			StoreW(addr, value, res);
			if (res)
				goto fault;
			addr += 4;
			value = regs->regs[reg + 1];
			StoreW(addr, value, res);
			if (res)
				goto fault;
			goto success;

		case mm_ldp_func:
#ifdef CONFIG_64BIT
			reg = insn.mm_m_format.rd;
			if (reg == 31)
				goto sigbus;

			if (!access_ok(VERIFY_READ, addr, 16))
				goto sigbus;

			LoadDW(addr, value, res);
			if (res)
				goto fault;
			regs->regs[reg] = value;
			addr += 8;
			LoadDW(addr, value, res);
			if (res)
				goto fault;
			regs->regs[reg + 1] = value;
			goto success;
#endif /* CONFIG_64BIT */

			goto sigill;

		case mm_sdp_func:
#ifdef CONFIG_64BIT
			reg = insn.mm_m_format.rd;
			if (reg == 31)
				goto sigbus;

			if (!access_ok(VERIFY_WRITE, addr, 16))
				goto sigbus;

			value = regs->regs[reg];
			StoreDW(addr, value, res);
			if (res)
				goto fault;
			addr += 8;
			value = regs->regs[reg + 1];
			StoreDW(addr, value, res);
			if (res)
				goto fault;
			goto success;
#endif /* CONFIG_64BIT */

			goto sigill;

		case mm_lwm32_func:
			reg = insn.mm_m_format.rd;
			rvar = reg & 0xf;
			if ((rvar > 9) || !reg)
				goto sigill;
			if (reg & 0x10) {
				if (!access_ok
				    (VERIFY_READ, addr, 4 * (rvar + 1)))
					goto sigbus;
			} else {
				if (!access_ok(VERIFY_READ, addr, 4 * rvar))
					goto sigbus;
			}
			if (rvar == 9)
				rvar = 8;
			for (i = 16; rvar; rvar--, i++) {
				LoadW(addr, value, res);
				if (res)
					goto fault;
				addr += 4;
				regs->regs[i] = value;
			}
			if ((reg & 0xf) == 9) {
				LoadW(addr, value, res);
				if (res)
					goto fault;
				addr += 4;
				regs->regs[30] = value;
			}
			if (reg & 0x10) {
				LoadW(addr, value, res);
				if (res)
					goto fault;
				regs->regs[31] = value;
			}
			goto success;

		case mm_swm32_func:
			reg = insn.mm_m_format.rd;
			rvar = reg & 0xf;
			if ((rvar > 9) || !reg)
				goto sigill;
			if (reg & 0x10) {
				if (!access_ok
				    (VERIFY_WRITE, addr, 4 * (rvar + 1)))
					goto sigbus;
			} else {
				if (!access_ok(VERIFY_WRITE, addr, 4 * rvar))
					goto sigbus;
			}
			if (rvar == 9)
				rvar = 8;
			for (i = 16; rvar; rvar--, i++) {
				value = regs->regs[i];
				StoreW(addr, value, res);
				if (res)
					goto fault;
				addr += 4;
			}
			if ((reg & 0xf) == 9) {
				value = regs->regs[30];
				StoreW(addr, value, res);
				if (res)
					goto fault;
				addr += 4;
			}
			if (reg & 0x10) {
				value = regs->regs[31];
				StoreW(addr, value, res);
				if (res)
					goto fault;
			}
			goto success;

		case mm_ldm_func:
#ifdef CONFIG_64BIT
			reg = insn.mm_m_format.rd;
			rvar = reg & 0xf;
			if ((rvar > 9) || !reg)
				goto sigill;
			if (reg & 0x10) {
				if (!access_ok
				    (VERIFY_READ, addr, 8 * (rvar + 1)))
					goto sigbus;
			} else {
				if (!access_ok(VERIFY_READ, addr, 8 * rvar))
					goto sigbus;
			}
			if (rvar == 9)
				rvar = 8;

			for (i = 16; rvar; rvar--, i++) {
				LoadDW(addr, value, res);
				if (res)
					goto fault;
				addr += 4;
				regs->regs[i] = value;
			}
			if ((reg & 0xf) == 9) {
				LoadDW(addr, value, res);
				if (res)
					goto fault;
				addr += 8;
				regs->regs[30] = value;
			}
			if (reg & 0x10) {
				LoadDW(addr, value, res);
				if (res)
					goto fault;
				regs->regs[31] = value;
			}
			goto success;
#endif /* CONFIG_64BIT */

			goto sigill;

		case mm_sdm_func:
#ifdef CONFIG_64BIT
			reg = insn.mm_m_format.rd;
			rvar = reg & 0xf;
			if ((rvar > 9) || !reg)
				goto sigill;
			if (reg & 0x10) {
				if (!access_ok
				    (VERIFY_WRITE, addr, 8 * (rvar + 1)))
					goto sigbus;
			} else {
				if (!access_ok(VERIFY_WRITE, addr, 8 * rvar))
					goto sigbus;
			}
			if (rvar == 9)
				rvar = 8;

			for (i = 16; rvar; rvar--, i++) {
				value = regs->regs[i];
				StoreDW(addr, value, res);
				if (res)
					goto fault;
				addr += 8;
			}
			if ((reg & 0xf) == 9) {
				value = regs->regs[30];
				StoreDW(addr, value, res);
				if (res)
					goto fault;
				addr += 8;
			}
			if (reg & 0x10) {
				value = regs->regs[31];
				StoreDW(addr, value, res);
				if (res)
					goto fault;
			}
			goto success;
#endif /* CONFIG_64BIT */

			goto sigill;

			/*  LWC2, SWC2, LDC2, SDC2 are not serviced */
		}

		goto sigbus;

	case mm_pool32c_op:
		switch (insn.mm_m_format.func) {
		case mm_lwu_func:
			reg = insn.mm_m_format.rd;
			goto loadWU;
		}

		/*  LL,SC,LLD,SCD are not serviced */
		goto sigbus;

	case mm_pool32f_op:
		switch (insn.mm_x_format.func) {
		case mm_lwxc1_func:
		case mm_swxc1_func:
		case mm_ldxc1_func:
		case mm_sdxc1_func:
			goto fpu_emul;
		}

		goto sigbus;

	case mm_ldc132_op:
	case mm_sdc132_op:
	case mm_lwc132_op:
	case mm_swc132_op:
fpu_emul:
		/* roll back jump/branch */
		regs->cp0_epc = origpc;
		regs->regs[31] = orig31;

		die_if_kernel("Unaligned FP access in kernel code", regs);
		BUG_ON(!used_math());
		BUG_ON(!is_fpu_owner());

		lose_fpu(1);	/* save the FPU state for the emulator */
		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
					       &fault_addr);
		own_fpu(1);	/* restore FPU state */

		/* If something went wrong, signal */
		process_fpemu_return(res, fault_addr);

		if (res == 0)
			goto success;
		return;

	case mm_lh32_op:
		reg = insn.mm_i_format.rt;
		goto loadHW;

	case mm_lhu32_op:
		reg = insn.mm_i_format.rt;
		goto loadHWU;

	case mm_lw32_op:
		reg = insn.mm_i_format.rt;
		goto loadW;

	case mm_sh32_op:
		reg = insn.mm_i_format.rt;
		goto storeHW;

	case mm_sw32_op:
		reg = insn.mm_i_format.rt;
		goto storeW;

	case mm_ld32_op:
		reg = insn.mm_i_format.rt;
		goto loadDW;

	case mm_sd32_op:
		reg = insn.mm_i_format.rt;
		goto storeDW;

	case mm_pool16c_op:
		switch (insn.mm16_m_format.func) {
		case mm_lwm16_op:
			reg = insn.mm16_m_format.rlist;
			rvar = reg + 1;
			if (!access_ok(VERIFY_READ, addr, 4 * rvar))
				goto sigbus;

			for (i = 16; rvar; rvar--, i++) {
				LoadW(addr, value, res);
				if (res)
					goto fault;
				addr += 4;
				regs->regs[i] = value;
			}
			LoadW(addr, value, res);
			if (res)
				goto fault;
			regs->regs[31] = value;

			goto success;

		case mm_swm16_op:
			reg = insn.mm16_m_format.rlist;
			rvar = reg + 1;
			if (!access_ok(VERIFY_WRITE, addr, 4 * rvar))
				goto sigbus;

			for (i = 16; rvar; rvar--, i++) {
				value = regs->regs[i];
				StoreW(addr, value, res);
				if (res)
					goto fault;
				addr += 4;
			}
			value = regs->regs[31];
			StoreW(addr, value, res);
			if (res)
				goto fault;

			goto success;

		}

		goto sigbus;

	case mm_lhu16_op:
		reg = reg16to32[insn.mm16_rb_format.rt];
		goto loadHWU;

	case mm_lw16_op:
		reg = reg16to32[insn.mm16_rb_format.rt];
		goto loadW;

	case mm_sh16_op:
		reg = reg16to32st[insn.mm16_rb_format.rt];
		goto storeHW;

	case mm_sw16_op:
		reg = reg16to32st[insn.mm16_rb_format.rt];
		goto storeW;

	case mm_lwsp16_op:
		reg = insn.mm16_r5_format.rt;
		goto loadW;

	case mm_swsp16_op:
		reg = insn.mm16_r5_format.rt;
		goto storeW;

	case mm_lwgp16_op:
		reg = reg16to32[insn.mm16_r3_format.rt];
		goto loadW;

	default:
		goto sigill;
	}

loadHW:
	if (!access_ok(VERIFY_READ, addr, 2))
		goto sigbus;

	LoadHW(addr, value, res);
	if (res)
		goto fault;
	regs->regs[reg] = value;
	goto success;

loadHWU:
	if (!access_ok(VERIFY_READ, addr, 2))
		goto sigbus;

	LoadHWU(addr, value, res);
	if (res)
		goto fault;
	regs->regs[reg] = value;
	goto success;

loadW:
	if (!access_ok(VERIFY_READ, addr, 4))
		goto sigbus;

	LoadW(addr, value, res);
	if (res)
		goto fault;
	regs->regs[reg] = value;
	goto success;

loadWU:
#ifdef CONFIG_64BIT
	/*
	 * A 32-bit kernel might be running on a 64-bit processor.  But
	 * if we're on a 32-bit processor and an i-cache incoherency
	 * or race makes us see a 64-bit instruction here the sdl/sdr
	 * would blow up, so for now we don't handle unaligned 64-bit
	 * instructions on 32-bit kernels.
	 */
	if (!access_ok(VERIFY_READ, addr, 4))
		goto sigbus;

	LoadWU(addr, value, res);
	if (res)
		goto fault;
	regs->regs[reg] = value;
	goto success;
#endif /* CONFIG_64BIT */

	/* Cannot handle 64-bit instructions in 32-bit kernel */
	goto sigill;

loadDW:
#ifdef CONFIG_64BIT
	/*
	 * A 32-bit kernel might be running on a 64-bit processor.  But
	 * if we're on a 32-bit processor and an i-cache incoherency
	 * or race makes us see a 64-bit instruction here the sdl/sdr
	 * would blow up, so for now we don't handle unaligned 64-bit
	 * instructions on 32-bit kernels.
	 */
	if (!access_ok(VERIFY_READ, addr, 8))
		goto sigbus;

	LoadDW(addr, value, res);
	if (res)
		goto fault;
	regs->regs[reg] = value;
	goto success;
#endif /* CONFIG_64BIT */

	/* Cannot handle 64-bit instructions in 32-bit kernel */
	goto sigill;

storeHW:
	if (!access_ok(VERIFY_WRITE, addr, 2))
		goto sigbus;

	value = regs->regs[reg];
	StoreHW(addr, value, res);
	if (res)
		goto fault;
	goto success;

storeW:
	if (!access_ok(VERIFY_WRITE, addr, 4))
		goto sigbus;

	value = regs->regs[reg];
	StoreW(addr, value, res);
	if (res)
		goto fault;
	goto success;

storeDW:
#ifdef CONFIG_64BIT
	/*
	 * A 32-bit kernel might be running on a 64-bit processor.  But
	 * if we're on a 32-bit processor and an i-cache incoherency
	 * or race makes us see a 64-bit instruction here the sdl/sdr
	 * would blow up, so for now we don't handle unaligned 64-bit
	 * instructions on 32-bit kernels.
	 */
	if (!access_ok(VERIFY_WRITE, addr, 8))
		goto sigbus;

	value = regs->regs[reg];
	StoreDW(addr, value, res);
	if (res)
		goto fault;
	goto success;
#endif /* CONFIG_64BIT */

	/* Cannot handle 64-bit instructions in 32-bit kernel */
	goto sigill;

success:
	regs->cp0_epc = contpc;	/* advance or branch */

#ifdef CONFIG_DEBUG_FS
	unaligned_instructions++;
#endif
	return;

fault:
	/* roll back jump/branch */
	regs->cp0_epc = origpc;
	regs->regs[31] = orig31;
	/* Did we have an exception handler installed? */
	if (fixup_exception(regs))
		return;

	die_if_kernel("Unhandled kernel unaligned access", regs);
	force_sig(SIGSEGV, current);

	return;

sigbus:
	die_if_kernel("Unhandled kernel unaligned access", regs);
	force_sig(SIGBUS, current);

	return;

sigill:
	die_if_kernel
	    ("Unhandled kernel unaligned access or invalid instruction", regs);
	force_sig(SIGILL, current);
}
コード例 #12
0
ファイル: unaligned.c プロジェクト: garyvan/openwrt-1.6
static void emulate_load_store_insn(struct pt_regs *regs,
	void __user *addr, unsigned int __user *pc)
{
	union mips_instruction insn;
	unsigned long value;
	unsigned int res;
	unsigned long origpc;
	unsigned long orig31;
	void __user *fault_addr = NULL;

	origpc = (unsigned long)pc;
	orig31 = regs->regs[31];

	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);

	/*
	 * This load never faults.
	 */
	__get_user(insn.word, pc);

	switch (insn.i_format.opcode) {
		/*
		 * These are instructions that a compiler doesn't generate.  We
		 * can assume therefore that the code is MIPS-aware and
		 * really buggy.  Emulating these instructions would break the
		 * semantics anyway.
		 */
	case ll_op:
	case lld_op:
	case sc_op:
	case scd_op:

		/*
		 * For these instructions the only way to create an address
		 * error is an attempted access to kernel/supervisor address
		 * space.
		 */
	case ldl_op:
	case ldr_op:
	case lwl_op:
	case lwr_op:
	case sdl_op:
	case sdr_op:
	case swl_op:
	case swr_op:
	case lb_op:
	case lbu_op:
	case sb_op:
		goto sigbus;

	case spec3_op:
		if (insn.r_format.func != lx_op)
			goto sigill;
		switch (insn.r_format.re) {
		case lwx_op:
			if (!access_ok(VERIFY_READ, addr, 4))
				goto sigbus;

			LoadW(addr, value, res);
			if (res)
				goto fault;
			compute_return_epc(regs);
			regs->regs[insn.r_format.rd] = value;
			break;

		case lhx_op:
			if (!access_ok(VERIFY_READ, addr, 2))
				goto sigbus;

			LoadHW(addr, value, res);
			if (res)
				goto fault;
			compute_return_epc(regs);
			regs->regs[insn.r_format.rd] = value;
			break;

#ifdef CONFIG_64BIT
		case ldx_op:
			if (!access_ok(VERIFY_READ, addr, 8))
				goto sigbus;

			LoadDW(addr, value, res);
			if (res)
				goto fault;
			compute_return_epc(regs);
			regs->regs[insn.r_format.rd] = value;
			break;

		case lwux_op:
			if (!access_ok(VERIFY_READ, addr, 4))
				goto sigbus;

			LoadWU(addr, value, res);
			if (res)
				goto fault;
			compute_return_epc(regs);
			regs->regs[insn.r_format.rd] = value;
			break;
#endif /* CONFIG_64BIT */

		case lhux_op:
			if (!access_ok(VERIFY_READ, addr, 2))
				goto sigbus;

			LoadHWU(addr, value, res);
			if (res)
				goto fault;
			compute_return_epc(regs);
			regs->regs[insn.r_format.rd] = value;
			break;

		case lbux_op:
		case lbx_op:
			goto sigbus;
		default:
			goto sigill;
		}
		break;
		/*
		 * The remaining opcodes are the ones that are really of
		 * interest.
		 */
	case lh_op:
		if (!access_ok(VERIFY_READ, addr, 2))
			goto sigbus;

		LoadHW(addr, value, res);
		if (res)
			goto fault;
		compute_return_epc(regs);
		regs->regs[insn.i_format.rt] = value;
		break;

	case lw_op:
		if (!access_ok(VERIFY_READ, addr, 4))
			goto sigbus;

		LoadW(addr, value, res);
		if (res)
			goto fault;
		compute_return_epc(regs);
		regs->regs[insn.i_format.rt] = value;
		break;

	case lhu_op:
		if (!access_ok(VERIFY_READ, addr, 2))
			goto sigbus;

		LoadHWU(addr, value, res);
		if (res)
			goto fault;
		compute_return_epc(regs);
		regs->regs[insn.i_format.rt] = value;
		break;

	case lwu_op:
#ifdef CONFIG_64BIT
		/*
		 * A 32-bit kernel might be running on a 64-bit processor.  But
		 * if we're on a 32-bit processor and an i-cache incoherency
		 * or race makes us see a 64-bit instruction here the sdl/sdr
		 * would blow up, so for now we don't handle unaligned 64-bit
		 * instructions on 32-bit kernels.
		 */
		if (!access_ok(VERIFY_READ, addr, 4))
			goto sigbus;

		LoadWU(addr, value, res);
		if (res)
			goto fault;
		compute_return_epc(regs);
		regs->regs[insn.i_format.rt] = value;
		break;
#endif /* CONFIG_64BIT */

		/* Cannot handle 64-bit instructions in 32-bit kernel */
		goto sigill;

	case ld_op:
#ifdef CONFIG_64BIT
		/*
		 * A 32-bit kernel might be running on a 64-bit processor.  But
		 * if we're on a 32-bit processor and an i-cache incoherency
		 * or race makes us see a 64-bit instruction here the sdl/sdr
		 * would blow up, so for now we don't handle unaligned 64-bit
		 * instructions on 32-bit kernels.
		 */
		if (!access_ok(VERIFY_READ, addr, 8))
			goto sigbus;

		LoadDW(addr, value, res);
		if (res)
			goto fault;
		compute_return_epc(regs);
		regs->regs[insn.i_format.rt] = value;
		break;
#endif /* CONFIG_64BIT */

		/* Cannot handle 64-bit instructions in 32-bit kernel */
		goto sigill;

	case sh_op:
		if (!access_ok(VERIFY_WRITE, addr, 2))
			goto sigbus;

		compute_return_epc(regs);
		value = regs->regs[insn.i_format.rt];
		StoreHW(addr, value, res);
		if (res)
			goto fault;
		break;

	case sw_op:
		if (!access_ok(VERIFY_WRITE, addr, 4))
			goto sigbus;

		compute_return_epc(regs);
		value = regs->regs[insn.i_format.rt];
		StoreW(addr, value, res);
		if (res)
			goto fault;
		break;

	case sd_op:
#ifdef CONFIG_64BIT
		/*
		 * A 32-bit kernel might be running on a 64-bit processor.  But
		 * if we're on a 32-bit processor and an i-cache incoherency
		 * or race makes us see a 64-bit instruction here the sdl/sdr
		 * would blow up, so for now we don't handle unaligned 64-bit
		 * instructions on 32-bit kernels.
		 */
		if (!access_ok(VERIFY_WRITE, addr, 8))
			goto sigbus;

		compute_return_epc(regs);
		value = regs->regs[insn.i_format.rt];
		StoreDW(addr, value, res);
		if (res)
			goto fault;
		break;
#endif /* CONFIG_64BIT */

		/* Cannot handle 64-bit instructions in 32-bit kernel */
		goto sigill;

	case lwc1_op:
	case ldc1_op:
	case swc1_op:
	case sdc1_op:
		die_if_kernel("Unaligned FP access in kernel code", regs);
		BUG_ON(!used_math());
		BUG_ON(!is_fpu_owner());

		lose_fpu(1);	/* Save FPU state for the emulator. */
		res = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
					       &fault_addr);
		own_fpu(1);	/* Restore FPU state. */

		/* Signal if something went wrong. */
		process_fpemu_return(res, fault_addr);

		if (res == 0)
			break;
		return;

	/*
	 * COP2 is available to implementor for application specific use.
	 * It's up to applications to register a notifier chain and do
	 * whatever they have to do, including possible sending of signals.
	 */
	case lwc2_op:
		cu2_notifier_call_chain(CU2_LWC2_OP, regs);
		break;

	case ldc2_op:
		cu2_notifier_call_chain(CU2_LDC2_OP, regs);
		break;

	case swc2_op:
		cu2_notifier_call_chain(CU2_SWC2_OP, regs);
		break;

	case sdc2_op:
		cu2_notifier_call_chain(CU2_SDC2_OP, regs);
		break;

	default:
		/*
		 * Pheeee...  We encountered an yet unknown instruction or
		 * cache coherence problem.  Die sucker, die ...
		 */
		goto sigill;
	}

#ifdef CONFIG_DEBUG_FS
	unaligned_instructions++;
#endif

	return;

fault:
	/* roll back jump/branch */
	regs->cp0_epc = origpc;
	regs->regs[31] = orig31;
	/* Did we have an exception handler installed? */
	if (fixup_exception(regs))
		return;

	die_if_kernel("Unhandled kernel unaligned access", regs);
	force_sig(SIGSEGV, current);

	return;

sigbus:
	die_if_kernel("Unhandled kernel unaligned access", regs);
	force_sig(SIGBUS, current);

	return;

sigill:
	die_if_kernel
	    ("Unhandled kernel unaligned access or invalid instruction", regs);
	force_sig(SIGILL, current);
}