diff -urN 2.2.20pre8/arch/alpha/kernel/entry.S z/arch/alpha/kernel/entry.S --- 2.2.20pre8/arch/alpha/kernel/entry.S Tue Jul 31 16:02:29 2001 +++ z/arch/alpha/kernel/entry.S Tue Aug 7 14:59:04 2001 @@ -287,6 +287,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) @@ -298,6 +300,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) @@ -332,10 +335,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) @@ -346,6 +352,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) @@ -379,6 +386,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.2.20pre8/arch/alpha/kernel/proto.h z/arch/alpha/kernel/proto.h --- 2.2.20pre8/arch/alpha/kernel/proto.h Thu Jan 25 14:14:56 2001 +++ z/arch/alpha/kernel/proto.h Tue Aug 7 14:59:04 2001 @@ -214,6 +214,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 generic_kill_arch (int mode, char *reboot_cmd); extern int cpu_idle(void *) __attribute__((noreturn)); diff -urN 2.2.20pre8/arch/alpha/kernel/traps.c z/arch/alpha/kernel/traps.c --- 2.2.20pre8/arch/alpha/kernel/traps.c Tue Jul 31 16:02:29 2001 +++ z/arch/alpha/kernel/traps.c Tue Aug 7 15:00:51 2001 @@ -384,6 +384,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("Instruction fault", ®s, type, 0); }