diff options
author | Baruch Siach <baruch@tkos.co.il> | 2010-10-18 02:36:34 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-10-18 02:36:34 +0200 |
commit | 36af2f7977edc818af8c01392ef700439a9fe163 (patch) | |
tree | 37c43ec830c9c961c76e49bd710e02b3b238eb2c /miscutils | |
parent | 873bb31d1703aae080d1928b5928c0011a944485 (diff) | |
download | busybox-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.c | 155 |
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 */ | ||
65 | static 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 | |||
33 | static unsigned next_good_eraseblock(int fd, struct mtd_info_user *meminfo, | 81 | static 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, | |||
49 | int nandwrite_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 102 | int nandwrite_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
50 | int nandwrite_main(int argc UNUSED_PARAM, char **argv) | 103 | int 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 */ |