Skip to content
Snippets Groups Projects
Select Git revision
  • 547af560ddbfe469ada2cad3009cbcfde313d73c
  • seco_lf-6.6.52-2.2.1 default protected
  • seco_lf-6.6.52-2.2.1-tr8mp-mcu
  • integrate/gitlab-ci/use-board-only-instead-codename-and-board-in-the-configuration/into/seco_lf-5.10.y
  • integrate/gitlab-ci/oleksii/fix-mtk-misc-artifacts/into/seco_lf-6.6.52-2.2.1
  • seco_lf-6.6.52-2.2.1-tr8mp-dtb
  • seco_lf-6.6.52-2.2.1-tr8mp-fpga
  • integrate/gitlab-ci/use-board-only-instead-codename-and-board-in-the-configuration/into/seco_lf-6.6.52-2.2.1
  • seco_lf-6.6.52-2.2.1-tr8mp-rv3028
  • seco_lf-6.6.23-2.0.0_e39-e83-p4-devicetree
  • integrate/gitlab-ci/cleaos-894-rename-distros-into-build-tergets/into/seco_lf-5.10.y
  • integrate/gitlab-ci/cleaos-894-rename-distros-into-build-tergets/into/seco_lf-6.6.52-2.2.1
  • seco_lf-5.10.y protected
  • seco_lf-6.6.52-2.2.1_e88-dev
  • seco_lf-6.6.52-2.2.1_ov5640-mx95-dev
  • seco_lf-6.6.52-2.2.1-tr8mp-rgb-defconfig
  • seco_lf-6.6.52-2.2.1-tr8mp-dev
  • seco_lf-6.6.52-2.2.1-tr8mp-dtbo
  • seco_lf-6.6.52-2.2.1_stm32g0-dev
  • seco_lf-6.6.52-2.2.1_remove-mwifiex_d18
  • seco_lf-6.6.52-2.2.1_e88-dbg-uart-dev
  • lf-6.6.52-2.2.1
  • lf-6.1.55-2.2.1
  • lf-6.6.3-1.0.0
  • lf-6.6.3-imx95-er2
  • lf-6.1.55-2.2.0
  • lf-6.6.y-imx95-er1
  • lf-5.15.71-2.2.2
  • lf-6.1.36-2.1.0
  • lf-5.15.71-2.2.1
  • lf-6.1.22-2.0.0
  • lf-6.1.1-1.0.1
  • rel_imx_5.4.24_2.1.4
  • rel_imx_4.9.88_2.0.13
  • rel_imx_4.14.98_2.3.5
  • lf-6.1.1-1.0.0
  • rel_imx_5.4.3_2.0.2
  • lf-5.15.71-2.2.0
  • lf-5.10.72-2.2.3
  • lf-5.15.52-2.1.0
  • imx_5.15.52_imx8ulp_er1
41 results

branch.c

