@ -14,10 +14,93 @@
# include <asm/cpu.h>
# include <asm/cpu-features.h>
# include <asm/fpu.h>
# include <asm/fpu_emulator.h>
# include <asm/inst.h>
# include <asm/ptrace.h>
# 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 .
*/
int __isa_exception_epc ( struct pt_regs * regs )
{
long epc = regs - > cp0_epc ;
unsigned short inst ;
/* 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 , current ) ;
return epc ;
}
if ( mm_insn_16bit ( inst ) )
epc + = 2 ;
else
epc + = 4 ;
return epc ;
}
/*
* 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 , current ) ;
return - EFAULT ;
}
/**
* __compute_return_epc_for_insn - Computes the return address and do emulate
* branch simulation , if required .
@ -129,6 +212,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
epc < < = 28 ;
epc | = ( insn . j_format . target < < 2 ) ;
regs - > cp0_epc = epc ;
if ( insn . i_format . opcode = = jalx_op )
set_isa16_mode ( regs - > cp0_epc ) ;
break ;
/*