patch-2.4.21 linux-2.4.21/arch/ia64/kernel/unaligned.c
Next file: linux-2.4.21/arch/ia64/kernel/unwind.c
Previous file: linux-2.4.21/arch/ia64/kernel/traps.c
Back to the patch index
Back to the overall index
- Lines: 197
- Date:
2003-06-13 07:51:29.000000000 -0700
- Orig file:
linux-2.4.20/arch/ia64/kernel/unaligned.c
- Orig date:
2002-11-28 15:53:09.000000000 -0800
diff -urN linux-2.4.20/arch/ia64/kernel/unaligned.c linux-2.4.21/arch/ia64/kernel/unaligned.c
@@ -5,6 +5,10 @@
* Stephane Eranian <eranian@hpl.hp.com>
* David Mosberger-Tang <davidm@hpl.hp.com>
*
+ * 2002/12/09 Fix rotating register handling (off-by-1 error, missing fr-rotation). Fix
+ * get_rse_reg() to not leak kernel bits to user-level (reading an out-of-frame
+ * stacked register returns an undefined value; it does NOT trigger a
+ * "rsvd register fault").
* 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.
@@ -275,6 +279,15 @@
# undef F
}
+static inline unsigned long
+rotate_reg (unsigned long sor, unsigned long rrb, unsigned long reg)
+{
+ reg += rrb;
+ if (reg >= sor)
+ reg -= sor;
+ return reg;
+}
+
static void
set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
{
@@ -286,26 +299,22 @@
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 ridx=%ld\n",
- r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
+ long ridx = r1 - 32;
- if ((r1 - 32) >= sof) {
+ if (ridx >= sof) {
/* this should never happen, as the "rsvd register fault" has higher priority */
DPRINT("ignoring write to r%lu; only %lu registers are allocated!\n", r1, sof);
return;
}
+ if (ridx < sor)
+ ridx = rotate_reg(sor, rrb_gr, ridx);
+
+ 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);
+
on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
- addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx);
+ addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + ridx);
if (addr >= kbs) {
/* the register is on the kernel backing store: easy... */
rnat_addr = ia64_rse_rnat_addr(addr);
@@ -333,7 +342,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, ridx + sof);
+ addr = ia64_rse_skip_regs(bsp, ridx);
DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
@@ -367,26 +376,22 @@
long sof = (regs->cr_ifs) & 0x7f;
long sor = 8 * ((regs->cr_ifs >> 14) & 0xf);
long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
- long ridx;
+ long ridx = r1 - 32;
- 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);
+ if (ridx >= sof) {
+ /* read of out-of-frame register returns an undefined value; 0 in our case. */
+ DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof);
+ goto fail;
+ }
+
+ if (ridx < sor)
+ ridx = rotate_reg(sor, rrb_gr, ridx);
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 */
- DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof);
- return;
- }
-
on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
- addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx);
+ addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + ridx);
if (addr >= kbs) {
/* the register is on the kernel backing store: easy... */
*val = *addr;
@@ -406,13 +411,13 @@
*/
if (regs->r12 >= TASK_SIZE) {
DPRINT("ignoring kernel read of r%lu; register isn't on the RBS!", r1);
- return;
+ goto fail;
}
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, ridx + sof);
+ addr = ia64_rse_skip_regs(bsp, ridx);
DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
@@ -427,6 +432,13 @@
ia64_peek(current, sw, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats);
*nat = (rnats & nat_mask) != 0;
}
+ return;
+
+ fail:
+ *val = 0;
+ if (nat)
+ *nat = 0;
+ return;
}
@@ -485,7 +497,16 @@
DPRINT("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat);
}
-#define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR)
+/*
+ * Return the (rotated) index for floating point register REGNUM (REGNUM must be in the
+ * range from 32-127, result is in the range from 0-95.
+ */
+static inline unsigned long
+fph_index (struct pt_regs *regs, long regnum)
+{
+ unsigned long rrb_fr = (regs->cr_ifs >> 25) & 0x7f;
+ return rotate_reg(96, rrb_fr, (regnum - IA64_FIRST_ROTATING_FR));
+}
static void
setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
@@ -506,7 +527,7 @@
*/
if (regnum >= IA64_FIRST_ROTATING_FR) {
ia64_sync_fph(current);
- current->thread.fph[IA64_FPH_OFFS(regnum)] = *fpval;
+ current->thread.fph[fph_index(regs, regnum)] = *fpval;
} else {
/*
* pt_regs or switch_stack ?
@@ -565,7 +586,7 @@
*/
if (regnum >= IA64_FIRST_ROTATING_FR) {
ia64_flush_fph(current);
- *fpval = current->thread.fph[IA64_FPH_OFFS(regnum)];
+ *fpval = current->thread.fph[fph_index(regs, regnum)];
} else {
/*
* f0 = 0.0, f1= 1.0. Those registers are constant and are thus
@@ -650,8 +671,8 @@
* just in case.
*/
if (ld.x6_op == 1 || ld.x6_op == 3) {
- printk("%s %s: register update on speculative load, error\n", KERN_ERR, __FUNCTION__);
- die_if_kernel("unaligned reference on specualtive load with register update\n",
+ printk(KERN_ERR "%s: register update on speculative load, error\n", __FUNCTION__);
+ die_if_kernel("unaligned reference on speculative load with register update\n",
regs, 30);
}
@@ -1080,8 +1101,8 @@
* For this reason we keep this sanity check
*/
if (ld.x6_op == 1 || ld.x6_op == 3)
- printk("%s %s: register update on speculative load pair, "
- "error\n",KERN_ERR, __FUNCTION__);
+ printk(KERN_ERR "%s: register update on speculative load pair, error\n",
+ __FUNCTION__);
setreg(ld.r3, ifa, 0, regs);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)