|
|
|
@ -20,13 +20,13 @@ |
|
|
|
|
#include <asm/uaccess.h> |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Calculate and return exception PC in case of branch delay |
|
|
|
|
* slot for microMIPS. It does not clear the ISA mode bit. |
|
|
|
|
* 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) |
|
|
|
|
{ |
|
|
|
|
long epc = regs->cp0_epc; |
|
|
|
|
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))) { |
|
|
|
@ -34,8 +34,13 @@ int __isa_exception_epc(struct pt_regs *regs) |
|
|
|
|
force_sig(SIGSEGV, current); |
|
|
|
|
return epc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mm_insn_16bit(inst)) |
|
|
|
|
if (cpu_has_mips16) { |
|
|
|
|
if (((union mips16e_instruction)inst).ri.opcode |
|
|
|
|
== MIPS16e_jal_op) |
|
|
|
|
epc += 4; |
|
|
|
|
else |
|
|
|
|
epc += 2; |
|
|
|
|
} else if (mm_insn_16bit(inst)) |
|
|
|
|
epc += 2; |
|
|
|
|
else |
|
|
|
|
epc += 4; |
|
|
|
@ -101,6 +106,94 @@ 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, current); |
|
|
|
|
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, current); |
|
|
|
|
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. |
|
|
|
|