Kernels 2.1 with 386DX/387 IRQ13 PC boxes

root (root@mangue.ibm.net)
Tue, 28 Oct 1997 21:58:20 +0100 (MET)


Hello there,

I have a problem with kernels since at least 2.1.46 and up to 2.1.59
with my 386DX33 (AMD compatible) and my 387 Cyrix FasMath CX83D87-33 GP
math coprocessor. I think the problem appears also with a standart Intel
80386/80387 when IRQ13 is used.

First, if the kernel is build and run, it display just after math
coprocessor detection the message "lock in an interrupt context". Second,
it display that all the time so the kernel will not boot.

Problems are in directory linux/arch/i386/kernel, in files traps.c and
irq.c (and include/linux/kernel.h).
To remind things, when IRQ13 is called, function "math_error_irq" in
irq.c is called (see "struct irqaction irq13"), and it calls "math_error"
in traps.c.
Function "math_error" is only called at two places, the second one is
inside traps.c in "do_coprocessor_error" following an exception 16, so
in fact the prototype of "math_error" in file include/linux/kernel.h
could be put between #ifdef CONFIG_M386 , if someone want to clean.

The message "lock in an interrupt context" is due to the call of
"lock_kernel()" and "unlock_kernel()" in "math_error" because then
this function is called within an IRQ handler - IRQ 13 handler, and this
protection is probably not needed.
Because function "math_error" is only called at two places (for i386
architecture, I do not know for the others), we can safely put the
kernel protection in "do_coprocessor_error", and remove it from
"math_error".

******************** The function are then : *************************
void math_error(void)
{
struct task_struct * task;

clts();
#ifdef __SMP__
task = current;
#else
task = last_task_used_math;
last_task_used_math = NULL;
if (!task) {
__asm__("fnclex");
return;
}
#endif
/*
* Save the info for the exception handler
*/
__asm__ __volatile__("fnsave %0":"=m" (task->tss.i387.hard));
task->flags&=~PF_USEDFPU;
stts();

force_sig(SIGFPE, task);
task->tss.trap_no = 16;
task->tss.error_code = 0;
}

asmlinkage
void do_coprocessor_error(struct pt_regs * regs, long error_code)
{
ignore_irq13 = 1;
lock_kernel();
math_error();
unlock_kernel();
}
**********************************************************************
Then, the kernel will boot ONLY if SMP is NOT defined at compile time.

Now, the second problem is that the message "lock from interrupt
context" is continously displayed (if SMP is defined). I also found
a patch which seems to work but I am less sure of it : it seems that
the math assembly instruction "fnclex" is never executed...

If it is added in irq.c like :

static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
{
outb(0,0xF0);
printk ("IRQ13 ");
if (ignore_irq13 || !hard_math)
return;
math_error();
__asm__("fnclex");
}

the kernel will boot without any problem, and coprocessor seems to work
correctly.

Now my question : How to test it? How to generate an IRQ13 interrupt?
I tried writing a small C program which divide by zero or takes one
of its operand outside the valid address range. I tried to intercept
SIGFPE, I looked at /proc/interrupts. No way to produce such an
external interrupt from my coprocessor. I also have a "printk()" inside
"math_error_irq" to log this IRQ but it seems to never happen.

If you have any solution, I would like to hear it...

Thanks for reading,
Etienne.

-- E-mail : etienne.lorrain@ibm.net
------------- On ne voit bien qu'avec le coeur, --------------------
----- l'essentiel est invisible pour les yeux . St Exupery ---------