Blame
  • user avatar
    Al Viro authored and Ralf Baechle committed
    Put the original syscall number into ->regs[0] when we leave syscall
    with error.  Use it in restart logics.  Everything else will have
    it 0 since we pass through SAVE_SOME on all the ways in.  Note that
    in places like bad_stack and inllegal_syscall we leave it 0 - it's not
    restartable.
    
    Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
    Cc: linux-kernel@vger.kernel.org
    Cc: linux-arch@vger.kernel.org
    Cc: linux-mips@linux-mips.org
    Patchwork: https://patchwork.linux-mips.org/patch/1698/
    
    
    Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
    8f5a00eb
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    branch.c 5.46 KiB
    /*
     * 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.h>
    #include <linux/signal.h>
    #include <asm/branch.h>
    #include <asm/cpu.h>
    #include <asm/cpu-features.h>
    #include <asm/fpu.h>
    #include <asm/inst.h>
    #include <asm/ptrace.h>
    #include <asm/uaccess.h>
    
    /*
     * Compute the return address and do emulate branch simulation, if required.
     */
    int __compute_return_epc(struct pt_regs *regs)
    {
    	unsigned int __user *addr;
    	unsigned int bit, fcr31, dspcontrol;
    	long epc;
    	union mips_instruction insn;
    
    	epc = regs->cp0_epc;
    	if (epc & 3)
    		goto unaligned;
    
    	/*
    	 * Read the instruction
    	 */
    	addr = (unsigned int __user *) epc;
    	if (__get_user(insn.word, addr)) {
    		force_sig(SIGSEGV, current);
    		return -EFAULT;
    	}
    
    	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;
    			/* Fall through */
    		case jr_op:
    			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 bltz_op:
    		case bltzl_op:
    			if ((long)regs->regs[insn.i_format.rs] < 0)
    				epc = epc + 4 + (insn.i_format.simmediate << 2);
    			else
    				epc += 8;
    			regs->cp0_epc = epc;
    			break;
    
    		case bgez_op:
    		case bgezl_op:
    			if ((long)regs->regs[insn.i_format.rs] >= 0)
    				epc = epc + 4 + (insn.i_format.simmediate << 2);
    			else
    				epc += 8;
    			regs->cp0_epc = epc;
    			break;
    
    		case bltzal_op:
    		case bltzall_op:
    			regs->regs[31] = epc + 8;
    			if ((long)regs->regs[insn.i_format.rs] < 0)
    				epc = epc + 4 + (insn.i_format.simmediate << 2);
    			else
    				epc += 8;
    			regs->cp0_epc = epc;
    			break;
    
    		case bgezal_op:
    		case bgezall_op:
    			regs->regs[31] = epc + 8;
    			if ((long)regs->regs[insn.i_format.rs] >= 0)
    				epc = epc + 4 + (insn.i_format.simmediate << 2);
    			else
    				epc += 8;
    			regs->cp0_epc = epc;
    			break;
    		case bposge32_op:
    			if (!cpu_has_dsp)
    				goto sigill;
    
    			dspcontrol = rddsp(0x01);
    
    			if (dspcontrol >= 32) {
    				epc = epc + 4 + (insn.i_format.simmediate << 2);
    			} else
    				epc += 8;
    			regs->cp0_epc = epc;
    			break;
    		}
    		break;
    
    	/*
    	 * These are unconditional and in j_format.
    	 */
    	case jal_op:
    		regs->regs[31] = regs->cp0_epc + 8;
    	case j_op:
    		epc += 4;
    		epc >>= 28;
    		epc <<= 28;
    		epc |= (insn.j_format.target << 2);
    		regs->cp0_epc = epc;
    		break;
    
    	/*
    	 * These are conditional and in i_format.
    	 */
    	case beq_op:
    	case beql_op:
    		if (regs->regs[insn.i_format.rs] ==
    		    regs->regs[insn.i_format.rt])
    			epc = epc + 4 + (insn.i_format.simmediate << 2);
    		else
    			epc += 8;
    		regs->cp0_epc = epc;
    		break;
    
    	case bne_op:
    	case bnel_op:
    		if (regs->regs[insn.i_format.rs] !=
    		    regs->regs[insn.i_format.rt])
    			epc = epc + 4 + (insn.i_format.simmediate << 2);
    		else
    			epc += 8;
    		regs->cp0_epc = epc;
    		break;
    
    	case blez_op: /* not really i_format */
    	case blezl_op:
    		/* rt field assumed to be zero */
    		if ((long)regs->regs[insn.i_format.rs] <= 0)
    			epc = epc + 4 + (insn.i_format.simmediate << 2);
    		else
    			epc += 8;
    		regs->cp0_epc = epc;
    		break;
    
    	case bgtz_op:
    	case bgtzl_op:
    		/* rt field assumed to be zero */
    		if ((long)regs->regs[insn.i_format.rs] > 0)
    			epc = epc + 4 + (insn.i_format.simmediate << 2);
    		else
    			epc += 8;
    		regs->cp0_epc = epc;
    		break;
    
    	/*
    	 * And now the FPA/cp1 branch instructions.
    	 */
    	case cop1_op:
    		preempt_disable();
    		if (is_fpu_owner())
    			asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
    		else
    			fcr31 = current->thread.fpu.fcr31;
    		preempt_enable();
    
    		bit = (insn.i_format.rt >> 2);
    		bit += (bit != 0);
    		bit += 23;
    		switch (insn.i_format.rt & 3) {
    		case 0:	/* bc1f */
    		case 2:	/* bc1fl */
    			if (~fcr31 & (1 << bit))
    				epc = epc + 4 + (insn.i_format.simmediate << 2);
    			else
    				epc += 8;
    			regs->cp0_epc = epc;
    			break;
    
    		case 1:	/* bc1t */
    		case 3:	/* bc1tl */
    			if (fcr31 & (1 << bit))
    				epc = epc + 4 + (insn.i_format.simmediate << 2);
    			else
    				epc += 8;
    			regs->cp0_epc = epc;
    			break;
    		}
    		break;
    #ifdef CONFIG_CPU_CAVIUM_OCTEON
    	case lwc2_op: /* This is bbit0 on Octeon */
    		if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
    		     == 0)
    			epc = epc + 4 + (insn.i_format.simmediate << 2);
    		else
    			epc += 8;
    		regs->cp0_epc = epc;
    		break;
    	case ldc2_op: /* This is bbit032 on Octeon */
    		if ((regs->regs[insn.i_format.rs] &
    		    (1ull<<(insn.i_format.rt+32))) == 0)
    			epc = epc + 4 + (insn.i_format.simmediate << 2);
    		else
    			epc += 8;
    		regs->cp0_epc = epc;
    		break;
    	case swc2_op: /* This is bbit1 on Octeon */
    		if (regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
    			epc = epc + 4 + (insn.i_format.simmediate << 2);
    		else
    			epc += 8;
    		regs->cp0_epc = epc;
    		break;
    	case sdc2_op: /* This is bbit132 on Octeon */
    		if (regs->regs[insn.i_format.rs] &
    		    (1ull<<(insn.i_format.rt+32)))
    			epc = epc + 4 + (insn.i_format.simmediate << 2);
    		else
    			epc += 8;
    		regs->cp0_epc = epc;
    		break;
    #endif
    	}
    
    	return 0;
    
    unaligned:
    	printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
    	force_sig(SIGBUS, current);
    	return -EFAULT;
    
    sigill:
    	printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
    	force_sig(SIGBUS, current);
    	return -EFAULT;
    }