1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * mtd.c 4 * 5 * Generic command to handle basic operations on any memory device. 6 * 7 * Copyright: Bootlin, 2018 8 * Author: Miquèl Raynal <miquel.raynal@bootlin.com> 9 */ 10 11 #include <command.h> 12 #include <common.h> 13 #include <console.h> 14 #include <malloc.h> 15 #include <mapmem.h> 16 #include <mtd.h> 17 18 #include <linux/ctype.h> 19 20 static struct mtd_info *get_mtd_by_name(const char *name) 21 { 22 struct mtd_info *mtd; 23 24 mtd_probe_devices(); 25 26 mtd = get_mtd_device_nm(name); 27 if (IS_ERR_OR_NULL(mtd)) 28 printf("MTD device %s not found, ret %ld\n", name, 29 PTR_ERR(mtd)); 30 31 return mtd; 32 } 33 34 static uint mtd_len_to_pages(struct mtd_info *mtd, u64 len) 35 { 36 do_div(len, mtd->writesize); 37 38 return len; 39 } 40 41 static bool mtd_is_aligned_with_min_io_size(struct mtd_info *mtd, u64 size) 42 { 43 return !do_div(size, mtd->writesize); 44 } 45 46 static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size) 47 { 48 return !do_div(size, mtd->erasesize); 49 } 50 51 static void mtd_dump_buf(const u8 *buf, uint len, uint offset) 52 { 53 int i, j; 54 55 for (i = 0; i < len; ) { 56 printf("0x%08x:\t", offset + i); 57 for (j = 0; j < 8; j++) 58 printf("%02x ", buf[i + j]); 59 printf(" "); 60 i += 8; 61 for (j = 0; j < 8; j++) 62 printf("%02x ", buf[i + j]); 63 printf("\n"); 64 i += 8; 65 } 66 } 67 68 static void mtd_dump_device_buf(struct mtd_info *mtd, u64 start_off, 69 const u8 *buf, u64 len, bool woob) 70 { 71 bool has_pages = mtd->type == MTD_NANDFLASH || 72 mtd->type == MTD_MLCNANDFLASH; 73 int npages = mtd_len_to_pages(mtd, len); 74 uint page; 75 76 if (has_pages) { 77 for (page = 0; page < npages; page++) { 78 u64 data_off = page * mtd->writesize; 79 80 printf("\nDump %d data bytes from 0x%08llx:\n", 81 mtd->writesize, start_off + data_off); 82 mtd_dump_buf(&buf[data_off], 83 mtd->writesize, start_off + data_off); 84 85 if (woob) { 86 u64 oob_off = page * mtd->oobsize; 87 88 printf("Dump %d OOB bytes from page at 0x%08llx:\n", 89 mtd->oobsize, start_off + data_off); 90 mtd_dump_buf(&buf[len + oob_off], 91 mtd->oobsize, 0); 92 } 93 } 94 } else { 95 printf("\nDump %lld data bytes from 0x%llx:\n", 96 len, start_off); 97 mtd_dump_buf(buf, len, start_off); 98 } 99 } 100 101 static void mtd_show_parts(struct mtd_info *mtd, int level) 102 { 103 struct mtd_info *part; 104 int i; 105 106 list_for_each_entry(part, &mtd->partitions, node) { 107 for (i = 0; i < level; i++) 108 printf("\t"); 109 printf(" - 0x%012llx-0x%012llx : \"%s\"\n", 110 part->offset, part->offset + part->size, part->name); 111 112 mtd_show_parts(part, level + 1); 113 } 114 } 115 116 static void mtd_show_device(struct mtd_info *mtd) 117 { 118 /* Device */ 119 printf("* %s\n", mtd->name); 120 #if defined(CONFIG_DM) 121 if (mtd->dev) { 122 printf(" - device: %s\n", mtd->dev->name); 123 printf(" - parent: %s\n", mtd->dev->parent->name); 124 printf(" - driver: %s\n", mtd->dev->driver->name); 125 } 126 #endif 127 128 /* MTD device information */ 129 printf(" - type: "); 130 switch (mtd->type) { 131 case MTD_RAM: 132 printf("RAM\n"); 133 break; 134 case MTD_ROM: 135 printf("ROM\n"); 136 break; 137 case MTD_NORFLASH: 138 printf("NOR flash\n"); 139 break; 140 case MTD_NANDFLASH: 141 printf("NAND flash\n"); 142 break; 143 case MTD_DATAFLASH: 144 printf("Data flash\n"); 145 break; 146 case MTD_UBIVOLUME: 147 printf("UBI volume\n"); 148 break; 149 case MTD_MLCNANDFLASH: 150 printf("MLC NAND flash\n"); 151 break; 152 case MTD_ABSENT: 153 default: 154 printf("Unknown\n"); 155 break; 156 } 157 158 printf(" - block size: 0x%x bytes\n", mtd->erasesize); 159 printf(" - min I/O: 0x%x bytes\n", mtd->writesize); 160 161 if (mtd->oobsize) { 162 printf(" - OOB size: %u bytes\n", mtd->oobsize); 163 printf(" - OOB available: %u bytes\n", mtd->oobavail); 164 } 165 166 if (mtd->ecc_strength) { 167 printf(" - ECC strength: %u bits\n", mtd->ecc_strength); 168 printf(" - ECC step size: %u bytes\n", mtd->ecc_step_size); 169 printf(" - bitflip threshold: %u bits\n", 170 mtd->bitflip_threshold); 171 } 172 173 printf(" - 0x%012llx-0x%012llx : \"%s\"\n", 174 mtd->offset, mtd->offset + mtd->size, mtd->name); 175 176 /* MTD partitions, if any */ 177 mtd_show_parts(mtd, 1); 178 } 179 180 /* Logic taken from fs/ubifs/recovery.c:is_empty() */ 181 static bool mtd_oob_write_is_empty(struct mtd_oob_ops *op) 182 { 183 int i; 184 185 for (i = 0; i < op->len; i++) 186 if (op->datbuf[i] != 0xff) 187 return false; 188 189 for (i = 0; i < op->ooblen; i++) 190 if (op->oobbuf[i] != 0xff) 191 return false; 192 193 return true; 194 } 195 196 static int do_mtd_list(cmd_tbl_t *cmdtp, int flag, int argc, 197 char * const argv[]) 198 { 199 struct mtd_info *mtd; 200 int dev_nb = 0; 201 202 /* Ensure all devices (and their partitions) are probed */ 203 mtd_probe_devices(); 204 205 printf("List of MTD devices:\n"); 206 mtd_for_each_device(mtd) { 207 if (!mtd_is_partition(mtd)) 208 mtd_show_device(mtd); 209 210 dev_nb++; 211 } 212 213 if (!dev_nb) { 214 printf("No MTD device found\n"); 215 return CMD_RET_FAILURE; 216 } 217 218 return CMD_RET_SUCCESS; 219 } 220 221 static int mtd_special_write_oob(struct mtd_info *mtd, u64 off, 222 struct mtd_oob_ops *io_op, 223 bool write_empty_pages, bool woob) 224 { 225 int ret = 0; 226 227 /* 228 * By default, do not write an empty page. 229 * Skip it by simulating a successful write. 230 */ 231 if (!write_empty_pages && mtd_oob_write_is_empty(io_op)) { 232 io_op->retlen = mtd->writesize; 233 io_op->oobretlen = woob ? mtd->oobsize : 0; 234 } else { 235 ret = mtd_write_oob(mtd, off, io_op); 236 } 237 238 return ret; 239 } 240 241 static int do_mtd_io(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 242 { 243 bool dump, read, raw, woob, write_empty_pages, has_pages = false; 244 u64 start_off, off, len, remaining, default_len; 245 struct mtd_oob_ops io_op = {}; 246 uint user_addr = 0, npages; 247 const char *cmd = argv[0]; 248 struct mtd_info *mtd; 249 u32 oob_len; 250 u8 *buf; 251 int ret; 252 253 if (argc < 2) 254 return CMD_RET_USAGE; 255 256 mtd = get_mtd_by_name(argv[1]); 257 if (IS_ERR_OR_NULL(mtd)) 258 return CMD_RET_FAILURE; 259 260 if (mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH) 261 has_pages = true; 262 263 dump = !strncmp(cmd, "dump", 4); 264 read = dump || !strncmp(cmd, "read", 4); 265 raw = strstr(cmd, ".raw"); 266 woob = strstr(cmd, ".oob"); 267 write_empty_pages = !has_pages || strstr(cmd, ".dontskipff"); 268 269 argc -= 2; 270 argv += 2; 271 272 if (!dump) { 273 if (!argc) { 274 ret = CMD_RET_USAGE; 275 goto out_put_mtd; 276 } 277 278 user_addr = simple_strtoul(argv[0], NULL, 16); 279 argc--; 280 argv++; 281 } 282 283 start_off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0; 284 if (!mtd_is_aligned_with_min_io_size(mtd, start_off)) { 285 printf("Offset not aligned with a page (0x%x)\n", 286 mtd->writesize); 287 ret = CMD_RET_FAILURE; 288 goto out_put_mtd; 289 } 290 291 default_len = dump ? mtd->writesize : mtd->size; 292 len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : default_len; 293 if (!mtd_is_aligned_with_min_io_size(mtd, len)) { 294 len = round_up(len, mtd->writesize); 295 printf("Size not on a page boundary (0x%x), rounding to 0x%llx\n", 296 mtd->writesize, len); 297 } 298 299 remaining = len; 300 npages = mtd_len_to_pages(mtd, len); 301 oob_len = woob ? npages * mtd->oobsize : 0; 302 303 if (dump) 304 buf = kmalloc(len + oob_len, GFP_KERNEL); 305 else 306 buf = map_sysmem(user_addr, 0); 307 308 if (!buf) { 309 printf("Could not map/allocate the user buffer\n"); 310 ret = CMD_RET_FAILURE; 311 goto out_put_mtd; 312 } 313 314 if (has_pages) 315 printf("%s %lld byte(s) (%d page(s)) at offset 0x%08llx%s%s%s\n", 316 read ? "Reading" : "Writing", len, npages, start_off, 317 raw ? " [raw]" : "", woob ? " [oob]" : "", 318 !read && write_empty_pages ? " [dontskipff]" : ""); 319 else 320 printf("%s %lld byte(s) at offset 0x%08llx\n", 321 read ? "Reading" : "Writing", len, start_off); 322 323 io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB; 324 io_op.len = has_pages ? mtd->writesize : len; 325 io_op.ooblen = woob ? mtd->oobsize : 0; 326 io_op.datbuf = buf; 327 io_op.oobbuf = woob ? &buf[len] : NULL; 328 329 /* Search for the first good block after the given offset */ 330 off = start_off; 331 while (mtd_block_isbad(mtd, off)) 332 off += mtd->erasesize; 333 334 /* Loop over the pages to do the actual read/write */ 335 while (remaining) { 336 /* Skip the block if it is bad */ 337 if (mtd_is_aligned_with_block_size(mtd, off) && 338 mtd_block_isbad(mtd, off)) { 339 off += mtd->erasesize; 340 continue; 341 } 342 343 if (read) 344 ret = mtd_read_oob(mtd, off, &io_op); 345 else 346 ret = mtd_special_write_oob(mtd, off, &io_op, 347 write_empty_pages, woob); 348 349 if (ret) { 350 printf("Failure while %s at offset 0x%llx\n", 351 read ? "reading" : "writing", off); 352 break; 353 } 354 355 off += io_op.retlen; 356 remaining -= io_op.retlen; 357 io_op.datbuf += io_op.retlen; 358 io_op.oobbuf += io_op.oobretlen; 359 } 360 361 if (!ret && dump) 362 mtd_dump_device_buf(mtd, start_off, buf, len, woob); 363 364 if (dump) 365 kfree(buf); 366 else 367 unmap_sysmem(buf); 368 369 if (ret) { 370 printf("%s on %s failed with error %d\n", 371 read ? "Read" : "Write", mtd->name, ret); 372 ret = CMD_RET_FAILURE; 373 } else { 374 ret = CMD_RET_SUCCESS; 375 } 376 377 out_put_mtd: 378 put_mtd_device(mtd); 379 380 return ret; 381 } 382 383 static int do_mtd_erase(cmd_tbl_t *cmdtp, int flag, int argc, 384 char * const argv[]) 385 { 386 struct erase_info erase_op = {}; 387 struct mtd_info *mtd; 388 u64 off, len; 389 bool scrub; 390 int ret; 391 392 if (argc < 2) 393 return CMD_RET_USAGE; 394 395 mtd = get_mtd_by_name(argv[1]); 396 if (IS_ERR_OR_NULL(mtd)) 397 return CMD_RET_FAILURE; 398 399 scrub = strstr(argv[0], ".dontskipbad"); 400 401 argc -= 2; 402 argv += 2; 403 404 off = argc > 0 ? simple_strtoul(argv[0], NULL, 16) : 0; 405 len = argc > 1 ? simple_strtoul(argv[1], NULL, 16) : mtd->size; 406 407 if (!mtd_is_aligned_with_block_size(mtd, off)) { 408 printf("Offset not aligned with a block (0x%x)\n", 409 mtd->erasesize); 410 ret = CMD_RET_FAILURE; 411 goto out_put_mtd; 412 } 413 414 if (!mtd_is_aligned_with_block_size(mtd, len)) { 415 printf("Size not a multiple of a block (0x%x)\n", 416 mtd->erasesize); 417 ret = CMD_RET_FAILURE; 418 goto out_put_mtd; 419 } 420 421 printf("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n", 422 off, off + len - 1, mtd_div_by_eb(len, mtd)); 423 424 erase_op.mtd = mtd; 425 erase_op.addr = off; 426 erase_op.len = len; 427 erase_op.scrub = scrub; 428 429 while (erase_op.len) { 430 ret = mtd_erase(mtd, &erase_op); 431 432 /* Abort if its not a bad block error */ 433 if (ret != -EIO) 434 break; 435 436 printf("Skipping bad block at 0x%08llx\n", erase_op.fail_addr); 437 438 /* Skip bad block and continue behind it */ 439 erase_op.len -= erase_op.fail_addr - erase_op.addr; 440 erase_op.len -= mtd->erasesize; 441 erase_op.addr = erase_op.fail_addr + mtd->erasesize; 442 } 443 444 if (ret && ret != -EIO) 445 ret = CMD_RET_FAILURE; 446 else 447 ret = CMD_RET_SUCCESS; 448 449 out_put_mtd: 450 put_mtd_device(mtd); 451 452 return ret; 453 } 454 455 static int do_mtd_bad(cmd_tbl_t *cmdtp, int flag, int argc, 456 char * const argv[]) 457 { 458 struct mtd_info *mtd; 459 loff_t off; 460 461 if (argc < 2) 462 return CMD_RET_USAGE; 463 464 mtd = get_mtd_by_name(argv[1]); 465 if (IS_ERR_OR_NULL(mtd)) 466 return CMD_RET_FAILURE; 467 468 if (!mtd_can_have_bb(mtd)) { 469 printf("Only NAND-based devices can have bad blocks\n"); 470 goto out_put_mtd; 471 } 472 473 printf("MTD device %s bad blocks list:\n", mtd->name); 474 for (off = 0; off < mtd->size; off += mtd->erasesize) { 475 if (mtd_block_isbad(mtd, off)) 476 printf("\t0x%08llx\n", off); 477 } 478 479 out_put_mtd: 480 put_mtd_device(mtd); 481 482 return CMD_RET_SUCCESS; 483 } 484 485 #ifdef CONFIG_AUTO_COMPLETE 486 static int mtd_name_complete(int argc, char * const argv[], char last_char, 487 int maxv, char *cmdv[]) 488 { 489 int len = 0, n_found = 0; 490 struct mtd_info *mtd; 491 492 argc--; 493 argv++; 494 495 if (argc > 1 || 496 (argc == 1 && (last_char == '\0' || isblank(last_char)))) 497 return 0; 498 499 if (argc) 500 len = strlen(argv[0]); 501 502 mtd_for_each_device(mtd) { 503 if (argc && 504 (len > strlen(mtd->name) || 505 strncmp(argv[0], mtd->name, len))) 506 continue; 507 508 if (n_found >= maxv - 2) { 509 cmdv[n_found++] = "..."; 510 break; 511 } 512 513 cmdv[n_found++] = mtd->name; 514 } 515 516 cmdv[n_found] = NULL; 517 518 return n_found; 519 } 520 #endif /* CONFIG_AUTO_COMPLETE */ 521 522 #ifdef CONFIG_SYS_LONGHELP 523 static char mtd_help_text[] = 524 "- generic operations on memory technology devices\n\n" 525 "mtd list\n" 526 "mtd read[.raw][.oob] <name> <addr> [<off> [<size>]]\n" 527 "mtd dump[.raw][.oob] <name> [<off> [<size>]]\n" 528 "mtd write[.raw][.oob][.dontskipff] <name> <addr> [<off> [<size>]]\n" 529 "mtd erase[.dontskipbad] <name> [<off> [<size>]]\n" 530 "\n" 531 "Specific functions:\n" 532 "mtd bad <name>\n" 533 "\n" 534 "With:\n" 535 "\t<name>: NAND partition/chip name\n" 536 "\t<addr>: user address from/to which data will be retrieved/stored\n" 537 "\t<off>: offset in <name> in bytes (default: start of the part)\n" 538 "\t\t* must be block-aligned for erase\n" 539 "\t\t* must be page-aligned otherwise\n" 540 "\t<size>: length of the operation in bytes (default: the entire device)\n" 541 "\t\t* must be a multiple of a block for erase\n" 542 "\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\n" 543 "\n" 544 "The .dontskipff option forces writing empty pages, don't use it if unsure.\n"; 545 #endif 546 547 U_BOOT_CMD_WITH_SUBCMDS(mtd, "MTD utils", mtd_help_text, 548 U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mtd_list), 549 U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io, 550 mtd_name_complete), 551 U_BOOT_SUBCMD_MKENT_COMPLETE(write, 5, 0, do_mtd_io, 552 mtd_name_complete), 553 U_BOOT_SUBCMD_MKENT_COMPLETE(dump, 4, 0, do_mtd_io, 554 mtd_name_complete), 555 U_BOOT_SUBCMD_MKENT_COMPLETE(erase, 4, 0, do_mtd_erase, 556 mtd_name_complete), 557 U_BOOT_SUBCMD_MKENT_COMPLETE(bad, 2, 1, do_mtd_bad, 558 mtd_name_complete)); 559