Fix for segfault in handle_nand_dump_command.
[openocd.git] / src / flash / nand / tcl.c
1 /***************************************************************************
2 * Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> *
3 * Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> *
4 * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
5 * *
6 * Partially based on drivers/mtd/nand_ids.c from Linux. *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "core.h"
28 #include "imp.h"
29 #include "fileio.h"
30
31 // to be removed
32 extern struct nand_device *nand_devices;
33
34 COMMAND_HANDLER(handle_nand_list_command)
35 {
36 struct nand_device *p;
37 int i;
38
39 if (!nand_devices)
40 {
41 command_print(CMD_CTX, "no NAND flash devices configured");
42 return ERROR_OK;
43 }
44
45 for (p = nand_devices, i = 0; p; p = p->next, i++)
46 {
47 if (p->device)
48 command_print(CMD_CTX, "#%i: %s (%s) "
49 "pagesize: %i, buswidth: %i,\n\t"
50 "blocksize: %i, blocks: %i",
51 i, p->device->name, p->manufacturer->name,
52 p->page_size, p->bus_width,
53 p->erase_size, p->num_blocks);
54 else
55 command_print(CMD_CTX, "#%i: not probed", i);
56 }
57
58 return ERROR_OK;
59 }
60
61 COMMAND_HANDLER(handle_nand_info_command)
62 {
63 int i = 0;
64 int j = 0;
65 int first = -1;
66 int last = -1;
67
68 switch (CMD_ARGC) {
69 default:
70 return ERROR_COMMAND_SYNTAX_ERROR;
71 case 1:
72 first = 0;
73 last = INT32_MAX;
74 break;
75 case 2:
76 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], i);
77 first = last = i;
78 i = 0;
79 break;
80 case 3:
81 COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first);
82 COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last);
83 break;
84 }
85
86 struct nand_device *p;
87 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
88 if (ERROR_OK != retval)
89 return retval;
90
91 if (NULL == p->device)
92 {
93 command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
94 return ERROR_OK;
95 }
96
97 if (first >= p->num_blocks)
98 first = p->num_blocks - 1;
99
100 if (last >= p->num_blocks)
101 last = p->num_blocks - 1;
102
103 command_print(CMD_CTX, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",
104 i++, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size);
105
106 for (j = first; j <= last; j++)
107 {
108 char *erase_state, *bad_state;
109
110 if (p->blocks[j].is_erased == 0)
111 erase_state = "not erased";
112 else if (p->blocks[j].is_erased == 1)
113 erase_state = "erased";
114 else
115 erase_state = "erase state unknown";
116
117 if (p->blocks[j].is_bad == 0)
118 bad_state = "";
119 else if (p->blocks[j].is_bad == 1)
120 bad_state = " (marked bad)";
121 else
122 bad_state = " (block condition unknown)";
123
124 command_print(CMD_CTX,
125 "\t#%i: 0x%8.8" PRIx32 " (%" PRId32 "kB) %s%s",
126 j,
127 p->blocks[j].offset,
128 p->blocks[j].size / 1024,
129 erase_state,
130 bad_state);
131 }
132
133 return ERROR_OK;
134 }
135
136 COMMAND_HANDLER(handle_nand_probe_command)
137 {
138 if (CMD_ARGC != 1)
139 {
140 return ERROR_COMMAND_SYNTAX_ERROR;
141 }
142
143 struct nand_device *p;
144 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
145 if (ERROR_OK != retval)
146 return retval;
147
148 if ((retval = nand_probe(p)) == ERROR_OK)
149 {
150 command_print(CMD_CTX, "NAND flash device '%s (%s)' found",
151 p->device->name, p->manufacturer->name);
152 }
153
154 return retval;
155 }
156
157 COMMAND_HANDLER(handle_nand_erase_command)
158 {
159 if (CMD_ARGC != 1 && CMD_ARGC != 3)
160 {
161 return ERROR_COMMAND_SYNTAX_ERROR;
162
163 }
164
165 struct nand_device *p;
166 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
167 if (ERROR_OK != retval)
168 return retval;
169
170 unsigned long offset;
171 unsigned long length;
172
173 /* erase specified part of the chip; or else everything */
174 if (CMD_ARGC == 3) {
175 unsigned long size = p->erase_size * p->num_blocks;
176
177 COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
178 if ((offset % p->erase_size) != 0 || offset >= size)
179 return ERROR_INVALID_ARGUMENTS;
180
181 COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
182 if ((length == 0) || (length % p->erase_size) != 0
183 || (length + offset) > size)
184 return ERROR_INVALID_ARGUMENTS;
185
186 offset /= p->erase_size;
187 length /= p->erase_size;
188 } else {
189 offset = 0;
190 length = p->num_blocks;
191 }
192
193 retval = nand_erase(p, offset, offset + length - 1);
194 if (retval == ERROR_OK)
195 {
196 command_print(CMD_CTX, "erased blocks %lu to %lu "
197 "on NAND flash device #%s '%s'",
198 offset, offset + length,
199 CMD_ARGV[0], p->device->name);
200 }
201
202 return retval;
203 }
204
205 COMMAND_HANDLER(handle_nand_check_bad_blocks_command)
206 {
207 int first = -1;
208 int last = -1;
209
210 if ((CMD_ARGC < 1) || (CMD_ARGC > 3) || (CMD_ARGC == 2))
211 {
212 return ERROR_COMMAND_SYNTAX_ERROR;
213
214 }
215
216 struct nand_device *p;
217 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
218 if (ERROR_OK != retval)
219 return retval;
220
221 if (CMD_ARGC == 3)
222 {
223 unsigned long offset;
224 unsigned long length;
225
226 COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
227 if (offset % p->erase_size)
228 return ERROR_INVALID_ARGUMENTS;
229 offset /= p->erase_size;
230
231 COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
232 if (length % p->erase_size)
233 return ERROR_INVALID_ARGUMENTS;
234
235 length -= 1;
236 length /= p->erase_size;
237
238 first = offset;
239 last = offset + length;
240 }
241
242 retval = nand_build_bbt(p, first, last);
243 if (retval == ERROR_OK)
244 {
245 command_print(CMD_CTX, "checked NAND flash device for bad blocks, "
246 "use \"nand info\" command to list blocks");
247 }
248
249 return retval;
250 }
251
252 COMMAND_HANDLER(handle_nand_write_command)
253 {
254 struct nand_device *nand = NULL;
255 struct nand_fileio_state s;
256 int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
257 &s, &nand, FILEIO_READ, false, true);
258 if (ERROR_OK != retval)
259 return retval;
260
261 uint32_t total_bytes = s.size;
262 while (s.size > 0)
263 {
264 int bytes_read = nand_fileio_read(nand, &s);
265 if (bytes_read <= 0)
266 {
267 command_print(CMD_CTX, "error while reading file");
268 return nand_fileio_cleanup(&s);
269 }
270 s.size -= bytes_read;
271
272 retval = nand_write_page(nand, s.address / nand->page_size,
273 s.page, s.page_size, s.oob, s.oob_size);
274 if (ERROR_OK != retval)
275 {
276 command_print(CMD_CTX, "failed writing file %s "
277 "to NAND flash %s at offset 0x%8.8" PRIx32,
278 CMD_ARGV[1], CMD_ARGV[0], s.address);
279 return nand_fileio_cleanup(&s);
280 }
281 s.address += s.page_size;
282 }
283
284 if (nand_fileio_finish(&s))
285 {
286 command_print(CMD_CTX, "wrote file %s to NAND flash %s up to "
287 "offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
288 CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench),
289 duration_kbps(&s.bench, total_bytes));
290 }
291 return ERROR_OK;
292 }
293
294 COMMAND_HANDLER(handle_nand_verify_command)
295 {
296 struct nand_device *nand = NULL;
297 struct nand_fileio_state file;
298 int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
299 &file, &nand, FILEIO_READ, false, true);
300 if (ERROR_OK != retval)
301 return retval;
302
303 struct nand_fileio_state dev;
304 nand_fileio_init(&dev);
305 dev.address = file.address;
306 dev.size = file.size;
307 dev.oob_format = file.oob_format;
308 retval = nand_fileio_start(CMD_CTX, nand, NULL, FILEIO_NONE, &dev);
309 if (ERROR_OK != retval)
310 return retval;
311
312 while (file.size > 0)
313 {
314 retval = nand_read_page(nand, dev.address / dev.page_size,
315 dev.page, dev.page_size, dev.oob, dev.oob_size);
316 if (ERROR_OK != retval)
317 {
318 command_print(CMD_CTX, "reading NAND flash page failed");
319 nand_fileio_cleanup(&dev);
320 nand_fileio_cleanup(&file);
321 return retval;
322 }
323
324 int bytes_read = nand_fileio_read(nand, &file);
325 if (bytes_read <= 0)
326 {
327 command_print(CMD_CTX, "error while reading file");
328 nand_fileio_cleanup(&dev);
329 nand_fileio_cleanup(&file);
330 return ERROR_FAIL;
331 }
332
333 if ((dev.page && memcmp(dev.page, file.page, dev.page_size)) ||
334 (dev.oob && memcmp(dev.oob, file.oob, dev.oob_size)) )
335 {
336 command_print(CMD_CTX, "NAND flash contents differ "
337 "at 0x%8.8" PRIx32, dev.address);
338 nand_fileio_cleanup(&dev);
339 nand_fileio_cleanup(&file);
340 return ERROR_FAIL;
341 }
342
343 file.size -= bytes_read;
344 dev.address += nand->page_size;
345 }
346
347 if (nand_fileio_finish(&file) == ERROR_OK)
348 {
349 command_print(CMD_CTX, "verified file %s in NAND flash %s "
350 "up to offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
351 CMD_ARGV[1], CMD_ARGV[0], dev.address, duration_elapsed(&file.bench),
352 duration_kbps(&file.bench, dev.size));
353 }
354
355 return nand_fileio_cleanup(&dev);
356 }
357
358 COMMAND_HANDLER(handle_nand_dump_command)
359 {
360 int filesize;
361 struct nand_device *nand = NULL;
362 struct nand_fileio_state s;
363 int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
364 &s, &nand, FILEIO_WRITE, true, false);
365 if (ERROR_OK != retval)
366 return retval;
367
368 while (s.size > 0)
369 {
370 size_t size_written;
371 retval = nand_read_page(nand, s.address / nand->page_size,
372 s.page, s.page_size, s.oob, s.oob_size);
373 if (ERROR_OK != retval)
374 {
375 command_print(CMD_CTX, "reading NAND flash page failed");
376 nand_fileio_cleanup(&s);
377 return retval;
378 }
379
380 if (NULL != s.page)
381 fileio_write(&s.fileio, s.page_size, s.page, &size_written);
382
383 if (NULL != s.oob)
384 fileio_write(&s.fileio, s.oob_size, s.oob, &size_written);
385
386 s.size -= nand->page_size;
387 s.address += nand->page_size;
388 }
389
390 retval = fileio_size(&s.fileio, &filesize);
391 if (retval != ERROR_OK)
392 return retval;
393
394 if (nand_fileio_finish(&s) == ERROR_OK)
395 {
396 command_print(CMD_CTX, "dumped %ld bytes in %fs (%0.3f KiB/s)",
397 (long)filesize, duration_elapsed(&s.bench),
398 duration_kbps(&s.bench, filesize));
399 }
400 return ERROR_OK;
401 }
402
403 COMMAND_HANDLER(handle_nand_raw_access_command)
404 {
405 if ((CMD_ARGC < 1) || (CMD_ARGC > 2))
406 {
407 return ERROR_COMMAND_SYNTAX_ERROR;
408 }
409
410 struct nand_device *p;
411 int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
412 if (ERROR_OK != retval)
413 return retval;
414
415 if (NULL == p->device)
416 {
417 command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
418 return ERROR_OK;
419 }
420
421 if (CMD_ARGC == 2)
422 COMMAND_PARSE_ENABLE(CMD_ARGV[1], p->use_raw);
423
424 const char *msg = p->use_raw ? "enabled" : "disabled";
425 command_print(CMD_CTX, "raw access is %s", msg);
426
427 return ERROR_OK;
428 }
429
430 static const struct command_registration nand_exec_command_handlers[] = {
431 {
432 .name = "list",
433 .handler = handle_nand_list_command,
434 .mode = COMMAND_EXEC,
435 .help = "list configured NAND flash devices",
436 },
437 {
438 .name = "info",
439 .handler = handle_nand_info_command,
440 .mode = COMMAND_EXEC,
441 .usage = "[banknum | first_bank_num last_bank_num]",
442 .help = "print info about one or more NAND flash devices",
443 },
444 {
445 .name = "probe",
446 .handler = handle_nand_probe_command,
447 .mode = COMMAND_EXEC,
448 .usage = "bank_id",
449 .help = "identify NAND flash device",
450 },
451 {
452 .name = "check_bad_blocks",
453 .handler = handle_nand_check_bad_blocks_command,
454 .mode = COMMAND_EXEC,
455 .usage = "bank_id [offset length]",
456 .help = "check all or part of NAND flash device for bad blocks",
457 },
458 {
459 .name = "erase",
460 .handler = handle_nand_erase_command,
461 .mode = COMMAND_EXEC,
462 .usage = "bank_id [offset length]",
463 .help = "erase all or subset of blocks on NAND flash device",
464 },
465 {
466 .name = "dump",
467 .handler = handle_nand_dump_command,
468 .mode = COMMAND_EXEC,
469 .usage = "bank_id filename offset length "
470 "['oob_raw'|'oob_only']",
471 .help = "dump from NAND flash device",
472 },
473 {
474 .name = "verify",
475 .handler = handle_nand_verify_command,
476 .mode = COMMAND_EXEC,
477 .usage = "bank_id filename offset "
478 "['oob_raw'|'oob_only'|'oob_softecc'|'oob_softecc_kw']",
479 .help = "verify NAND flash device",
480 },
481 {
482 .name = "write",
483 .handler = handle_nand_write_command,
484 .mode = COMMAND_EXEC,
485 .usage = "bank_id filename offset "
486 "['oob_raw'|'oob_only'|'oob_softecc'|'oob_softecc_kw']",
487 .help = "write to NAND flash device",
488 },
489 {
490 .name = "raw_access",
491 .handler = handle_nand_raw_access_command,
492 .mode = COMMAND_EXEC,
493 .usage = "bank_id ['enable'|'disable']",
494 .help = "raw access to NAND flash device",
495 },
496 COMMAND_REGISTRATION_DONE
497 };
498
499 static int nand_init(struct command_context *cmd_ctx)
500 {
501 if (!nand_devices)
502 return ERROR_OK;
503 struct command *parent = command_find_in_context(cmd_ctx, "nand");
504 return register_commands(cmd_ctx, parent, nand_exec_command_handlers);
505 }
506
507 COMMAND_HANDLER(handle_nand_init_command)
508 {
509 if (CMD_ARGC != 0)
510 return ERROR_COMMAND_SYNTAX_ERROR;
511
512 static bool nand_initialized = false;
513 if (nand_initialized)
514 {
515 LOG_INFO("'nand init' has already been called");
516 return ERROR_OK;
517 }
518 nand_initialized = true;
519
520 LOG_DEBUG("Initializing NAND devices...");
521 return nand_init(CMD_CTX);
522 }
523
524 static int nand_list_walker(struct nand_flash_controller *c, void *x)
525 {
526 struct command_context *cmd_ctx = (struct command_context *)x;
527 command_print(cmd_ctx, " %s", c->name);
528 return ERROR_OK;
529 }
530
531 COMMAND_HANDLER(handle_nand_list_drivers)
532 {
533 command_print(CMD_CTX, "Available NAND flash controller drivers:");
534 return nand_driver_walk(&nand_list_walker, CMD_CTX);
535 }
536
537 static COMMAND_HELPER(create_nand_device, const char *bank_name,
538 struct nand_flash_controller *controller)
539 {
540 if (NULL != controller->commands)
541 {
542 int retval = register_commands(CMD_CTX, NULL,
543 controller->commands);
544 if (ERROR_OK != retval)
545 return retval;
546 }
547 struct nand_device *c = malloc(sizeof(struct nand_device));
548
549 c->name = strdup(bank_name);
550 c->controller = controller;
551 c->controller_priv = NULL;
552 c->manufacturer = NULL;
553 c->device = NULL;
554 c->bus_width = 0;
555 c->address_cycles = 0;
556 c->page_size = 0;
557 c->use_raw = 0;
558 c->next = NULL;
559
560 int retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c);
561 if (ERROR_OK != retval)
562 {
563 LOG_ERROR("'%s' driver rejected nand flash", controller->name);
564 free(c);
565 return ERROR_OK;
566 }
567
568 nand_device_add(c);
569
570 return ERROR_OK;
571 }
572
573 COMMAND_HANDLER(handle_nand_device_command)
574 {
575 if (CMD_ARGC < 1)
576 {
577 LOG_ERROR("incomplete nand device configuration");
578 return ERROR_FLASH_BANK_INVALID;
579 }
580
581 // save name and increment (for compatibility) with drivers
582 const char *bank_name = *CMD_ARGV++;
583 CMD_ARGC--;
584
585 const char *driver_name = CMD_ARGV[0];
586 struct nand_flash_controller *controller;
587 controller = nand_driver_find_by_name(CMD_ARGV[0]);
588 if (NULL == controller)
589 {
590 LOG_ERROR("No valid NAND flash driver found (%s)", driver_name);
591 return CALL_COMMAND_HANDLER(handle_nand_list_drivers);
592 }
593 return CALL_COMMAND_HANDLER(create_nand_device, bank_name, controller);
594 }
595
596 static const struct command_registration nand_config_command_handlers[] = {
597 {
598 .name = "device",
599 .handler = &handle_nand_device_command,
600 .mode = COMMAND_CONFIG,
601 .help = "defines a new NAND bank",
602 .usage = "bank_id driver target [driver_options ...]",
603 },
604 {
605 .name = "drivers",
606 .handler = &handle_nand_list_drivers,
607 .mode = COMMAND_ANY,
608 .help = "lists available NAND drivers",
609 },
610 {
611 .name = "init",
612 .mode = COMMAND_CONFIG,
613 .handler = &handle_nand_init_command,
614 .help = "initialize NAND devices",
615 },
616 COMMAND_REGISTRATION_DONE
617 };
618 static const struct command_registration nand_command_handlers[] = {
619 {
620 .name = "nand",
621 .mode = COMMAND_ANY,
622 .help = "NAND flash command group",
623 .chain = nand_config_command_handlers,
624 },
625 COMMAND_REGISTRATION_DONE
626 };
627
628 int nand_register_commands(struct command_context *cmd_ctx)
629 {
630 return register_commands(cmd_ctx, NULL, nand_command_handlers);
631 }
632
633

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)