diff mbox series

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

Message ID 20180710195915.1856-1-zajec5@gmail.com
State Superseded
Delegated to: Rafał Miłecki
Headers show
Series [OpenWrt-Devel] mtd: support bad blocks within the mtd_fixtrx() | expand

Commit Message

Rafał Miłecki July 10, 2018, 7:59 p.m. UTC
From: Rafał Miłecki <rafal@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@milecki.pl>
---
 package/system/mtd/src/trx.c | 40 ++++++++++++++++++++++++++++++++++------
 1 file changed, 34 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/package/system/mtd/src/trx.c b/package/system/mtd/src/trx.c
index 1f5c52914c..305efc5dd5 100644
--- a/package/system/mtd/src/trx.c
+++ b/package/system/mtd/src/trx.c
@@ -156,9 +156,10 @@  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;
+	size_t read_offset, read_size;
 
 	if (quiet < 2)
 		fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset);
@@ -214,10 +215,38 @@  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);
+	read_offset = data_offset;
+	read_size = data_size;
+	to = buf;
+	while (read_size) {
+		size_t read_block_offset = read_offset & ~(erasesize - 1);
+		size_t read_chunk;
+
+		read_chunk = erasesize - (read_offset & (erasesize - 1));
+		read_chunk = read_chunk > read_size ? read_size : read_chunk;
+
+		res = ioctl(fd, MEMGETBADBLOCK, &read_block_offset);
+		if (res == -1) {
+			perror("ioctl");
+			exit(1);
+		}
+
+		/* Skip bad block to match CFE behavior */
+		if (res) {
+			read_offset += read_chunk;
+			read_size -= read_chunk;
+			continue;
+		}
+
+		res = pread(fd, to, read_chunk, read_offset);
+		if (res != read_chunk) {
+			perror("pread");
+			exit(1);
+		}
+
+		read_offset += read_chunk;
+		read_size -= read_chunk;
+		to += read_chunk;
 	}
 
 	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;
 
 }
-