|
@@ -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.
|