Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 284774
b: refs/heads/master
c: 2c1b54d
h: refs/heads/master
v: v3
  • Loading branch information
Deng-Cheng Zhu authored and Ralf Baechle committed Dec 7, 2011
1 parent caeb01b commit 0b5cb7a
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 276 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6457a396bbc20656009eaf950ca165912a943520
refs/heads/master: 2c1b54d331bde7afbf8da24789cce2402e155495
5 changes: 0 additions & 5 deletions trunk/arch/mips/include/asm/branch.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#define _ASM_BRANCH_H

#include <asm/ptrace.h>
#include <asm/inst.h>

static inline int delay_slot(struct pt_regs *regs)
{
Expand All @@ -24,11 +23,7 @@ static inline unsigned long exception_epc(struct pt_regs *regs)
return regs->cp0_epc + 4;
}

#define BRANCH_LIKELY_TAKEN 0x0001

extern int __compute_return_epc(struct pt_regs *regs);
extern int __compute_return_epc_for_insn(struct pt_regs *regs,
union mips_instruction insn);

static inline int compute_return_epc(struct pt_regs *regs)
{
Expand Down
5 changes: 0 additions & 5 deletions trunk/arch/mips/include/asm/kprobes.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ struct prev_kprobe {
: MAX_JPROBES_STACK_SIZE)


#define SKIP_DELAYSLOT 0x0001

/* per-cpu kprobe control block */
struct kprobe_ctlblk {
unsigned long kprobe_status;
Expand All @@ -84,9 +82,6 @@ struct kprobe_ctlblk {
unsigned long kprobe_saved_epc;
unsigned long jprobe_saved_sp;
struct pt_regs jprobe_saved_regs;
/* Per-thread fields, used while emulating branches */
unsigned long flags;
unsigned long target_epc;
u8 jprobes_stack[MAX_JPROBES_STACK_SIZE];
struct prev_kprobe prev_kprobe;
};
Expand Down
128 changes: 44 additions & 84 deletions trunk/arch/mips/kernel/branch.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/module.h>
#include <asm/branch.h>
#include <asm/cpu.h>
#include <asm/cpu-features.h>
Expand All @@ -18,22 +17,28 @@
#include <asm/ptrace.h>
#include <asm/uaccess.h>

/**
* __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
* @returns: -EFAULT on error and forces SIGBUS, and on success
* returns 0 or BRANCH_LIKELY_TAKEN as appropriate after
* evaluating the branch.
/*
* Compute the return address and do emulate branch simulation, if required.
*/
int __compute_return_epc_for_insn(struct pt_regs *regs,
union mips_instruction insn)
int __compute_return_epc(struct pt_regs *regs)
{
unsigned int __user *addr;
unsigned int bit, fcr31, dspcontrol;
long epc = regs->cp0_epc;
int ret = 0;
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) {
/*
Expand All @@ -59,50 +64,41 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
switch (insn.i_format.rt) {
case bltz_op:
case bltzl_op:
if ((long)regs->regs[insn.i_format.rs] < 0) {
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
else
epc += 8;
regs->cp0_epc = epc;
break;

case bgez_op:
case bgezl_op:
if ((long)regs->regs[insn.i_format.rs] >= 0) {
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
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) {
if ((long)regs->regs[insn.i_format.rs] < 0)
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bltzall_op)
ret = BRANCH_LIKELY_TAKEN;
} else
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) {
if ((long)regs->regs[insn.i_format.rs] >= 0)
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bgezall_op)
ret = BRANCH_LIKELY_TAKEN;
} else
else
epc += 8;
regs->cp0_epc = epc;
break;

case bposge32_op:
if (!cpu_has_dsp)
goto sigill;
Expand Down Expand Up @@ -137,47 +133,39 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
case beq_op:
case beql_op:
if (regs->regs[insn.i_format.rs] ==
regs->regs[insn.i_format.rt]) {
regs->regs[insn.i_format.rt])
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == beql_op)
ret = BRANCH_LIKELY_TAKEN;
} else
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]) {
regs->regs[insn.i_format.rt])
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bnel_op)
ret = BRANCH_LIKELY_TAKEN;
} else
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) {
if ((long)regs->regs[insn.i_format.rs] <= 0)
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bnel_op)
ret = BRANCH_LIKELY_TAKEN;
} else
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) {
if ((long)regs->regs[insn.i_format.rs] > 0)
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bnel_op)
ret = BRANCH_LIKELY_TAKEN;
} else
else
epc += 8;
regs->cp0_epc = epc;
break;
Expand All @@ -199,22 +187,18 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
switch (insn.i_format.rt & 3) {
case 0: /* bc1f */
case 2: /* bc1fl */
if (~fcr31 & (1 << bit)) {
if (~fcr31 & (1 << bit))
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == 2)
ret = BRANCH_LIKELY_TAKEN;
} else
else
epc += 8;
regs->cp0_epc = epc;
break;

case 1: /* bc1t */
case 3: /* bc1tl */
if (fcr31 & (1 << bit)) {
if (fcr31 & (1 << bit))
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == 3)
ret = BRANCH_LIKELY_TAKEN;
} else
else
epc += 8;
regs->cp0_epc = epc;
break;
Expand Down Expand Up @@ -255,39 +239,15 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
#endif
}

return ret;

sigill:
printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
force_sig(SIGBUS, current);
return -EFAULT;
}
EXPORT_SYMBOL_GPL(__compute_return_epc_for_insn);

int __compute_return_epc(struct pt_regs *regs)
{
unsigned int __user *addr;
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;
}

return __compute_return_epc_for_insn(regs, insn);
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;
}
Loading

0 comments on commit 0b5cb7a

Please sign in to comment.