aboutsummaryrefslogtreecommitdiff
path: root/miscutils
diff options
context:
space:
mode:
authorBaruch Siach <baruch@tkos.co.il>2010-10-18 02:36:34 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2010-10-18 02:36:34 +0200
commit36af2f7977edc818af8c01392ef700439a9fe163 (patch)
tree37c43ec830c9c961c76e49bd710e02b3b238eb2c /miscutils
parent873bb31d1703aae080d1928b5928c0011a944485 (diff)
downloadbusybox-w32-36af2f7977edc818af8c01392ef700439a9fe163.tar.gz
busybox-w32-36af2f7977edc818af8c01392ef700439a9fe163.tar.bz2
busybox-w32-36af2f7977edc818af8c01392ef700439a9fe163.zip
nanddump: new applet
function old new delta nandwrite_main 418 936 +518 dump_bad - 119 +119 packed_usage 27752 27810 +58 next_good_eraseblock 84 106 +22 applet_names 2366 2375 +9 applet_main 1380 1384 +4 applet_nameofs 690 692 +2 bbconfig_config_bz2 4932 4922 -10 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 6/1 up/down: 732/-10) Total: 722 bytes Signed-off-by: Baruch Siach <baruch@tkos.co.il> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'miscutils')
-rw-r--r--miscutils/nandwrite.c155
1 files changed, 127 insertions, 28 deletions
diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c
index f42242687..6c85ea346 100644
--- a/miscutils/nandwrite.c
+++ b/miscutils/nandwrite.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * nandwrite.c - ported to busybox from mtd-utils 2 * nandwrite and nanddump ported to busybox from mtd-utils
3 * 3 *
4 * Author: Baruch Siach <baruch@tkos.co.il>, Orex Computed Radiography 4 * Author: Baruch Siach <baruch@tkos.co.il>, Orex Computed Radiography
5 * 5 *
@@ -9,8 +9,10 @@
9 */ 9 */
10 10
11//applet:IF_NANDWRITE(APPLET(nandwrite, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 11//applet:IF_NANDWRITE(APPLET(nandwrite, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
12//applet:IF_NANDWRITE(APPLET_ODDNAME(nanddump, nandwrite, _BB_DIR_USR_SBIN, _BB_SUID_DROP, nanddump))
12 13
13//kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o 14//kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o
15//kbuild:lib-$(CONFIG_NANDDUMP) += nandwrite.o
14 16
15//config:config NANDWRITE 17//config:config NANDWRITE
16//config: bool "nandwrite" 18//config: bool "nandwrite"
@@ -18,9 +20,13 @@
18//config: depends on PLATFORM_LINUX 20//config: depends on PLATFORM_LINUX
19//config: help 21//config: help
20//config: Write to the specified MTD device, with bad blocks awareness 22//config: Write to the specified MTD device, with bad blocks awareness
21 23//config:
22#include "libbb.h" 24//config:config NANDDUMP
23#include <mtd/mtd-user.h> 25//config: bool "nanddump"
26//config: default n
27//config: depends on PLATFORM_LINUX
28//config: help
29//config: Dump the content of raw NAND chip
24 30
25//usage:#define nandwrite_trivial_usage 31//usage:#define nandwrite_trivial_usage
26//usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]" 32//usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]"
@@ -30,18 +36,65 @@
30//usage: "\n -p Pad to page size" 36//usage: "\n -p Pad to page size"
31//usage: "\n -s ADDR Start address" 37//usage: "\n -s ADDR Start address"
32 38
39//usage:#define nanddump_trivial_usage
40//usage: "[-o] [-b] [-s ADDR] [-f FILE] MTD_DEVICE"
41//usage:#define nanddump_full_usage "\n\n"
42//usage: "Dump the sepcified MTD device\n"
43//usage: "\nOptions:"
44//usage: "\n -o Omit oob data"
45//usage: "\n -b Omit bad block from the dump"
46//usage: "\n -s ADDR Start address"
47//usage: "\n -l LEN Length"
48//usage: "\n -f FILE Dump to file ('-' for stdout)"
49
50#include "libbb.h"
51#include <mtd/mtd-user.h>
52
53#define IS_NANDDUMP (ENABLE_NANDDUMP && (!ENABLE_NANDWRITE || (applet_name[4] == 'd')))
54#define IS_NANDWRITE (ENABLE_NANDWRITE && (!ENABLE_NANDDUMP || (applet_name[4] != 'd')))
55
56#define OPT_p (1 << 0) /* nandwrite only */
57#define OPT_o (1 << 0) /* nanddump only */
58#define OPT_s (1 << 1)
59#define OPT_b (1 << 2)
60#define OPT_f (1 << 3)
61#define OPT_l (1 << 4)
62
63#define NAND_MAX_OOBSIZE 256
64/* helper for writing out 0xff for bad blocks pad */
65static void dump_bad(struct mtd_info_user *meminfo, unsigned len, int oob)
66{
67 unsigned char buf[meminfo->writesize];
68 unsigned count;
69
70 /* round len to the next page */
71 len = (len | ~(meminfo->writesize - 1)) + 1;
72
73 memset(buf, 0xff, sizeof(buf));
74 for (count = 0; count < len; count += meminfo->writesize) {
75 xwrite(STDOUT_FILENO, buf, meminfo->writesize);
76 if (oob)
77 xwrite(STDOUT_FILENO, buf, meminfo->oobsize);
78 }
79}
80
33static unsigned next_good_eraseblock(int fd, struct mtd_info_user *meminfo, 81static unsigned next_good_eraseblock(int fd, struct mtd_info_user *meminfo,
34 unsigned block_offset) 82 unsigned block_offset)
35{ 83{
36 while (1) { 84 while (1) {
37 loff_t offs; 85 loff_t offs;
38 if (block_offset >= meminfo->size) 86
39 bb_error_msg_and_die("not enough space in MTD device"); 87 if (block_offset >= meminfo->size) {
88 if (IS_NANDWRITE)
89 bb_error_msg_and_die("not enough space in MTD device");
90 return block_offset; /* let the caller exit */
91 }
40 offs = block_offset; 92 offs = block_offset;
41 if (xioctl(fd, MEMGETBADBLOCK, &offs) == 0) 93 if (xioctl(fd, MEMGETBADBLOCK, &offs) == 0)
42 return block_offset; 94 return block_offset;
43 /* ioctl returned 1 => "bad block" */ 95 /* ioctl returned 1 => "bad block" */
44 printf("Skipping bad block at 0x%08x\n", block_offset); 96 if (IS_NANDWRITE)
97 printf("Skipping bad block at 0x%08x\n", block_offset);
45 block_offset += meminfo->erasesize; 98 block_offset += meminfo->erasesize;
46 } 99 }
47} 100}
@@ -49,31 +102,49 @@ static unsigned next_good_eraseblock(int fd, struct mtd_info_user *meminfo,
49int nandwrite_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 102int nandwrite_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
50int nandwrite_main(int argc UNUSED_PARAM, char **argv) 103int nandwrite_main(int argc UNUSED_PARAM, char **argv)
51{ 104{
105 /* Buffer for OOB data */
106 unsigned char oobbuf[NAND_MAX_OOBSIZE];
52 unsigned opts; 107 unsigned opts;
53 int fd; 108 int fd;
54 ssize_t cnt; 109 ssize_t cnt;
55 unsigned mtdoffset, meminfo_writesize, blockstart; 110 unsigned mtdoffset, meminfo_writesize, blockstart, limit;
111 unsigned end_addr = ~0;
56 struct mtd_info_user meminfo; 112 struct mtd_info_user meminfo;
113 struct mtd_oob_buf oob;
57 unsigned char *filebuf; 114 unsigned char *filebuf;
58 const char *opt_s = "0"; 115 const char *opt_s = "0", *opt_f = "-", *opt_l;
59 enum { 116
60 OPT_p = (1 << 0), 117 if (IS_NANDDUMP) {
61 OPT_s = (1 << 1), 118 opt_complementary = "=1";
62 }; 119 opts = getopt32(argv, "os:bf:l:", &opt_s, &opt_f, &opt_l);
63 120 } else { /* nandwrite */
64 opt_complementary = "-1:?2"; 121 opt_complementary = "-1:?2";
65 opts = getopt32(argv, "ps:", &opt_s); 122 opts = getopt32(argv, "ps:", &opt_s);
123 }
66 argv += optind; 124 argv += optind;
67 125
68 if (argv[1]) 126 if (IS_NANDWRITE && argv[1])
69 xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO); 127 opt_f = argv[1];
128 if (!LONE_DASH(opt_f)) {
129 int tmp_fd = xopen(opt_f,
130 IS_NANDDUMP ? O_WRONLY | O_TRUNC | O_CREAT : O_RDONLY
131 );
132 xmove_fd(tmp_fd, IS_NANDDUMP ? STDOUT_FILENO : STDIN_FILENO);
133 }
70 134
71 fd = xopen(argv[0], O_RDWR); 135 fd = xopen(argv[0], O_RDWR);
72 xioctl(fd, MEMGETINFO, &meminfo); 136 xioctl(fd, MEMGETINFO, &meminfo);
73 137
74 mtdoffset = bb_strtou(opt_s, NULL, 0); 138 oob.start = 0;
75 if (errno) 139 oob.length = meminfo.oobsize;
76 bb_error_msg_and_die("invalid number '%s'", opt_s); 140 oob.ptr = oobbuf;
141
142 mtdoffset = xstrtou(opt_s, 0);
143 if (IS_NANDDUMP && (opts & OPT_l)) {
144 unsigned length = xstrtou(opt_l, 0);
145 if (length < meminfo.size - mtdoffset)
146 end_addr = mtdoffset + length;
147 }
77 148
78 /* Pull it into a CPU register (hopefully) - smaller code that way */ 149 /* Pull it into a CPU register (hopefully) - smaller code that way */
79 meminfo_writesize = meminfo.writesize; 150 meminfo_writesize = meminfo.writesize;
@@ -91,20 +162,39 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv)
91 * bad. 162 * bad.
92 */ 163 */
93 tmp = next_good_eraseblock(fd, &meminfo, blockstart); 164 tmp = next_good_eraseblock(fd, &meminfo, blockstart);
94 if (tmp != blockstart) /* bad block(s), advance mtdoffset */ 165 if (tmp != blockstart) {
166 /* bad block(s), advance mtdoffset */
167 if (IS_NANDDUMP & !(opts & OPT_b)) {
168 int bad_len = MIN(tmp, end_addr) - mtdoffset;
169 dump_bad(&meminfo, bad_len, !(opts & OPT_o));
170 }
95 mtdoffset = tmp; 171 mtdoffset = tmp;
172 }
96 } 173 }
97 174
98 cnt = -1; 175 cnt = -1;
99 while (mtdoffset < meminfo.size) { 176 limit = MIN(meminfo.size, end_addr);
177 while (mtdoffset < limit) {
178 int input_fd = IS_NANDWRITE ? STDIN_FILENO : fd;
179 int output_fd = IS_NANDWRITE ? fd : STDOUT_FILENO;
180
100 blockstart = mtdoffset & ~(meminfo.erasesize - 1); 181 blockstart = mtdoffset & ~(meminfo.erasesize - 1);
101 if (blockstart == mtdoffset) { 182 if (blockstart == mtdoffset) {
102 /* starting a new eraseblock */ 183 /* starting a new eraseblock */
103 mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart); 184 mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart);
104 printf("Writing at 0x%08x\n", mtdoffset); 185 if (IS_NANDWRITE)
186 printf("Writing at 0x%08x\n", mtdoffset);
187 else if (mtdoffset > blockstart) {
188 int bad_len = MIN(mtdoffset, limit) - blockstart;
189 dump_bad(&meminfo, bad_len, !(opts & OPT_o));
190 }
191 if (mtdoffset >= limit)
192 break;
105 } 193 }
194 xlseek(fd, mtdoffset, SEEK_SET);
195
106 /* get some more data from input */ 196 /* get some more data from input */
107 cnt = full_read(STDIN_FILENO, filebuf, meminfo_writesize); 197 cnt = full_read(input_fd, filebuf, meminfo_writesize);
108 if (cnt == 0) { 198 if (cnt == 0) {
109 /* even with -p, we do not pad past the end of input 199 /* even with -p, we do not pad past the end of input
110 * (-p only zero-pads last incomplete page) 200 * (-p only zero-pads last incomplete page)
@@ -112,20 +202,29 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv)
112 break; 202 break;
113 } 203 }
114 if (cnt < meminfo_writesize) { 204 if (cnt < meminfo_writesize) {
205 if (IS_NANDDUMP)
206 bb_error_msg_and_die("short read");
115 if (!(opts & OPT_p)) 207 if (!(opts & OPT_p))
116 bb_error_msg_and_die("input size is not rounded up to page size, " 208 bb_error_msg_and_die("input size is not rounded up to page size, "
117 "use -p to zero pad"); 209 "use -p to zero pad");
118 /* zero pad to end of write block */ 210 /* zero pad to end of write block */
119 memset(filebuf + cnt, 0, meminfo_writesize - cnt); 211 memset(filebuf + cnt, 0, meminfo_writesize - cnt);
120 } 212 }
121 xlseek(fd, mtdoffset, SEEK_SET); 213 xwrite(output_fd, filebuf, meminfo_writesize);
122 xwrite(fd, filebuf, meminfo_writesize); 214
215 if (IS_NANDDUMP && !(opts & OPT_o)) {
216 /* Dump OOB data */
217 oob.start = mtdoffset;
218 xioctl(fd, MEMREADOOB, &oob);
219 xwrite(output_fd, oobbuf, meminfo.oobsize);
220 }
221
123 mtdoffset += meminfo_writesize; 222 mtdoffset += meminfo_writesize;
124 if (cnt < meminfo_writesize) 223 if (cnt < meminfo_writesize)
125 break; 224 break;
126 } 225 }
127 226
128 if (cnt != 0) { 227 if (IS_NANDWRITE && cnt != 0) {
129 /* We filled entire MTD, but did we reach EOF on input? */ 228 /* We filled entire MTD, but did we reach EOF on input? */
130 if (full_read(STDIN_FILENO, filebuf, meminfo_writesize) != 0) { 229 if (full_read(STDIN_FILENO, filebuf, meminfo_writesize) != 0) {
131 /* no */ 230 /* no */