[OpenWrt-Devel] [PATCH V2] mtd: support bad blocks within the mtd_fixtrx()

Rafał Miłecki zajec5 at gmail.com
Wed Jul 11 04:52:34 EDT 2018


From: Rafał Miłecki <rafal at milecki.pl>

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 at milecki.pl>
---
V2: Bump PKG_RELEASE
    Use min() to make code easier to understand
    Recalculate data_size to make sure old size value (including bad
    blocks) isn't used.
    Drop some unneeded helper variables.
---
 package/system/mtd/Makefile  |  2 +-
 package/system/mtd/src/trx.c | 40 ++++++++++++++++++++++++++++++++++------
 2 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/package/system/mtd/Makefile b/package/system/mtd/Makefile
index 9ae03a77a9..969e1c711c 100644
--- a/package/system/mtd/Makefile
+++ b/package/system/mtd/Makefile
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 include $(INCLUDE_DIR)/kernel.mk
 
 PKG_NAME:=mtd
-PKG_RELEASE:=21
+PKG_RELEASE:=22
 
 PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)
 STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)
diff --git a/package/system/mtd/src/trx.c b/package/system/mtd/src/trx.c
index 1f5c52914c..d4d486c32b 100644
--- a/package/system/mtd/src/trx.c
+++ b/package/system/mtd/src/trx.c
@@ -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,34 @@ 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);
+
+		res = ioctl(fd, MEMGETBADBLOCK, &read_block_offset);
+		if (res == -1) {
+			perror("ioctl");
+			exit(1);
+		}
+
+		/* Read from good blocks only to match CFE behavior */
+		if (res == 0) {
+			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 +273,3 @@ mtd_fixtrx(const char *mtd, size_t offset, size_t data_size)
 	return 0;
 
 }
-
-- 
2.13.7


_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel


More information about the openwrt-devel mailing list