[Top] [All Lists]

Re: Should send SIGFPE to .*

To: "Florian Lohoff" <>, <>
Subject: Re: Should send SIGFPE to .*
From: "Kevin D. Kissell" <>
Date: Thu, 20 Apr 2000 18:42:15 +0200
>    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)

        if(!(mips_cpu.options & MIPS_CPU_FPU))
                panic("Floating Point Exception with No FPU");

        if (fpe_handler != NULL) {
                fpe_handler(regs, fcr31);

        if (fcr31 & FPU_CSR_UNI_X) {
                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.

                /* Run the emulator */
                sig = fpu_emulator_cop1Handler(0, regs);

                /* Restore the hardware register state */

                /* If something went wrong, signal */
                if(sig) {
                        force_sig(sig, current);
                /* 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",
                        fcr31 &= ~FPU_CSR_UNI_X;
                        fcr31 |= (1<<24);
                        __asm__ __volatile__(
                                : /* 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);

                goto out;

        if (compute_return_epc(regs)) {
                goto out;
        force_sig(SIGFPE, current);
        printk(KERN_DEBUG "Sent SIGFPE to %s\n", current->comm);


<Prev in Thread] Current Thread [Next in Thread>