[U-Boot] [PATCH] cmd_nand: add biterror insertion command for NAND Flash

Holger Brunck holger.brunck at keymile.com
Wed Jan 4 16:32:03 CET 2012


From: Stefan Bigler <stefan.bigler at keymile.com>

Initial implementation for unsafe feature for biterror insertion on
NAND-Flash devices. The code flips single bits in the data block of the
flash to simulate single bit-errors.
Tested with Samsung K9F1G08U0D and Micron MT29F1G08ABADAWP on
km_kirkwood boards.

Signed-off-by: Stefan Bigler <stefan.bigler at keymile.com>
Cc: Holger Brunck <holger.brunck at keymile.com>
Cc: Valentin Longchamp <valentin.longchamp at keymile.com>
Cc: Scott Wood <scottwood at freescale.com>
---
 common/cmd_nand.c |  131 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 128 insertions(+), 3 deletions(-)

diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 3e2edb8..3873d6f 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -96,6 +96,125 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat)
 	return 0;
 }
 
+#define MAX_WRITE_BLOCKS 64
+
+static int nand_biterror(nand_info_t *nand, ulong off, int bit)
+{
+	int ret = 0;
+	int block = 0;
+	ulong  block_off;
+	u_char * datbuf[MAX_WRITE_BLOCKS]; /* contains data and obb */
+	u_char * oobbuf[MAX_WRITE_BLOCKS]; /* not used */
+	u_char data;
+	int nbr_write_blocks = nand->erasesize / nand->writesize;
+	struct erase_info einfo;
+
+	if (nbr_write_blocks > MAX_WRITE_BLOCKS) {
+		puts("to many write blocks in one erase block\n");
+		return 1;
+	}
+
+	if ((bit < 0) || (bit > 7)) {
+		puts("bit position 0 to 7 is allowed\n");
+		return 1;
+	}
+
+	/* allocate memory */
+	memset(datbuf, 0, sizeof(datbuf));
+	memset(oobbuf, 0, sizeof(oobbuf));
+
+	for (block = 0; block < nbr_write_blocks; block++) {
+		datbuf[block] = malloc(nand->writesize + nand->oobsize);
+		oobbuf[block] = malloc(nand->oobsize);
+		if (!datbuf[block] || !oobbuf[block]) {
+			puts("No memory for page buffer\n");
+			ret = 1;
+			goto free_memory;
+		}
+	}
+
+	/* read out memory as first step */
+	block_off = off & (~(nand->erasesize - 1));
+	/* allign to eraseable block boundary */
+	for (block = 0; block < nbr_write_blocks; block++) {
+		struct mtd_oob_ops ops;
+
+		loff_t addr = (loff_t) block_off;
+		memset(&ops, 0, sizeof(ops));
+		ops.datbuf = datbuf[block];
+		ops.oobbuf = oobbuf[block];
+		/* must exist, but oob data will be appended to ops.datbuf */
+		ops.len = nand->writesize;
+		ops.ooblen = nand->oobsize;
+		ops.mode = MTD_OOB_RAW;
+		ret = nand->read_oob(nand, addr, &ops);
+		if (ret < 0) {
+			printf("Error (%d) reading page %08lx\n",
+				ret, block_off);
+			ret = 1;
+			goto free_memory;
+		}
+		block_off += nand->writesize;
+	}
+
+	/* second step erase the block */
+	memset(&einfo, 0, sizeof(einfo));
+	einfo.mtd = nand;
+	/* allign to eraseable block boundry */
+	einfo.addr = (loff_t) (off & (~(nand->erasesize - 1)));
+	einfo.len = nand->erasesize;
+	ret = nand_erase_nand(nand, &einfo, 1);
+
+	if (ret < 0) {
+		printf("Error (%d) nand_erase_nand page %08llx\n",
+			ret, einfo.addr);
+		ret = 1;
+		goto free_memory;
+	}
+
+	/* third step twist a bit in data part */
+	/* offset in the erasable block */
+	block_off = off & (nand->erasesize - 1);
+	data = datbuf[block_off/nand->writesize][block_off%nand->writesize];
+	data ^= (1 << bit);
+	datbuf[block_off/nand->writesize][block_off%nand->writesize] = data;
+
+	printf("Flip data at 0x%lx with xor 0x%02x (bit=%d) to value=0x%02x\n",
+		off, (1 << bit), bit, data);
+
+	/* write back twisted data and unmodified obb */
+	/* allign to eraseable block boundry */
+	block_off = off & (~(nand->erasesize - 1));
+	for (block = 0; block < nbr_write_blocks; block++) {
+		struct mtd_oob_ops ops;
+
+		loff_t addr = (loff_t) block_off;
+		memset(&ops, 0, sizeof(ops));
+		ops.datbuf = datbuf[block];
+		ops.oobbuf = &datbuf[block][nand->writesize];
+		ops.len = nand->writesize;
+		ops.ooblen = nand->oobsize;
+		ops.mode = MTD_OOB_RAW;
+		ret = nand->write_oob(nand, addr, &ops);
+
+		if (ret < 0) {
+			printf("Error (%d) write page %08lx\n", ret, block_off);
+			ret = 1;
+			goto free_memory;
+		}
+		block_off += nand->writesize;
+	}
+
+free_memory:
+	for (block = 0; block < nbr_write_blocks; block++) {
+		if (datbuf[block])
+			free(datbuf[block]);
+		if (oobbuf[block])
+			free(oobbuf[block]);
+	}
+	return ret;
+}
+
 /* ------------------------------------------------------------------------- */
 
 static int set_dev(int dev)
@@ -676,8 +795,14 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 	}
 
 	if (strcmp(cmd, "biterr") == 0) {
-		/* todo */
-		return 1;
+		int bit;
+		if (argc == 4) {
+			off = (int)simple_strtoul(argv[2], NULL, 16);
+			bit = (int)simple_strtoul(argv[3], NULL, 10);
+			ret = nand_biterror(nand, off, bit);
+			return ret;
+		} else
+			goto usage;
 	}
 
 #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
@@ -756,7 +881,7 @@ U_BOOT_CMD(
 	"nand scrub [-y] off size | scrub.part partition | scrub.chip\n"
 	"    really clean NAND erasing bad blocks (UNSAFE)\n"
 	"nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n"
-	"nand biterr off - make a bit error at offset (UNSAFE)"
+	"nand biterr off bit - make a bit error at offset and bit position (UNSAFE)"
 #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
 	"\n"
 	"nand lock [tight] [status]\n"
-- 
1.7.1



More information about the U-Boot mailing list