[PATCH]mtd: map: fixed bug in 64-bit systems

Wang Haitao wang.haitao1 at zte.com.cn
Wed Aug 7 03:34:20 EDT 2013


Hardware:
         CPU:XLP832,the 64-bit OS
         NOR Flash:S29GL128S 128M
Software:
         Kernel:2.6.32.41
         Filesystem:JFFS2

When writing files, errors appear:
         Write len 182  but return retlen 180 
         Write of 182 bytes at 0x072c815c failed. returned -5, retlen 180
         Write len 186  but return retlen 184 
         Write of 186 bytes at 0x072caff4 failed. returned -5, retlen 184 
These errors exist only in 64-bit systems,not in 32-bit systems. After analysis, we found that the left shift operation is wrong in map_word_load_partial. For instance:
         unsigned char buf[3] ={0x9e,0x3a,0xea};
         map_bankwidth(map) is 4;

         for (i=0; i < 3; i++) {
                   int bitpos;
                   bitpos = (map_bankwidth(map)-1-i)*8;
                   orig.x[0] &= ~(0xff << bitpos);
                   orig.x[0] |= buf[i] << bitpos;
         }

The value of orig.x[0] is expected to be 0x9e3aeaff, but in this situation(64-bit System) we'll get the wrong value of 0xffffffff9e3aeaff due to the 64-bit sign extension: 
buf[i] is defined as "unsigned char" and the left-shift operation will convert it to the type of "signed int", so when left-shift buf[i] by 24 bits, the final result will get the wrong value: 0xffffffff9e3aeaff.

If the left-shift bits are less than 24, then sign extension will not occur. Whereas the bankwidth of the nor flash we used is 4, therefore this BUG emerges.

Signed-off-by:Pang Xunlei <pang.xunlei at zte.com.cn>
Signed-off-by: Zhang Yi <zhang.yi20 at zte.com.cn>
Signed-off-by:Lu Zhongjun <lu.zhongjun at zte.com.cn>
Reviewed-by: Jiang Biao <jiang.biao2 at zte.com.cn>
Tested-by: Ma Chenggong <ma.chenggong at zte.com.cn>

diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
index aa30244..18ee717
--- a/include/linux/mtd/map.h
+++ b/include/linux/mtd/map.h
@@ -342,7 +342,7 @@ static inline map_word map_word_load_partial(struct map_info *map, map_word orig
                          bitpos = (map_bankwidth(map)-1-i)*8;  #endif
                            orig.x[0] &= ~(0xff << bitpos);
-                           orig.x[0] |= buf[i-start] << bitpos;
+                          orig.x[0] |= (unsigned long)buf[i-start] << bitpos;
                 }
       }
       return orig;
@@ -361,7 +361,7 @@ static inline map_word map_word_ff(struct map_info *map)

        if (map_bankwidth(map) < MAP_FF_LIMIT) {

                   int bw = 8 * map_bankwidth(map);
-                 r.x[0] = (1 << bw) - 1;
+                r.x[0] = (1UL << bw) - 1;
       } else {
                 for (i=0; i<map_words(map); i++)
                          r.x[i] = ~0UL;


--------------------------------------------------------
ZTE Information Security Notice: The information contained in this mail (and any attachment transmitted herewith) is privileged and confidential and is intended for the exclusive use of the addressee(s).  If you are not an intended recipient, any disclosure, reproduction, distribution or other dissemination or use of the information contained is strictly prohibited.  If you have received this mail in error, please delete it and notify us immediately.



More information about the linux-mtd mailing list