mtd: map: fixed bug in 64-bit systems

Message ID 001f01ce9340$8880b750$998225f0$
State New, archived
Headers show

Commit Message

Wang Haitao Aug. 7, 2013, 7:34 a.m.
         CPU:XLP832,the 64-bit OS
         NOR Flash:S29GL128S 128M

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 <>
Signed-off-by: Zhang Yi <>
Signed-off-by:Lu Zhongjun <>
Reviewed-by: Jiang Biao <>
Tested-by: Ma Chenggong <>

        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.


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)