908 lines · 21.3 KB · C
RawDownload
/* * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1996, 97, 2000, 2001 by Ralf Baechle * Copyright (C) 2001 MIPS Technologies, Inc. */#include <linux/kernel.h>#include <linux/sched/signal.h>#include <linux/signal.h>#include <linux/export.h>#include <asm/branch.h>#include <asm/cpu.h>#include <asm/cpu-features.h>#include <asm/fpu.h>#include <asm/fpu_emulator.h>#include <asm/inst.h>#include <asm/mips-r2-to-r6-emul.h>#include <asm/ptrace.h>#include <linux/uaccess.h> #include "probes-common.h" /* * Calculate and return exception PC in case of branch delay slot * for microMIPS and MIPS16e. It does not clear the ISA mode bit. */int __isa_exception_epc(struct pt_regs *regs){	unsigned short inst;	long epc = regs->cp0_epc; 	/* Calculate exception PC in branch delay slot. */	if (__get_user(inst, (u16 __user *) msk_isa16_mode(epc))) {		/* This should never happen because delay slot was checked. */		force_sig(SIGSEGV);		return epc;	}	if (cpu_has_mips16) {		union mips16e_instruction inst_mips16e; 		inst_mips16e.full = inst;		if (inst_mips16e.ri.opcode == MIPS16e_jal_op)			epc += 4;		else			epc += 2;	} else if (mm_insn_16bit(inst))		epc += 2;	else		epc += 4; 	return epc;} /* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7}; int __mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,		       unsigned long *contpc){	union mips_instruction insn = (union mips_instruction)dec_insn.insn;	int __maybe_unused bc_false = 0; 	if (!cpu_has_mmips)		return 0; 	switch (insn.mm_i_format.opcode) {	case mm_pool32a_op:		if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) ==		    mm_pool32axf_op) {			switch (insn.mm_i_format.simmediate >>				MM_POOL32A_MINOR_SHIFT) {			case mm_jalr_op:			case mm_jalrhb_op:			case mm_jalrs_op:			case mm_jalrshb_op:				if (insn.mm_i_format.rt != 0)	/* Not mm_jr */					regs->regs[insn.mm_i_format.rt] =						regs->cp0_epc +						dec_insn.pc_inc +						dec_insn.next_pc_inc;				*contpc = regs->regs[insn.mm_i_format.rs];				return 1;			}		}		break;	case mm_pool32i_op:		switch (insn.mm_i_format.rt) {		case mm_bltzals_op:		case mm_bltzal_op:			regs->regs[31] = regs->cp0_epc +				dec_insn.pc_inc +				dec_insn.next_pc_inc;			fallthrough;		case mm_bltz_op:			if ((long)regs->regs[insn.mm_i_format.rs] < 0)				*contpc = regs->cp0_epc +					dec_insn.pc_inc +					(insn.mm_i_format.simmediate << 1);			else				*contpc = regs->cp0_epc +					dec_insn.pc_inc +					dec_insn.next_pc_inc;			return 1;		case mm_bgezals_op:		case mm_bgezal_op:			regs->regs[31] = regs->cp0_epc +					dec_insn.pc_inc +					dec_insn.next_pc_inc;			fallthrough;		case mm_bgez_op:			if ((long)regs->regs[insn.mm_i_format.rs] >= 0)				*contpc = regs->cp0_epc +					dec_insn.pc_inc +					(insn.mm_i_format.simmediate << 1);			else				*contpc = regs->cp0_epc +					dec_insn.pc_inc +					dec_insn.next_pc_inc;			return 1;		case mm_blez_op:			if ((long)regs->regs[insn.mm_i_format.rs] <= 0)				*contpc = regs->cp0_epc +					dec_insn.pc_inc +					(insn.mm_i_format.simmediate << 1);			else				*contpc = regs->cp0_epc +					dec_insn.pc_inc +					dec_insn.next_pc_inc;			return 1;		case mm_bgtz_op:			if ((long)regs->regs[insn.mm_i_format.rs] <= 0)				*contpc = regs->cp0_epc +					dec_insn.pc_inc +					(insn.mm_i_format.simmediate << 1);			else				*contpc = regs->cp0_epc +					dec_insn.pc_inc +					dec_insn.next_pc_inc;			return 1;#ifdef CONFIG_MIPS_FP_SUPPORT		case mm_bc2f_op:		case mm_bc1f_op: {			unsigned int fcr31;			unsigned int bit; 			bc_false = 1;			fallthrough;		case mm_bc2t_op:		case mm_bc1t_op:			preempt_disable();			if (is_fpu_owner())			        fcr31 = read_32bit_cp1_register(CP1_STATUS);			else				fcr31 = current->thread.fpu.fcr31;			preempt_enable(); 			if (bc_false)				fcr31 = ~fcr31; 			bit = (insn.mm_i_format.rs >> 2);			bit += (bit != 0);			bit += 23;			if (fcr31 & (1 << bit))				*contpc = regs->cp0_epc +					dec_insn.pc_inc +					(insn.mm_i_format.simmediate << 1);			else				*contpc = regs->cp0_epc +					dec_insn.pc_inc + dec_insn.next_pc_inc;			return 1;		}#endif /* CONFIG_MIPS_FP_SUPPORT */		}		break;	case mm_pool16c_op:		switch (insn.mm_i_format.rt) {		case mm_jalr16_op:		case mm_jalrs16_op:			regs->regs[31] = regs->cp0_epc +				dec_insn.pc_inc + dec_insn.next_pc_inc;			fallthrough;		case mm_jr16_op:			*contpc = regs->regs[insn.mm_i_format.rs];			return 1;		}		break;	case mm_beqz16_op:		if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0)			*contpc = regs->cp0_epc +				dec_insn.pc_inc +				(insn.mm_b1_format.simmediate << 1);		else			*contpc = regs->cp0_epc +				dec_insn.pc_inc + dec_insn.next_pc_inc;		return 1;	case mm_bnez16_op:		if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0)			*contpc = regs->cp0_epc +				dec_insn.pc_inc +				(insn.mm_b1_format.simmediate << 1);		else			*contpc = regs->cp0_epc +				dec_insn.pc_inc + dec_insn.next_pc_inc;		return 1;	case mm_b16_op:		*contpc = regs->cp0_epc + dec_insn.pc_inc +			 (insn.mm_b0_format.simmediate << 1);		return 1;	case mm_beq32_op:		if (regs->regs[insn.mm_i_format.rs] ==		    regs->regs[insn.mm_i_format.rt])			*contpc = regs->cp0_epc +				dec_insn.pc_inc +				(insn.mm_i_format.simmediate << 1);		else			*contpc = regs->cp0_epc +				dec_insn.pc_inc +				dec_insn.next_pc_inc;		return 1;	case mm_bne32_op:		if (regs->regs[insn.mm_i_format.rs] !=		    regs->regs[insn.mm_i_format.rt])			*contpc = regs->cp0_epc +				dec_insn.pc_inc +				(insn.mm_i_format.simmediate << 1);		else			*contpc = regs->cp0_epc +				dec_insn.pc_inc + dec_insn.next_pc_inc;		return 1;	case mm_jalx32_op:		regs->regs[31] = regs->cp0_epc +			dec_insn.pc_inc + dec_insn.next_pc_inc;		*contpc = regs->cp0_epc + dec_insn.pc_inc;		*contpc >>= 28;		*contpc <<= 28;		*contpc |= (insn.j_format.target << 2);		return 1;	case mm_jals32_op:	case mm_jal32_op:		regs->regs[31] = regs->cp0_epc +			dec_insn.pc_inc + dec_insn.next_pc_inc;		fallthrough;	case mm_j32_op:		*contpc = regs->cp0_epc + dec_insn.pc_inc;		*contpc >>= 27;		*contpc <<= 27;		*contpc |= (insn.j_format.target << 1);		set_isa16_mode(*contpc);		return 1;	}	return 0;} /* * Compute return address and emulate branch in microMIPS mode after an * exception only. It does not handle compact branches/jumps and cannot * be used in interrupt context. (Compact branches/jumps do not cause * exceptions.) */int __microMIPS_compute_return_epc(struct pt_regs *regs){	u16 __user *pc16;	u16 halfword;	unsigned int word;	unsigned long contpc;	struct mm_decoded_insn mminsn = { 0 }; 	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 sigsegv;	mminsn.next_pc_inc = 2;	word = ((unsigned int)halfword << 16); 	if (!mm_insn_16bit(halfword)) {		pc16++;		if (get_user(halfword, pc16))			goto sigsegv;		mminsn.next_pc_inc = 4;		word |= halfword;	}	mminsn.next_insn = word; 	mm_isBranchInstr(regs, mminsn, &contpc); 	regs->cp0_epc = contpc; 	return 0; sigsegv:	force_sig(SIGSEGV);	return -EFAULT;} /* * Compute return address and emulate branch in MIPS16e mode after an * exception only. It does not handle compact branches/jumps and cannot * be used in interrupt context. (Compact branches/jumps do not cause * exceptions.) */int __MIPS16e_compute_return_epc(struct pt_regs *regs){	u16 __user *addr;	union mips16e_instruction inst;	u16 inst2;	u32 fullinst;	long epc; 	epc = regs->cp0_epc; 	/* Read the instruction. */	addr = (u16 __user *)msk_isa16_mode(epc);	if (__get_user(inst.full, addr)) {		force_sig(SIGSEGV);		return -EFAULT;	} 	switch (inst.ri.opcode) {	case MIPS16e_extend_op:		regs->cp0_epc += 4;		return 0; 		/*		 *  JAL and JALX in MIPS16e mode		 */	case MIPS16e_jal_op:		addr += 1;		if (__get_user(inst2, addr)) {			force_sig(SIGSEGV);			return -EFAULT;		}		fullinst = ((unsigned)inst.full << 16) | inst2;		regs->regs[31] = epc + 6;		epc += 4;		epc >>= 28;		epc <<= 28;		/*		 * JAL:5 X:1 TARGET[20-16]:5 TARGET[25:21]:5 TARGET[15:0]:16		 *		 * ......TARGET[15:0].................TARGET[20:16]...........		 * ......TARGET[25:21]		 */		epc |=		    ((fullinst & 0xffff) << 2) | ((fullinst & 0x3e00000) >> 3) |		    ((fullinst & 0x1f0000) << 7);		if (!inst.jal.x)			set_isa16_mode(epc);	/* Set ISA mode bit. */		regs->cp0_epc = epc;		return 0; 		/*		 *  J(AL)R(C)		 */	case MIPS16e_rr_op:		if (inst.rr.func == MIPS16e_jr_func) { 			if (inst.rr.ra)				regs->cp0_epc = regs->regs[31];			else				regs->cp0_epc =				    regs->regs[reg16to32[inst.rr.rx]]; 			if (inst.rr.l) {				if (inst.rr.nd)					regs->regs[31] = epc + 2;				else					regs->regs[31] = epc + 4;			}			return 0;		}		break;	} 	/*	 * All other cases have no branch delay slot and are 16-bits.	 * Branches do not cause an exception.	 */	regs->cp0_epc += 2; 	return 0;} /** * __compute_return_epc_for_insn - Computes the return address and do emulate *				    branch simulation, if required. * * @regs:	Pointer to pt_regs * @insn:	branch instruction to decode * Return:	-EFAULT on error and forces SIGILL, and on success *		returns 0 or BRANCH_LIKELY_TAKEN as appropriate after *		evaluating the branch. * * MIPS R6 Compact branches and forbidden slots: *	Compact branches do not throw exceptions because they do *	not have delay slots. The forbidden slot instruction ($PC+4) *	is only executed if the branch was not taken. Otherwise the *	forbidden slot is skipped entirely. This means that the *	only possible reason to be here because of a MIPS R6 compact *	branch instruction is that the forbidden slot has thrown one. *	In that case the branch was not taken, so the EPC can be safely *	set to EPC + 8. */int __compute_return_epc_for_insn(struct pt_regs *regs,				   union mips_instruction insn){	long epc = regs->cp0_epc;	unsigned int dspcontrol;	int ret = 0; 	switch (insn.i_format.opcode) {	/*	 * jr and jalr are in r_format format.	 */	case spec_op:		switch (insn.r_format.func) {		case jalr_op:			regs->regs[insn.r_format.rd] = epc + 8;			fallthrough;		case jr_op:			if (NO_R6EMU && insn.r_format.func == jr_op)				goto sigill_r2r6;			regs->cp0_epc = regs->regs[insn.r_format.rs];			break;		}		break; 	/*	 * This group contains:	 * bltz_op, bgez_op, bltzl_op, bgezl_op,	 * bltzal_op, bgezal_op, bltzall_op, bgezall_op.	 */	case bcond_op:		switch (insn.i_format.rt) {		case bltzl_op:			if (NO_R6EMU)				goto sigill_r2r6;			fallthrough;		case bltz_op:			if ((long)regs->regs[insn.i_format.rs] < 0) {				epc = epc + 4 + (insn.i_format.simmediate << 2);				if (insn.i_format.rt == bltzl_op)					ret = BRANCH_LIKELY_TAKEN;			} else				epc += 8;			regs->cp0_epc = epc;			break; 		case bgezl_op:			if (NO_R6EMU)				goto sigill_r2r6;			fallthrough;		case bgez_op:			if ((long)regs->regs[insn.i_format.rs] >= 0) {				epc = epc + 4 + (insn.i_format.simmediate << 2);				if (insn.i_format.rt == bgezl_op)					ret = BRANCH_LIKELY_TAKEN;			} else				epc += 8;			regs->cp0_epc = epc;			break; 		case bltzal_op:		case bltzall_op:			if (NO_R6EMU && (insn.i_format.rs ||			    insn.i_format.rt == bltzall_op))				goto sigill_r2r6;			regs->regs[31] = epc + 8;			/*			 * OK we are here either because we hit a NAL			 * instruction or because we are emulating an			 * old bltzal{,l} one. Let's figure out what the			 * case really is.			 */			if (!insn.i_format.rs) {				/*				 * NAL or BLTZAL with rs == 0				 * Doesn't matter if we are R6 or not. The				 * result is the same				 */				regs->cp0_epc += 4 +					(insn.i_format.simmediate << 2);

Lines 1–500 of 908.