]> git.hungrycats.org Git - linux/commitdiff
[PATCH] ia64: fix ld.a emulation
authorKenneth W. Chen <kenneth.w.chen@intel.com>
Tue, 10 Feb 2004 04:55:53 +0000 (20:55 -0800)
committerDavid Mosberger <davidm@tiger.hpl.hp.com>
Tue, 10 Feb 2004 04:55:53 +0000 (20:55 -0800)
This patch fixes a corner-case of ld.a emulation.  ld.a should be
emulated such that it always loads a misaligned value and clears the
corresponding ALAT entry.  The old emulation was correct for the case
where ld.a was followed by ld.c/chk.a (since ALAT entry was cleared),
but wrong for the case where it _wasn't_ followed by ld.c/chk.a.  In
that case, the misaligned value wasn't read from memory, as it should
have been.

arch/ia64/kernel/unaligned.c

index 6cb14f493cd9f05f74ef953564063e8f9f1b82ff..81b57c063be85ef6b7ce18e07a2a1dd363d0c1cc 100644 (file)
@@ -740,6 +740,7 @@ static int
 emulate_load_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
 {
        unsigned int len = 1 << ld.x6_sz;
+       unsigned long val = 0;
 
        /*
         * r0, as target, doesn't need to be checked because Illegal Instruction
@@ -750,21 +751,18 @@ emulate_load_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
         */
 
        /*
-        * ldX.a we don't try to emulate anything but we must invalidate the ALAT entry.
+        * ldX.a we will emulate load and also invalidate the ALAT entry.
         * See comment below for explanation on how we handle ldX.a
         */
-       if (ld.x6_op != 0x2) {
-               unsigned long val = 0;
 
-               if (len != 2 && len != 4 && len != 8) {
-                       DPRINT("unknown size: x6=%d\n", ld.x6_sz);
-                       return -1;
-               }
-               /* this assumes little-endian byte-order: */
-               if (copy_from_user(&val, (void *) ifa, len))
-                   return -1;
-               setreg(ld.r1, val, 0, regs);
+       if (len != 2 && len != 4 && len != 8) {
+               DPRINT("unknown size: x6=%d\n", ld.x6_sz);
+               return -1;
        }
+       /* this assumes little-endian byte-order: */
+       if (copy_from_user(&val, (void *) ifa, len))
+               return -1;
+       setreg(ld.r1, val, 0, regs);
 
        /*
         * check for updates on any kind of loads
@@ -817,7 +815,7 @@ emulate_load_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
         *              store & shift to temporary;
         *              r1=temporary
         *
-        *        So int this case, you would get the right value is r1 but the wrong info in
+        *        So in this case, you would get the right value is r1 but the wrong info in
         *        the ALAT.  Notice that you could do it in reverse to finish with address 3
         *        but you would still get the size wrong.  To get the size right, one needs to
         *        execute exactly the same kind of load. You could do it from a aligned
@@ -826,9 +824,12 @@ emulate_load_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
         *        So no matter what, it is not possible to emulate an advanced load
         *        correctly. But is that really critical ?
         *
+        *        We will always convert ld.a into a normal load with ALAT invalidated.  This
+        *        will enable compiler to do optimization where certain code path after ld.a
+        *        is not required to have ld.c/chk.a, e.g., code path with no intervening stores.
         *
-        *        Now one has to look at how ld.a is used, one must either do a ld.c.* or
-        *        chck.a.* to reuse the value stored in the ALAT. Both can "fail" (meaning no
+        *        If there is a store after the advanced load, one must either do a ld.c.* or
+        *        chk.a.* to reuse the value stored in the ALAT. Both can "fail" (meaning no
         *        entry found in ALAT), and that's perfectly ok because:
         *
         *              - ld.c.*, if the entry is not present a  normal load is executed
@@ -836,19 +837,8 @@ emulate_load_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
         *
         *        In either case, the load can be potentially retried in another form.
         *
-        *        So it's okay NOT to do any actual load on an unaligned ld.a. However the ALAT
-        *        must be invalidated for the register (so that's chck.a.*,ld.c.* don't pick up
-        *        a stale entry later) The register base update MUST also be performed.
-        *
-        *        Now what is the content of the register and its NaT bit in the case we don't
-        *        do the load ?  EAS2.4, says (in case an actual load is needed)
-        *
-        *              - r1 = [r3], Nat = 0 if succeeds
-        *              - r1 = 0 Nat = 0 if trying to access non-speculative memory
-        *
-        *        For us, there is nothing to do, because both ld.c.* and chk.a.* are going to
-        *        retry and thus eventually reload the register thereby changing Nat and
-        *        register content.
+        *        ALAT must be invalidated for the register (so that chk.a or ld.c don't pick
+        *        up a stale entry later). The register base update MUST also be performed.
         */
 
        /*