diff -urN 2.4.10pre9/arch/alpha/kernel/entry.S alpha-fp/arch/alpha/kernel/entry.S --- 2.4.10pre9/arch/alpha/kernel/entry.S Sat Aug 11 08:03:53 2001 +++ alpha-fp/arch/alpha/kernel/entry.S Fri Sep 14 06:30:18 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 -urN 2.4.10pre9/arch/alpha/kernel/proto.h alpha-fp/arch/alpha/kernel/proto.h --- 2.4.10pre9/arch/alpha/kernel/proto.h Sun Apr 1 20:36:06 2001 +++ alpha-fp/arch/alpha/kernel/proto.h Fri Sep 14 06:30:18 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 -urN 2.4.10pre9/arch/alpha/kernel/traps.c alpha-fp/arch/alpha/kernel/traps.c --- 2.4.10pre9/arch/alpha/kernel/traps.c Fri Sep 14 04:05:38 2001 +++ alpha-fp/arch/alpha/kernel/traps.c Fri Sep 14 06:32:19 2001 @@ -218,6 +218,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; + } + } if (!opDEC_testing || type != 4) { die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"), ®s, type, 0);