--- ../../REF/2.4.10-ia64-combo/arch/ia64/kernel/unaligned.c Wed Oct 3 11:02:18 2001 +++ linux/arch/ia64/kernel/unaligned.c Thu Oct 11 09:00:54 2001 @@ -5,6 +5,7 @@ * Copyright (C) 1999-2000 Stephane Eranian * Copyright (C) 2001 David Mosberger-Tang * + * 2001/10/11 Fix unaligned access to rotating registers in s/w pipelined loops. * 2001/08/13 Correct size of extended floats (float_fsz) from 16 to 10 bytes. * 2001/01/17 Add support emulation of unaligned kernel accesses. */ @@ -283,9 +284,19 @@ unsigned long rnats, nat_mask; unsigned long on_kbs; long sof = (regs->cr_ifs) & 0x7f; + long sor = 8 * ((regs->cr_ifs >> 14) & 0xf); + long rrb_gr = (regs->cr_ifs >> 18) & 0x7f; + long ridx; + + if ((r1 - 32) > sor) + ridx = -sof + (r1 - 32); + else if ((r1 - 32) < (sor - rrb_gr)) + ridx = -sof + (r1 - 32) + rrb_gr; + else + ridx = -sof + (r1 - 32) - (sor - rrb_gr); - DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n", - r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f); + DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n", + r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx); if ((r1 - 32) >= sof) { /* this should never happen, as the "rsvd register fault" has higher priority */ @@ -294,7 +305,7 @@ } on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore); - addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32)); + addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx); if (addr >= kbs) { /* the register is on the kernel backing store: easy... */ rnat_addr = ia64_rse_rnat_addr(addr); @@ -319,12 +330,12 @@ return; } - bspstore = (unsigned long *) regs->ar_bspstore; + bspstore = (unsigned long *)regs->ar_bspstore; ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); bsp = ia64_rse_skip_regs(ubs_end, -sof); - addr = ia64_rse_skip_regs(bsp, r1 - 32); + addr = ia64_rse_skip_regs(bsp, ridx + sof); - DPRINT("ubs_end=%p bsp=%p addr=%px\n", (void *) ubs_end, (void *) bsp, (void *) addr); + DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr); ia64_poke(current, sw, (unsigned long) ubs_end, (unsigned long) addr, val); @@ -354,9 +365,19 @@ unsigned long rnats, nat_mask; unsigned long on_kbs; long sof = (regs->cr_ifs) & 0x7f; + long sor = 8 * ((regs->cr_ifs >> 14) & 0xf); + long rrb_gr = (regs->cr_ifs >> 18) & 0x7f; + long ridx; + + if ((r1 - 32) > sor) + ridx = -sof + (r1 - 32); + else if ((r1 - 32) < (sor - rrb_gr)) + ridx = -sof + (r1 - 32) + rrb_gr; + else + ridx = -sof + (r1 - 32) - (sor - rrb_gr); - DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n", - r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f); + DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n", + r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx); if ((r1 - 32) >= sof) { /* this should never happen, as the "rsvd register fault" has higher priority */ @@ -365,7 +386,7 @@ } on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore); - addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32)); + addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx); if (addr >= kbs) { /* the register is on the kernel backing store: easy... */ *val = *addr; @@ -391,7 +412,7 @@ bspstore = (unsigned long *)regs->ar_bspstore; ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); bsp = ia64_rse_skip_regs(ubs_end, -sof); - addr = ia64_rse_skip_regs(bsp, r1 - 32); + addr = ia64_rse_skip_regs(bsp, ridx + sof); DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);