fix unaligned references inside s/w pipelined loops
PATCH 1/1 fix unaligned references inside s/w pipelined loops
If an application takes an unaligned trap on a "rotating" register inside a software pipelined loop[1], then the kernel will use the wrong register when it fixes the fault. This results in corrupted memory or register depending on whether the unaligned reference was a store or a load respectively.
Attached is a patch to fix this (both for the integer case, which was the one actually reported to me, and the floating point case too). Patch is against 2.4.10.
-Tony Luck
[1] Don't ask me why someone would go through all the effort of writing a s/w pipelined loop, but not check for unaligned access, I don't understand it either ... but they did.
arch/ia64/kernel/unaligned.c renamed from ../REF/2.4.10-ia64-combo/arch/ia64/kernel/unaligned.c +31 -10
@@ -5,6 +5,7 @@* Copyright (C) 1999-2000 Stephane Eranian <[email protected]> * Copyright (C) 2001 David Mosberger-Tang <[email protected]> * +* 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);