[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