mtd: support bad blocks within the mtd_fixtrx()
authorRafał Miłecki <rafal@milecki.pl>
Sun, 15 Jul 2018 14:51:41 +0000 (16:51 +0200)
committerRafał Miłecki <rafal@milecki.pl>
Tue, 17 Jul 2018 05:17:37 +0000 (07:17 +0200)
Reading MTD data with (p)read doesn't return any error when accessing
bad block. As the result, with current code, CRC32 covers "data" stored
in bad blocks.

That behavior doesn't match CFE's one (bootloader simply skips bad
blocks) and may result in:
1) Invalid CRC32
2) CFE refusing to boot firmware with a following error:
Boot program checksum is invalid

Fix that problem by checking every block before reading its content.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
(cherry picked from commit 0f54489f754e7bd34e0430c57a11b6a54740d58e)

package/system/mtd/Makefile
package/system/mtd/src/trx.c

index ecb440061ec660b35d48dbc0a59f7ed4a1477f7b..5d1538ea95ff0882326717cbbe6d2c6948f63b5a 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 include $(INCLUDE_DIR)/kernel.mk
 
 PKG_NAME:=mtd
-PKG_RELEASE:=21$(if $(SDK),,.1)
+PKG_RELEASE:=22$(if $(SDK),,.1)
 
 PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)
 STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
index 1f5c52914c453786dde689ac3a1a01bead30982a..c1296a5f707a3feea138fabf5ba231d4d86f7048 100644 (file)
@@ -46,6 +46,12 @@ struct trx_header {
        uint32_t offsets[3];    /* Offsets of partitions from start of header */
 };
 
+#define min(x,y) ({            \
+       typeof(x) _x = (x);     \
+       typeof(y) _y = (y);     \
+       (void) (&_x == &_y);    \
+       _x < _y ? _x : _y; })
+
 #if __BYTE_ORDER == __BIG_ENDIAN
 #define STORE32_LE(X)           ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
 #elif __BYTE_ORDER == __LITTLE_ENDIAN
@@ -156,7 +162,7 @@ mtd_fixtrx(const char *mtd, size_t offset, size_t data_size)
        int fd;
        struct trx_header *trx;
        char *first_block;
-       char *buf;
+       char *buf, *to;
        ssize_t res;
        size_t block_offset;
 
@@ -214,11 +220,28 @@ mtd_fixtrx(const char *mtd, size_t offset, size_t data_size)
                exit(1);
        }
 
-       res = pread(fd, buf, data_size, data_offset);
-       if (res != data_size) {
-               perror("pread");
-               exit(1);
+       to = buf;
+       while (data_size) {
+               size_t read_block_offset = data_offset & ~(erasesize - 1);
+               size_t read_chunk;
+
+               read_chunk = erasesize - (data_offset & (erasesize - 1));
+               read_chunk = min(read_chunk, data_size);
+
+               /* Read from good blocks only to match CFE behavior */
+               if (!mtd_block_is_bad(fd, read_block_offset)) {
+                       res = pread(fd, to, read_chunk, data_offset);
+                       if (res != read_chunk) {
+                               perror("pread");
+                               exit(1);
+                       }
+                       to += read_chunk;
+               }
+
+               data_offset += read_chunk;
+               data_size -= read_chunk;
        }
+       data_size = to - buf;
 
        trx->len = STORE32_LE(data_size + offsetof(struct trx_header, flag_version));
 
@@ -244,4 +267,3 @@ mtd_fixtrx(const char *mtd, size_t offset, size_t data_size)
        return 0;
 
 }
-