>arch/mips/kernel/traps.c
>
> 354 printk(KERN_DEBUG "Unimplemented exception for insn
%08x at 0x%08lx in %s.\n",
> 355 insn, regs->cp0_epc, current->comm);
> 356 simfp(insn);
> 357 }
> 358
> 359 if (compute_return_epc(regs))
> 360 goto out;
> 361 //force_sig(SIGFPE, current);
> 362 printk(KERN_DEBUG "Should send SIGFPE to %s\n", current->comm);
> 363
> 364 out:
> 365 unlock_kernel();
>
>
>Might it be that compute_return_epc in branch.c does not support
>the mentioned instructions (FP instructions ?) and though can not
>calculate the correct epc ?
My previous response was a bit confused, because I was
looking at our already-modified code and reconstructing
the old logic. Looking at the more-or-less-current 2.3
tree, I see the further bug to which you are referring.
There *should* be another goto following the simfp()
call. The code that does the compute_return_epc()
followed by the force_sig(SIGFP) should be executed
in all cases where the emulator was not invoked,
which is to say in the cases of real FP exceptions,
but not if the mini-emulator has handled the situation.
Presumably, the absence of that bypass path was causing
bogus SIGFPE's, prompting someone to comment
out the force_sig() in all cases and add the printk(),
but that's not the correct behaviour.
The overall handler (MIPS version) looks like this:
(and yes, it still can be improved, as I mentioned earlier...)
/*
* XXX Delayed fp exceptions when doing a lazy ctx switch XXX
*/
void do_fpe(struct pt_regs *regs, unsigned long fcr31)
{
#ifdef CONFIG_MIPS_FPU_EMULATOR
if(!(mips_cpu.options & MIPS_CPU_FPU))
panic("Floating Point Exception with No FPU");
#endif
#ifdef CONFIG_MIPS_FPE_MODULE
if (fpe_handler != NULL) {
fpe_handler(regs, fcr31);
return;
}
#endif
lock_kernel();
if (fcr31 & FPU_CSR_UNI_X) {
#ifdef CONFIG_MIPS_FPU_EMULATOR
extern void r4xx0_save_fp(struct task_struct *);
extern void r4xx0_restore_fp(struct task_struct *);
int sig;
/*
* Unimplemented operation exception. If we've got the
* Full software emulator on-board, let's use it...
*
* Force FPU to dump state into task/thread context.
* We're moving a lot of data here for what is probably
* a single instruction, but the alternative is to
* pre-decode the FP register operands before invoking
* the emulator, which seems a bit extreme for what
* should be an infrequent event.
*/
r4xx0_save_fp(current);
/* Run the emulator */
sig = fpu_emulator_cop1Handler(0, regs);
/* Restore the hardware register state */
r4xx0_restore_fp(current);
/* If something went wrong, signal */
if(sig) {
force_sig(sig, current);
}
#else
/* Else use mini-emulator */
extern void simfp(int);
unsigned long pc;
unsigned int insn;
/* Retry instruction with flush to zero ... */
if (!(fcr31 & (1<<24))) {
printk("Setting flush to zero for %s.\n",
current->comm);
fcr31 &= ~FPU_CSR_UNI_X;
fcr31 |= (1<<24);
__asm__ __volatile__(
"ctc1\t%0,$31"
: /* No outputs */
: "r" (fcr31));
goto out;
}
pc = regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0);
if(pc & 0x80000000) insn = *(unsigned int *)pc;
else if (get_user(insn, (unsigned int *)pc)) {
/* XXX Can this happen? */
force_sig(SIGSEGV, current);
}
printk(KERN_DEBUG "Unimplemented exception for insn %08x at
0x%8lx in %s.\n",
insn, regs->cp0_epc, current->comm);
simfp(MIPSInst(insn));
compute_return_epc(regs);
#endif /* CONFIG_MIPS_FPU_EMULATOR */
goto out;
}
if (compute_return_epc(regs)) {
goto out;
}
force_sig(SIGFPE, current);
printk(KERN_DEBUG "Sent SIGFPE to %s\n", current->comm);
out:
unlock_kernel();
}
|