diff -burN linux-2.4.7/arch/alpha/kernel/entry.S linux-247-patched/arch/alpha/kernel/entry.S --- linux-2.4.7/arch/alpha/kernel/entry.S Thu Jul 26 16:45:31 2001 +++ linux-247-patched/arch/alpha/kernel/entry.S Wed Aug 1 17:28:50 2001 @@ -290,6 +290,8 @@ .end __kernel_execve .align 3 +.globl do_switch_fp_start +.globl do_switch_fp_end .ent do_switch_stack do_switch_stack: lda $30,-SWITCH_STACK_SIZE($30) @@ -301,6 +303,7 @@ stq $14,40($30) stq $15,48($30) stq $26,56($30) +do_switch_fp_start: stt $f0,64($30) stt $f1,72($30) stt $f2,80($30) @@ -335,10 +338,13 @@ stt $f30,304($30) stt $f0,312($30) # save fpcr in slot of $f31 ldt $f0,64($30) # dont let "do_switch_stack" change fp state. +do_switch_fp_end: ret $31,($1),1 .end do_switch_stack .align 3 +.globl undo_switch_fp_start +.globl undo_switch_fp_end .ent undo_switch_stack undo_switch_stack: ldq $9,0($30) @@ -349,6 +355,7 @@ ldq $14,40($30) ldq $15,48($30) ldq $26,56($30) +undo_switch_fp_start: ldt $f30,312($30) # get saved fpcr ldt $f0,64($30) ldt $f1,72($30) @@ -382,6 +389,7 @@ ldt $f28,288($30) ldt $f29,296($30) ldt $f30,304($30) +undo_switch_fp_end: lda $30,SWITCH_STACK_SIZE($30) ret $31,($1),1 .end undo_switch_stack diff -burN linux-2.4.7/arch/alpha/kernel/proto.h linux-247-patched/arch/alpha/kernel/proto.h --- linux-2.4.7/arch/alpha/kernel/proto.h Thu Jul 26 16:16:37 2001 +++ linux-247-patched/arch/alpha/kernel/proto.h Wed Aug 1 17:28:54 2001 @@ -134,6 +134,11 @@ extern void entUna(void); extern void entDbg(void); +extern void do_switch_fp_start(void); +extern void do_switch_fp_end(void); +extern void undo_switch_fp_start(void); +extern void undo_switch_fp_end(void); + /* process.c */ extern void cpu_idle(void) __attribute__((noreturn)); diff -burN linux-2.4.7/arch/alpha/kernel/traps.c linux-247-patched/arch/alpha/kernel/traps.c --- linux-2.4.7/arch/alpha/kernel/traps.c Thu Jul 26 16:45:31 2001 +++ linux-247-patched/arch/alpha/kernel/traps.c Wed Aug 1 17:29:01 2001 @@ -188,6 +188,23 @@ unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { + if (type == 3 && !(regs.ps & 8) ) { + /* + * Handle a rare case where the user has disabled floating + * point using the clrfen PALcall and the kernel is attempting + * to view floating point state. This happens in two asm stubs: + * do_switch_stack and undo_switch_stack. + * If this is the case, we modify the return value to pass + * over this section and resume from there. + */ + if (regs.pc == (unsigned long) do_switch_fp_start) { + regs.pc = (unsigned long) do_switch_fp_end; + return; + } else if (regs.pc == (unsigned long) undo_switch_fp_start) { + regs.pc = (unsigned long) undo_switch_fp_end; + return; + } + } die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"), ®s, type, 0);