--- kernel.orig/arch/mips/kernel/unaligned.c Tue Jan 15 04:08:09 2002 +++ kernel/arch/mips/kernel/unaligned.c Fri Sep 27 16:58:22 2002 @@ -8,6 +8,11 @@ * Copyright (C) 1996, 1998 by Ralf Baechle * Copyright (C) 1999 Silicon Graphics, Inc. * + * Fixes: + * 2002 Denis Joseph Barrow + * Fix to do_ade to compute destination addresses correctly + * after fixing delay slot instructions. + * * This file contains exception handler for address error exception with the * special capability to execute faulting instructions in software. The * handler does not try to handle the case when the program counter points @@ -97,13 +102,15 @@ goto sigbus; static inline int emulate_load_store_insn(struct pt_regs *regs, - unsigned long addr, unsigned long pc) + unsigned long addr, unsigned long pc, + unsigned long **regptr,unsigned long *newvalue) { union mips_instruction insn; unsigned long value, fixup; unsigned int res; regs->regs[0] = 0; + *regptr=NULL; /* * This load never faults. */ @@ -169,7 +176,8 @@ : "r" (addr), "i" (-EFAULT)); if (res) goto fault; - regs->regs[insn.i_format.rt] = value; + *newvalue=value; + *regptr=®s->regs[insn.i_format.rt]; return 0; case lw_op: @@ -196,7 +204,8 @@ : "r" (addr), "i" (-EFAULT)); if (res) goto fault; - regs->regs[insn.i_format.rt] = value; + *newvalue=value; + *regptr=®s->regs[insn.i_format.rt]; return 0; case lhu_op: @@ -227,7 +236,8 @@ : "r" (addr), "i" (-EFAULT)); if (res) goto fault; - regs->regs[insn.i_format.rt] = value; + *newvalue=value; + *regptr=®s->regs[insn.i_format.rt]; return 0; case lwu_op: @@ -365,7 +375,7 @@ asmlinkage void do_ade(struct pt_regs *regs) { - unsigned long pc; + unsigned long pc,*regptr,newval; extern int do_dsemulret(struct pt_regs *); /* @@ -395,9 +405,18 @@ * Do branch emulation only if we didn't forward the exception. * This is all so but ugly ... */ - if (!emulate_load_store_insn(regs, regs->cp0_badvaddr, pc)) + if (!emulate_load_store_insn(regs, regs->cp0_badvaddr, pc,®ptr,&newval)) + { compute_return_epc(regs); - + /* We need use the regptr complication for delay slot instructions + * which can miscompute destination addresses + * e.g. consider the sequence + * beqz v0, + * lw v0,(t3) + */ + if(regptr) + *regptr=newval; + } #ifdef CONFIG_PROC_FS unaligned_instructions++; #endif --- kernel.orig/arch/mips64/kernel/unaligned.c Sat Jan 26 07:28:35 2002 +++ kernel/arch/mips64/kernel/unaligned.c Fri Sep 27 17:09:28 2002 @@ -8,6 +8,11 @@ * Copyright (C) 1996, 1998, 1999 by Ralf Baechle * Copyright (C) 1999 Silicon Graphics, Inc. * + * Fixes: + * 2002 Denis Joseph Barrow + * Fix to do_ade to compute destination addresses correctly + * after fixing delay slot instructions. + * * This file contains exception handler for address error exception with the * special capability to execute faulting instructions in software. The * handler does not try to handle the case when the program counter points @@ -97,12 +102,14 @@ goto sigbus; static inline int emulate_load_store_insn(struct pt_regs *regs, - unsigned long addr, unsigned long pc) + unsigned long addr, unsigned long pc, + unsigned long **regptr,unsigned long *newvalue) { union mips_instruction insn; unsigned long value, fixup; regs->regs[0] = 0; + *regptr=NULL; /* * This load never faults. */ @@ -162,7 +169,8 @@ ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault)); - regs->regs[insn.i_format.rt] = value; + *newvalue=value; + *regptr=®s->regs[insn.i_format.rt]; return 0; case lw_op: @@ -182,8 +190,9 @@ ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault)); - regs->regs[insn.i_format.rt] = value; - return 0; + *newvalue=value; + *regptr=®s->regs[insn.i_format.rt]; + return 0; case lhu_op: check_axs(pc, addr, 2); @@ -206,7 +215,8 @@ ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault)); - regs->regs[insn.i_format.rt] = value; + *newvalue=value; + *regptr=®s->regs[insn.i_format.rt]; return 0; case lwu_op: @@ -227,7 +237,8 @@ :"=&r" (value) :"r" (addr), "i" (&&fault)); value &= 0xffffffff; - regs->regs[insn.i_format.rt] = value; + *newvalue=value; + *regptr=®s->regs[insn.i_format.rt]; return 0; case ld_op: @@ -249,7 +260,8 @@ ".previous" :"=&r" (value) :"r" (addr), "i" (&&fault)); - regs->regs[insn.i_format.rt] = value; + *newvalue=value; + *regptr=®s->regs[insn.i_format.rt]; return 0; case sh_op: @@ -398,9 +410,18 @@ * Do branch emulation only if we didn't forward the exception. * This is all so but ugly ... */ - if (!emulate_load_store_insn(regs, regs->cp0_badvaddr, pc)) + if (!emulate_load_store_insn(regs, regs->cp0_badvaddr, pc,®ptr,&newval)) + { compute_return_epc(regs); - + /* We need use the regptr complication for delay slot instructions + * which can miscompute destination addresses + * e.g. consider the sequence + * beqz v0, + * lw v0,(t3) + */ + if(regptr) + *regptr=newval; + } #ifdef CONFIG_PROC_FS unaligned_instructions++; #endif