Would someone with an affected system (Multia or Jensen) try this out?
It removes two global variables, and avoids an extra test once we're
done with startup code.
r~
--- 2.4.15-7/arch/alpha/kernel/traps.c.~2~ Mon Nov 19 23:05:50 2001
+++ 2.4.15-7/arch/alpha/kernel/traps.c Mon Nov 19 23:07:32 2001
@@ -24,31 +24,32 @@
#include "proto.h"
-/* data/code implementing a work-around for some SRMs which
- mishandle opDEC faults
-*/
-static int opDEC_testing = 0;
-static int opDEC_fix = 0;
-static unsigned long opDEC_test_pc = 0;
+/* Work-around for some SRMs which mishandle opDEC faults. */
+static int opDEC_fix;
static void
opDEC_check(void)
{
- unsigned long test_pc;
+ unsigned long data;
- lock_kernel();
- opDEC_testing = 1;
+ /* We temporarily set opDEC_fix so that we skip forward to either
+ the cmpteq (for a broken srm) or the addt (for a working srm).
+ Because of this skip, at the end of the sequence $f0 will be 0
+ for a working srm, and 2.0 for a broken srm. */
- __asm__ __volatile__(
- " br %0,1f\n"
- "1: addq %0,8,%0\n"
- " stq %0,%1\n"
- " cvttq/svm $f31,$f31\n"
- : "=&r"(test_pc), "=m"(opDEC_test_pc)
- : );
+ opDEC_fix = 8;
- opDEC_testing = 0;
- unlock_kernel();
+ __asm__ __volatile__(
+ "fmov $f31, $f0\n\t"
+ "cvttq/svm $f31, $f31\n\t"
+ "cmpteq $f31, $f31, $f0\n\t"
+ "addt $f31, $f31, $f31\n\t"
+ "stt $f0, %0"
+ : "=m"(data));
+
+ opDEC_fix = data ? 4 : 0;
+ if (data)
+ printk("opDEC fixup enabled.\n");
}
void
@@ -231,24 +232,22 @@ do_entIF(unsigned long type, unsigned lo
unsigned long a2, unsigned long a3, unsigned long a4,
unsigned long a5, struct pt_regs regs)
{
- if (!opDEC_testing || type != 4) {
- die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"),
- ®s, type, 0);
- }
-
switch (type) {
- case 0: /* breakpoint */
+ case 0: /* breakpoint */
+ die_if_kernel("Breakpoint fault", ®s, type, 0);
if (ptrace_cancel_bpt(current)) {
regs.pc -= 4; /* make pc point to former bpt */
}
send_sig(SIGTRAP, current, 1);
return;
- case 1: /* bugcheck */
+ case 1: /* bugcheck */
+ die_if_kernel("Kernel Bug", ®s, type, 0);
send_sig(SIGTRAP, current, 1);
return;
- case 2: /* gentrap */
+ case 2: /* gentrap */
+ die_if_kernel("Divide by zero fault", ®s, type, 0);
/*
* The exception code should be passed on to the signal
* handler as the second argument. Linux doesn't do that
@@ -285,27 +284,14 @@ do_entIF(unsigned long type, unsigned lo
}
break;
- case 4: /* opDEC */
+ case 4: /* opDEC */
if (implver() == IMPLVER_EV4) {
- /* The some versions of SRM do not handle
- the opDEC properly - they return the PC of the
- opDEC fault, not the instruction after as the
- Alpha architecture requires. Here we fix it up.
- We do this by intentionally causing an opDEC
- fault during the boot sequence and testing if
- we get the correct PC. If not, we set a flag
- to correct it every time through.
- */
- if (opDEC_testing) {
- if (regs.pc == opDEC_test_pc) {
- opDEC_fix = 4;
- regs.pc += 4;
- printk("opDEC fixup enabled.\n");
- }
- return;
- }
+ /* Some versions of SRM do not handle opDEC properly.
+ They return the PC of the opDEC fault, not the
+ instruction after the fault as the architecture
+ requires. Here we fix it up. */
regs.pc += opDEC_fix;
-
+
/* EV4 does not implement anything except normal
rounding. Everything else will come here as
an illegal instruction. Emulate them. */
@@ -314,7 +300,7 @@ do_entIF(unsigned long type, unsigned lo
}
break;
- case 3: /* FEN fault */
+ case 3: /* FEN fault */
/* Irritating users can call PAL_clrfen to disable the
FPU for the process. The kernel will then trap in
do_switch_stack and undo_switch_stack when we try
@@ -328,10 +314,12 @@ do_entIF(unsigned long type, unsigned lo
__reload_thread(¤t->thread);
return;
- case 5: /* illoc */
- default: /* unexpected instruction-fault type */
- ;
+ case 5: /* illoc */
+ default: /* unexpected instruction-fault type */
+ break;
}
+
+ die_if_kernel("Instruction fault", ®s, type, 0);
send_sig(SIGILL, current, 1);
}
@@ -1014,9 +1002,7 @@ trap_init(void)
wrent(entDbg, 6);
/* Hack for Multia (UDB) and JENSEN: some of their SRMs have
- * a bug in the handling of the opDEC fault. Fix it up if so.
- */
- if (implver() == IMPLVER_EV4) {
+ a bug in the handling of the opDEC fault. Fix it up if so. */
+ if (implver() == IMPLVER_EV4)
opDEC_check();
- }
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Fri Nov 23 2001 - 21:00:22 EST