1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2002 4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 5 * 6 * (C) Copyright 2002 7 * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de> 8 * 9 * (C) Copyright 2003 10 * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de> 11 * 12 * (C) Copyright 2005 13 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 14 * 15 * Added support for reading flash partition table from environment. 16 * Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4 17 * kernel tree. 18 * 19 * (C) Copyright 2008 20 * Harald Welte, OpenMoko, Inc., Harald Welte <laforge@openmoko.org> 21 * 22 * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $ 23 * Copyright 2002 SYSGO Real-Time Solutions GmbH 24 */ 25 26 /* 27 * Three environment variables are used by the parsing routines: 28 * 29 * 'partition' - keeps current partition identifier 30 * 31 * partition := <part-id> 32 * <part-id> := <dev-id>,part_num 33 * 34 * 35 * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping 36 * 37 * mtdids=<idmap>[,<idmap>,...] 38 * 39 * <idmap> := <dev-id>=<mtd-id> 40 * <dev-id> := 'nand'|'nor'|'onenand'<dev-num> 41 * <dev-num> := mtd device number, 0... 42 * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name) 43 * 44 * 45 * 'mtdparts' - partition list 46 * 47 * mtdparts=mtdparts=<mtd-def>[;<mtd-def>...] 48 * 49 * <mtd-def> := <mtd-id>:<part-def>[,<part-def>...] 50 * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name) 51 * <part-def> := <size>[@<offset>][<name>][<ro-flag>] 52 * <size> := standard linux memsize OR '-' to denote all remaining space 53 * <offset> := partition start offset within the device 54 * <name> := '(' NAME ')' 55 * <ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel) 56 * 57 * Notes: 58 * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping 59 * - if the above variables are not set defaults for a given target are used 60 * 61 * Examples: 62 * 63 * 1 NOR Flash, with 1 single writable partition: 64 * mtdids=nor0=edb7312-nor 65 * mtdparts=mtdparts=edb7312-nor:- 66 * 67 * 1 NOR Flash with 2 partitions, 1 NAND with one 68 * mtdids=nor0=edb7312-nor,nand0=edb7312-nand 69 * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) 70 * 71 */ 72 73 #include <common.h> 74 #include <command.h> 75 #include <malloc.h> 76 #include <jffs2/load_kernel.h> 77 #include <linux/list.h> 78 #include <linux/ctype.h> 79 #include <linux/err.h> 80 #include <linux/mtd/mtd.h> 81 82 #if defined(CONFIG_CMD_NAND) 83 #include <linux/mtd/rawnand.h> 84 #include <nand.h> 85 #endif 86 87 #if defined(CONFIG_CMD_ONENAND) 88 #include <linux/mtd/onenand.h> 89 #include <onenand_uboot.h> 90 #endif 91 92 DECLARE_GLOBAL_DATA_PTR; 93 94 /* special size referring to all the remaining space in a partition */ 95 #define SIZE_REMAINING (~0llu) 96 97 /* special offset value, it is used when not provided by user 98 * 99 * this value is used temporarily during parsing, later such offests 100 * are recalculated */ 101 #define OFFSET_NOT_SPECIFIED (~0llu) 102 103 /* minimum partition size */ 104 #define MIN_PART_SIZE 4096 105 106 /* this flag needs to be set in part_info struct mask_flags 107 * field for read-only partitions */ 108 #define MTD_WRITEABLE_CMD 1 109 110 /* default values for mtdids and mtdparts variables */ 111 #if !defined(MTDIDS_DEFAULT) 112 #ifdef CONFIG_MTDIDS_DEFAULT 113 #define MTDIDS_DEFAULT CONFIG_MTDIDS_DEFAULT 114 #else 115 #define MTDIDS_DEFAULT NULL 116 #endif 117 #endif 118 #if !defined(MTDPARTS_DEFAULT) 119 #ifdef CONFIG_MTDPARTS_DEFAULT 120 #define MTDPARTS_DEFAULT CONFIG_MTDPARTS_DEFAULT 121 #else 122 #define MTDPARTS_DEFAULT NULL 123 #endif 124 #endif 125 #if defined(CONFIG_SYS_MTDPARTS_RUNTIME) 126 extern void board_mtdparts_default(const char **mtdids, const char **mtdparts); 127 #endif 128 static const char *mtdids_default = MTDIDS_DEFAULT; 129 static const char *mtdparts_default = MTDPARTS_DEFAULT; 130 131 /* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */ 132 #define MTDIDS_MAXLEN 128 133 #define MTDPARTS_MAXLEN 512 134 #define PARTITION_MAXLEN 16 135 static char last_ids[MTDIDS_MAXLEN + 1]; 136 static char last_parts[MTDPARTS_MAXLEN + 1]; 137 static char last_partition[PARTITION_MAXLEN + 1]; 138 139 /* low level jffs2 cache cleaning routine */ 140 extern void jffs2_free_cache(struct part_info *part); 141 142 /* mtdids mapping list, filled by parse_ids() */ 143 static struct list_head mtdids; 144 145 /* device/partition list, parse_cmdline() parses into here */ 146 static struct list_head devices; 147 148 /* current active device and partition number */ 149 struct mtd_device *current_mtd_dev = NULL; 150 u8 current_mtd_partnum = 0; 151 152 u8 use_defaults; 153 154 static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part_num); 155 156 /* command line only routines */ 157 static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len); 158 static int device_del(struct mtd_device *dev); 159 160 /** 161 * Parses a string into a number. The number stored at ptr is 162 * potentially suffixed with K (for kilobytes, or 1024 bytes), 163 * M (for megabytes, or 1048576 bytes), or G (for gigabytes, or 164 * 1073741824). If the number is suffixed with K, M, or G, then 165 * the return value is the number multiplied by one kilobyte, one 166 * megabyte, or one gigabyte, respectively. 167 * 168 * @param ptr where parse begins 169 * @param retptr output pointer to next char after parse completes (output) 170 * @return resulting unsigned int 171 */ 172 static u64 memsize_parse (const char *const ptr, const char **retptr) 173 { 174 u64 ret = simple_strtoull(ptr, (char **)retptr, 0); 175 176 switch (**retptr) { 177 case 'G': 178 case 'g': 179 ret <<= 10; 180 case 'M': 181 case 'm': 182 ret <<= 10; 183 case 'K': 184 case 'k': 185 ret <<= 10; 186 (*retptr)++; 187 default: 188 break; 189 } 190 191 return ret; 192 } 193 194 /** 195 * Format string describing supplied size. This routine does the opposite job 196 * to memsize_parse(). Size in bytes is converted to string and if possible 197 * shortened by using k (kilobytes), m (megabytes) or g (gigabytes) suffix. 198 * 199 * Note, that this routine does not check for buffer overflow, it's the caller 200 * who must assure enough space. 201 * 202 * @param buf output buffer 203 * @param size size to be converted to string 204 */ 205 static void memsize_format(char *buf, u64 size) 206 { 207 #define SIZE_GB ((u32)1024*1024*1024) 208 #define SIZE_MB ((u32)1024*1024) 209 #define SIZE_KB ((u32)1024) 210 211 if ((size % SIZE_GB) == 0) 212 sprintf(buf, "%llug", size/SIZE_GB); 213 else if ((size % SIZE_MB) == 0) 214 sprintf(buf, "%llum", size/SIZE_MB); 215 else if (size % SIZE_KB == 0) 216 sprintf(buf, "%lluk", size/SIZE_KB); 217 else 218 sprintf(buf, "%llu", size); 219 } 220 221 /** 222 * This routine does global indexing of all partitions. Resulting index for 223 * current partition is saved in 'mtddevnum'. Current partition name in 224 * 'mtddevname'. 225 */ 226 static void index_partitions(void) 227 { 228 u16 mtddevnum; 229 struct part_info *part; 230 struct list_head *dentry; 231 struct mtd_device *dev; 232 233 debug("--- index partitions ---\n"); 234 235 if (current_mtd_dev) { 236 mtddevnum = 0; 237 list_for_each(dentry, &devices) { 238 dev = list_entry(dentry, struct mtd_device, link); 239 if (dev == current_mtd_dev) { 240 mtddevnum += current_mtd_partnum; 241 env_set_ulong("mtddevnum", mtddevnum); 242 debug("=> mtddevnum %d,\n", mtddevnum); 243 break; 244 } 245 mtddevnum += dev->num_parts; 246 } 247 248 part = mtd_part_info(current_mtd_dev, current_mtd_partnum); 249 if (part) { 250 env_set("mtddevname", part->name); 251 252 debug("=> mtddevname %s\n", part->name); 253 } else { 254 env_set("mtddevname", NULL); 255 256 debug("=> mtddevname NULL\n"); 257 } 258 } else { 259 env_set("mtddevnum", NULL); 260 env_set("mtddevname", NULL); 261 262 debug("=> mtddevnum NULL\n=> mtddevname NULL\n"); 263 } 264 } 265 266 /** 267 * Save current device and partition in environment variable 'partition'. 268 */ 269 static void current_save(void) 270 { 271 char buf[16]; 272 273 debug("--- current_save ---\n"); 274 275 if (current_mtd_dev) { 276 sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_mtd_dev->id->type), 277 current_mtd_dev->id->num, current_mtd_partnum); 278 279 env_set("partition", buf); 280 strncpy(last_partition, buf, 16); 281 282 debug("=> partition %s\n", buf); 283 } else { 284 env_set("partition", NULL); 285 last_partition[0] = '\0'; 286 287 debug("=> partition NULL\n"); 288 } 289 index_partitions(); 290 } 291 292 293 /** 294 * Produce a mtd_info given a type and num. 295 * 296 * @param type mtd type 297 * @param num mtd number 298 * @param mtd a pointer to an mtd_info instance (output) 299 * @return 0 if device is valid, 1 otherwise 300 */ 301 static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd) 302 { 303 char mtd_dev[16]; 304 305 sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num); 306 *mtd = get_mtd_device_nm(mtd_dev); 307 if (IS_ERR(*mtd)) { 308 printf("Device %s not found!\n", mtd_dev); 309 return 1; 310 } 311 put_mtd_device(*mtd); 312 313 return 0; 314 } 315 316 /** 317 * Performs sanity check for supplied flash partition. 318 * Table of existing MTD flash devices is searched and partition device 319 * is located. Alignment with the granularity of nand erasesize is verified. 320 * 321 * @param id of the parent device 322 * @param part partition to validate 323 * @return 0 if partition is valid, 1 otherwise 324 */ 325 static int part_validate_eraseblock(struct mtdids *id, struct part_info *part) 326 { 327 struct mtd_info *mtd = NULL; 328 int i, j; 329 ulong start; 330 u64 offset, size; 331 332 if (get_mtd_info(id->type, id->num, &mtd)) 333 return 1; 334 335 part->sector_size = mtd->erasesize; 336 337 if (!mtd->numeraseregions) { 338 /* 339 * Only one eraseregion (NAND, OneNAND or uniform NOR), 340 * checking for alignment is easy here 341 */ 342 offset = part->offset; 343 if (do_div(offset, mtd->erasesize)) { 344 printf("%s%d: partition (%s) start offset" 345 "alignment incorrect\n", 346 MTD_DEV_TYPE(id->type), id->num, part->name); 347 return 1; 348 } 349 350 size = part->size; 351 if (do_div(size, mtd->erasesize)) { 352 printf("%s%d: partition (%s) size alignment incorrect\n", 353 MTD_DEV_TYPE(id->type), id->num, part->name); 354 return 1; 355 } 356 } else { 357 /* 358 * Multiple eraseregions (non-uniform NOR), 359 * checking for alignment is more complex here 360 */ 361 362 /* Check start alignment */ 363 for (i = 0; i < mtd->numeraseregions; i++) { 364 start = mtd->eraseregions[i].offset; 365 for (j = 0; j < mtd->eraseregions[i].numblocks; j++) { 366 if (part->offset == start) 367 goto start_ok; 368 start += mtd->eraseregions[i].erasesize; 369 } 370 } 371 372 printf("%s%d: partition (%s) start offset alignment incorrect\n", 373 MTD_DEV_TYPE(id->type), id->num, part->name); 374 return 1; 375 376 start_ok: 377 378 /* Check end/size alignment */ 379 for (i = 0; i < mtd->numeraseregions; i++) { 380 start = mtd->eraseregions[i].offset; 381 for (j = 0; j < mtd->eraseregions[i].numblocks; j++) { 382 if ((part->offset + part->size) == start) 383 goto end_ok; 384 start += mtd->eraseregions[i].erasesize; 385 } 386 } 387 /* Check last sector alignment */ 388 if ((part->offset + part->size) == start) 389 goto end_ok; 390 391 printf("%s%d: partition (%s) size alignment incorrect\n", 392 MTD_DEV_TYPE(id->type), id->num, part->name); 393 return 1; 394 395 end_ok: 396 return 0; 397 } 398 399 return 0; 400 } 401 402 403 /** 404 * Performs sanity check for supplied partition. Offset and size are 405 * verified to be within valid range. Partition type is checked and 406 * part_validate_eraseblock() is called with the argument of part. 407 * 408 * @param id of the parent device 409 * @param part partition to validate 410 * @return 0 if partition is valid, 1 otherwise 411 */ 412 static int part_validate(struct mtdids *id, struct part_info *part) 413 { 414 if (part->size == SIZE_REMAINING) 415 part->size = id->size - part->offset; 416 417 if (part->offset > id->size) { 418 printf("%s: offset %08llx beyond flash size %08llx\n", 419 id->mtd_id, part->offset, id->size); 420 return 1; 421 } 422 423 if ((part->offset + part->size) <= part->offset) { 424 printf("%s%d: partition (%s) size too big\n", 425 MTD_DEV_TYPE(id->type), id->num, part->name); 426 return 1; 427 } 428 429 if (part->offset + part->size > id->size) { 430 printf("%s: partitioning exceeds flash size\n", id->mtd_id); 431 return 1; 432 } 433 434 /* 435 * Now we need to check if the partition starts and ends on 436 * sector (eraseblock) regions 437 */ 438 return part_validate_eraseblock(id, part); 439 } 440 441 /** 442 * Delete selected partition from the partition list of the specified device. 443 * 444 * @param dev device to delete partition from 445 * @param part partition to delete 446 * @return 0 on success, 1 otherwise 447 */ 448 static int part_del(struct mtd_device *dev, struct part_info *part) 449 { 450 u8 current_save_needed = 0; 451 452 /* if there is only one partition, remove whole device */ 453 if (dev->num_parts == 1) 454 return device_del(dev); 455 456 /* otherwise just delete this partition */ 457 458 if (dev == current_mtd_dev) { 459 /* we are modyfing partitions for the current device, 460 * update current */ 461 struct part_info *curr_pi; 462 curr_pi = mtd_part_info(current_mtd_dev, current_mtd_partnum); 463 464 if (curr_pi) { 465 if (curr_pi == part) { 466 printf("current partition deleted, resetting current to 0\n"); 467 current_mtd_partnum = 0; 468 } else if (part->offset <= curr_pi->offset) { 469 current_mtd_partnum--; 470 } 471 current_save_needed = 1; 472 } 473 } 474 475 list_del(&part->link); 476 free(part); 477 dev->num_parts--; 478 479 if (current_save_needed > 0) 480 current_save(); 481 else 482 index_partitions(); 483 484 return 0; 485 } 486 487 /** 488 * Delete all partitions from parts head list, free memory. 489 * 490 * @param head list of partitions to delete 491 */ 492 static void part_delall(struct list_head *head) 493 { 494 struct list_head *entry, *n; 495 struct part_info *part_tmp; 496 497 /* clean tmp_list and free allocated memory */ 498 list_for_each_safe(entry, n, head) { 499 part_tmp = list_entry(entry, struct part_info, link); 500 501 list_del(entry); 502 free(part_tmp); 503 } 504 } 505 506 /** 507 * Add new partition to the supplied partition list. Make sure partitions are 508 * sorted by offset in ascending order. 509 * 510 * @param head list this partition is to be added to 511 * @param new partition to be added 512 */ 513 static int part_sort_add(struct mtd_device *dev, struct part_info *part) 514 { 515 struct list_head *entry; 516 struct part_info *new_pi, *curr_pi; 517 518 /* link partition to parrent dev */ 519 part->dev = dev; 520 521 if (list_empty(&dev->parts)) { 522 debug("part_sort_add: list empty\n"); 523 list_add(&part->link, &dev->parts); 524 dev->num_parts++; 525 index_partitions(); 526 return 0; 527 } 528 529 new_pi = list_entry(&part->link, struct part_info, link); 530 531 /* get current partition info if we are updating current device */ 532 curr_pi = NULL; 533 if (dev == current_mtd_dev) 534 curr_pi = mtd_part_info(current_mtd_dev, current_mtd_partnum); 535 536 list_for_each(entry, &dev->parts) { 537 struct part_info *pi; 538 539 pi = list_entry(entry, struct part_info, link); 540 541 /* be compliant with kernel cmdline, allow only one partition at offset zero */ 542 if ((new_pi->offset == pi->offset) && (pi->offset == 0)) { 543 printf("cannot add second partition at offset 0\n"); 544 return 1; 545 } 546 547 if (new_pi->offset <= pi->offset) { 548 list_add_tail(&part->link, entry); 549 dev->num_parts++; 550 551 if (curr_pi && (pi->offset <= curr_pi->offset)) { 552 /* we are modyfing partitions for the current 553 * device, update current */ 554 current_mtd_partnum++; 555 current_save(); 556 } else { 557 index_partitions(); 558 } 559 return 0; 560 } 561 } 562 563 list_add_tail(&part->link, &dev->parts); 564 dev->num_parts++; 565 index_partitions(); 566 return 0; 567 } 568 569 /** 570 * Add provided partition to the partition list of a given device. 571 * 572 * @param dev device to which partition is added 573 * @param part partition to be added 574 * @return 0 on success, 1 otherwise 575 */ 576 static int part_add(struct mtd_device *dev, struct part_info *part) 577 { 578 /* verify alignment and size */ 579 if (part_validate(dev->id, part) != 0) 580 return 1; 581 582 /* partition is ok, add it to the list */ 583 if (part_sort_add(dev, part) != 0) 584 return 1; 585 586 return 0; 587 } 588 589 /** 590 * Parse one partition definition, allocate memory and return pointer to this 591 * location in retpart. 592 * 593 * @param partdef pointer to the partition definition string i.e. <part-def> 594 * @param ret output pointer to next char after parse completes (output) 595 * @param retpart pointer to the allocated partition (output) 596 * @return 0 on success, 1 otherwise 597 */ 598 static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart) 599 { 600 struct part_info *part; 601 u64 size; 602 u64 offset; 603 const char *name; 604 int name_len; 605 unsigned int mask_flags; 606 const char *p; 607 608 p = partdef; 609 *retpart = NULL; 610 *ret = NULL; 611 612 /* fetch the partition size */ 613 if (*p == '-') { 614 /* assign all remaining space to this partition */ 615 debug("'-': remaining size assigned\n"); 616 size = SIZE_REMAINING; 617 p++; 618 } else { 619 size = memsize_parse(p, &p); 620 if (size < MIN_PART_SIZE) { 621 printf("partition size too small (%llx)\n", size); 622 return 1; 623 } 624 } 625 626 /* check for offset */ 627 offset = OFFSET_NOT_SPECIFIED; 628 if (*p == '@') { 629 p++; 630 offset = memsize_parse(p, &p); 631 } 632 633 /* now look for the name */ 634 if (*p == '(') { 635 name = ++p; 636 if ((p = strchr(name, ')')) == NULL) { 637 printf("no closing ) found in partition name\n"); 638 return 1; 639 } 640 name_len = p - name + 1; 641 if ((name_len - 1) == 0) { 642 printf("empty partition name\n"); 643 return 1; 644 } 645 p++; 646 } else { 647 /* 0x00000000@0x00000000 */ 648 name_len = 22; 649 name = NULL; 650 } 651 652 /* test for options */ 653 mask_flags = 0; 654 if (strncmp(p, "ro", 2) == 0) { 655 mask_flags |= MTD_WRITEABLE_CMD; 656 p += 2; 657 } 658 659 /* check for next partition definition */ 660 if (*p == ',') { 661 if (size == SIZE_REMAINING) { 662 *ret = NULL; 663 printf("no partitions allowed after a fill-up partition\n"); 664 return 1; 665 } 666 *ret = ++p; 667 } else if ((*p == ';') || (*p == '\0')) { 668 *ret = p; 669 } else { 670 printf("unexpected character '%c' at the end of partition\n", *p); 671 *ret = NULL; 672 return 1; 673 } 674 675 /* allocate memory */ 676 part = (struct part_info *)malloc(sizeof(struct part_info) + name_len); 677 if (!part) { 678 printf("out of memory\n"); 679 return 1; 680 } 681 memset(part, 0, sizeof(struct part_info) + name_len); 682 part->size = size; 683 part->offset = offset; 684 part->mask_flags = mask_flags; 685 part->name = (char *)(part + 1); 686 687 if (name) { 688 /* copy user provided name */ 689 strncpy(part->name, name, name_len - 1); 690 part->auto_name = 0; 691 } else { 692 /* auto generated name in form of size@offset */ 693 sprintf(part->name, "0x%08llx@0x%08llx", size, offset); 694 part->auto_name = 1; 695 } 696 697 part->name[name_len - 1] = '\0'; 698 INIT_LIST_HEAD(&part->link); 699 700 debug("+ partition: name %-22s size 0x%08llx offset 0x%08llx mask flags %d\n", 701 part->name, part->size, 702 part->offset, part->mask_flags); 703 704 *retpart = part; 705 return 0; 706 } 707 708 /** 709 * Check device number to be within valid range for given device type. 710 * 711 * @param type mtd type 712 * @param num mtd number 713 * @param size a pointer to the size of the mtd device (output) 714 * @return 0 if device is valid, 1 otherwise 715 */ 716 static int mtd_device_validate(u8 type, u8 num, u64 *size) 717 { 718 struct mtd_info *mtd = NULL; 719 720 if (get_mtd_info(type, num, &mtd)) 721 return 1; 722 723 *size = mtd->size; 724 725 return 0; 726 } 727 728 /** 729 * Delete all mtd devices from a supplied devices list, free memory allocated for 730 * each device and delete all device partitions. 731 * 732 * @return 0 on success, 1 otherwise 733 */ 734 static int device_delall(struct list_head *head) 735 { 736 struct list_head *entry, *n; 737 struct mtd_device *dev_tmp; 738 739 /* clean devices list */ 740 list_for_each_safe(entry, n, head) { 741 dev_tmp = list_entry(entry, struct mtd_device, link); 742 list_del(entry); 743 part_delall(&dev_tmp->parts); 744 free(dev_tmp); 745 } 746 INIT_LIST_HEAD(&devices); 747 748 return 0; 749 } 750 751 /** 752 * If provided device exists it's partitions are deleted, device is removed 753 * from device list and device memory is freed. 754 * 755 * @param dev device to be deleted 756 * @return 0 on success, 1 otherwise 757 */ 758 static int device_del(struct mtd_device *dev) 759 { 760 part_delall(&dev->parts); 761 list_del(&dev->link); 762 free(dev); 763 764 if (dev == current_mtd_dev) { 765 /* we just deleted current device */ 766 if (list_empty(&devices)) { 767 current_mtd_dev = NULL; 768 } else { 769 /* reset first partition from first dev from the 770 * devices list as current */ 771 current_mtd_dev = list_entry(devices.next, struct mtd_device, link); 772 current_mtd_partnum = 0; 773 } 774 current_save(); 775 return 0; 776 } 777 778 index_partitions(); 779 return 0; 780 } 781 782 /** 783 * Search global device list and return pointer to the device of type and num 784 * specified. 785 * 786 * @param type device type 787 * @param num device number 788 * @return NULL if requested device does not exist 789 */ 790 struct mtd_device *device_find(u8 type, u8 num) 791 { 792 struct list_head *entry; 793 struct mtd_device *dev_tmp; 794 795 list_for_each(entry, &devices) { 796 dev_tmp = list_entry(entry, struct mtd_device, link); 797 798 if ((dev_tmp->id->type == type) && (dev_tmp->id->num == num)) 799 return dev_tmp; 800 } 801 802 return NULL; 803 } 804 805 /** 806 * Add specified device to the global device list. 807 * 808 * @param dev device to be added 809 */ 810 static void device_add(struct mtd_device *dev) 811 { 812 u8 current_save_needed = 0; 813 814 if (list_empty(&devices)) { 815 current_mtd_dev = dev; 816 current_mtd_partnum = 0; 817 current_save_needed = 1; 818 } 819 820 list_add_tail(&dev->link, &devices); 821 822 if (current_save_needed > 0) 823 current_save(); 824 else 825 index_partitions(); 826 } 827 828 /** 829 * Parse device type, name and mtd-id. If syntax is ok allocate memory and 830 * return pointer to the device structure. 831 * 832 * @param mtd_dev pointer to the device definition string i.e. <mtd-dev> 833 * @param ret output pointer to next char after parse completes (output) 834 * @param retdev pointer to the allocated device (output) 835 * @return 0 on success, 1 otherwise 836 */ 837 static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev) 838 { 839 struct mtd_device *dev; 840 struct part_info *part; 841 struct mtdids *id; 842 const char *mtd_id; 843 unsigned int mtd_id_len; 844 const char *p; 845 const char *pend; 846 LIST_HEAD(tmp_list); 847 struct list_head *entry, *n; 848 u16 num_parts; 849 u64 offset; 850 int err = 1; 851 852 debug("===device_parse===\n"); 853 854 assert(retdev); 855 *retdev = NULL; 856 857 if (ret) 858 *ret = NULL; 859 860 /* fetch <mtd-id> */ 861 mtd_id = p = mtd_dev; 862 if (!(p = strchr(mtd_id, ':'))) { 863 printf("no <mtd-id> identifier\n"); 864 return 1; 865 } 866 mtd_id_len = p - mtd_id + 1; 867 p++; 868 869 /* verify if we have a valid device specified */ 870 if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) { 871 printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id); 872 return 1; 873 } 874 875 pend = strchr(p, ';'); 876 debug("dev type = %d (%s), dev num = %d, mtd-id = %s\n", 877 id->type, MTD_DEV_TYPE(id->type), 878 id->num, id->mtd_id); 879 debug("parsing partitions %.*s\n", (int)(pend ? pend - p : strlen(p)), p); 880 881 /* parse partitions */ 882 num_parts = 0; 883 884 offset = 0; 885 if ((dev = device_find(id->type, id->num)) != NULL) { 886 /* if device already exists start at the end of the last partition */ 887 part = list_entry(dev->parts.prev, struct part_info, link); 888 offset = part->offset + part->size; 889 } 890 891 while (p && (*p != '\0') && (*p != ';')) { 892 err = 1; 893 if ((part_parse(p, &p, &part) != 0) || (!part)) 894 break; 895 896 /* calculate offset when not specified */ 897 if (part->offset == OFFSET_NOT_SPECIFIED) 898 part->offset = offset; 899 else 900 offset = part->offset; 901 902 /* verify alignment and size */ 903 if (part_validate(id, part) != 0) 904 break; 905 906 offset += part->size; 907 908 /* partition is ok, add it to the list */ 909 list_add_tail(&part->link, &tmp_list); 910 num_parts++; 911 err = 0; 912 } 913 if (err == 1) { 914 part_delall(&tmp_list); 915 return 1; 916 } 917 918 debug("\ntotal partitions: %d\n", num_parts); 919 920 /* check for next device presence */ 921 if (p) { 922 if (*p == ';') { 923 if (ret) 924 *ret = ++p; 925 } else if (*p == '\0') { 926 if (ret) 927 *ret = p; 928 } else { 929 printf("unexpected character '%c' at the end of device\n", *p); 930 if (ret) 931 *ret = NULL; 932 return 1; 933 } 934 } 935 936 /* allocate memory for mtd_device structure */ 937 if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) { 938 printf("out of memory\n"); 939 return 1; 940 } 941 memset(dev, 0, sizeof(struct mtd_device)); 942 dev->id = id; 943 dev->num_parts = 0; /* part_sort_add increments num_parts */ 944 INIT_LIST_HEAD(&dev->parts); 945 INIT_LIST_HEAD(&dev->link); 946 947 /* move partitions from tmp_list to dev->parts */ 948 list_for_each_safe(entry, n, &tmp_list) { 949 part = list_entry(entry, struct part_info, link); 950 list_del(entry); 951 if (part_sort_add(dev, part) != 0) { 952 device_del(dev); 953 return 1; 954 } 955 } 956 957 *retdev = dev; 958 959 debug("===\n\n"); 960 return 0; 961 } 962 963 /** 964 * Initialize global device list. 965 * 966 * @return 0 on success, 1 otherwise 967 */ 968 static int mtd_devices_init(void) 969 { 970 last_parts[0] = '\0'; 971 current_mtd_dev = NULL; 972 current_save(); 973 974 return device_delall(&devices); 975 } 976 977 /* 978 * Search global mtdids list and find id of requested type and number. 979 * 980 * @return pointer to the id if it exists, NULL otherwise 981 */ 982 static struct mtdids* id_find(u8 type, u8 num) 983 { 984 struct list_head *entry; 985 struct mtdids *id; 986 987 list_for_each(entry, &mtdids) { 988 id = list_entry(entry, struct mtdids, link); 989 990 if ((id->type == type) && (id->num == num)) 991 return id; 992 } 993 994 return NULL; 995 } 996 997 /** 998 * Search global mtdids list and find id of a requested mtd_id. 999 * 1000 * Note: first argument is not null terminated. 1001 * 1002 * @param mtd_id string containing requested mtd_id 1003 * @param mtd_id_len length of supplied mtd_id 1004 * @return pointer to the id if it exists, NULL otherwise 1005 */ 1006 static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len) 1007 { 1008 struct list_head *entry; 1009 struct mtdids *id; 1010 1011 debug("--- id_find_by_mtd_id: '%.*s' (len = %d)\n", 1012 mtd_id_len, mtd_id, mtd_id_len); 1013 1014 list_for_each(entry, &mtdids) { 1015 id = list_entry(entry, struct mtdids, link); 1016 1017 debug("entry: '%s' (len = %zu)\n", 1018 id->mtd_id, strlen(id->mtd_id)); 1019 1020 if (mtd_id_len != strlen(id->mtd_id)) 1021 continue; 1022 if (strncmp(id->mtd_id, mtd_id, mtd_id_len) == 0) 1023 return id; 1024 } 1025 1026 return NULL; 1027 } 1028 1029 /** 1030 * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>, 1031 * return device type and number. 1032 * 1033 * @param id string describing device id 1034 * @param ret_id output pointer to next char after parse completes (output) 1035 * @param dev_type parsed device type (output) 1036 * @param dev_num parsed device number (output) 1037 * @return 0 on success, 1 otherwise 1038 */ 1039 int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, 1040 u8 *dev_num) 1041 { 1042 const char *p = id; 1043 1044 *dev_type = 0; 1045 if (strncmp(p, "nand", 4) == 0) { 1046 *dev_type = MTD_DEV_TYPE_NAND; 1047 p += 4; 1048 } else if (strncmp(p, "nor", 3) == 0) { 1049 *dev_type = MTD_DEV_TYPE_NOR; 1050 p += 3; 1051 } else if (strncmp(p, "onenand", 7) == 0) { 1052 *dev_type = MTD_DEV_TYPE_ONENAND; 1053 p += 7; 1054 } else { 1055 printf("incorrect device type in %s\n", id); 1056 return 1; 1057 } 1058 1059 if (!isdigit(*p)) { 1060 printf("incorrect device number in %s\n", id); 1061 return 1; 1062 } 1063 1064 *dev_num = simple_strtoul(p, (char **)&p, 0); 1065 if (ret_id) 1066 *ret_id = p; 1067 return 0; 1068 } 1069 1070 /** 1071 * Process all devices and generate corresponding mtdparts string describing 1072 * all partitions on all devices. 1073 * 1074 * @param buf output buffer holding generated mtdparts string (output) 1075 * @param buflen buffer size 1076 * @return 0 on success, 1 otherwise 1077 */ 1078 static int generate_mtdparts(char *buf, u32 buflen) 1079 { 1080 struct list_head *pentry, *dentry; 1081 struct mtd_device *dev; 1082 struct part_info *part, *prev_part; 1083 char *p = buf; 1084 char tmpbuf[32]; 1085 u64 size, offset; 1086 u32 len, part_cnt; 1087 u32 maxlen = buflen - 1; 1088 1089 debug("--- generate_mtdparts ---\n"); 1090 1091 if (list_empty(&devices)) { 1092 buf[0] = '\0'; 1093 return 0; 1094 } 1095 1096 strcpy(p, "mtdparts="); 1097 p += 9; 1098 1099 list_for_each(dentry, &devices) { 1100 dev = list_entry(dentry, struct mtd_device, link); 1101 1102 /* copy mtd_id */ 1103 len = strlen(dev->id->mtd_id) + 1; 1104 if (len > maxlen) 1105 goto cleanup; 1106 memcpy(p, dev->id->mtd_id, len - 1); 1107 p += len - 1; 1108 *(p++) = ':'; 1109 maxlen -= len; 1110 1111 /* format partitions */ 1112 prev_part = NULL; 1113 part_cnt = 0; 1114 list_for_each(pentry, &dev->parts) { 1115 part = list_entry(pentry, struct part_info, link); 1116 size = part->size; 1117 offset = part->offset; 1118 part_cnt++; 1119 1120 /* partition size */ 1121 memsize_format(tmpbuf, size); 1122 len = strlen(tmpbuf); 1123 if (len > maxlen) 1124 goto cleanup; 1125 memcpy(p, tmpbuf, len); 1126 p += len; 1127 maxlen -= len; 1128 1129 1130 /* add offset only when there is a gap between 1131 * partitions */ 1132 if ((!prev_part && (offset != 0)) || 1133 (prev_part && ((prev_part->offset + prev_part->size) != part->offset))) { 1134 1135 memsize_format(tmpbuf, offset); 1136 len = strlen(tmpbuf) + 1; 1137 if (len > maxlen) 1138 goto cleanup; 1139 *(p++) = '@'; 1140 memcpy(p, tmpbuf, len - 1); 1141 p += len - 1; 1142 maxlen -= len; 1143 } 1144 1145 /* copy name only if user supplied */ 1146 if(!part->auto_name) { 1147 len = strlen(part->name) + 2; 1148 if (len > maxlen) 1149 goto cleanup; 1150 1151 *(p++) = '('; 1152 memcpy(p, part->name, len - 2); 1153 p += len - 2; 1154 *(p++) = ')'; 1155 maxlen -= len; 1156 } 1157 1158 /* ro mask flag */ 1159 if (part->mask_flags && MTD_WRITEABLE_CMD) { 1160 len = 2; 1161 if (len > maxlen) 1162 goto cleanup; 1163 *(p++) = 'r'; 1164 *(p++) = 'o'; 1165 maxlen -= 2; 1166 } 1167 1168 /* print ',' separator if there are other partitions 1169 * following */ 1170 if (dev->num_parts > part_cnt) { 1171 if (1 > maxlen) 1172 goto cleanup; 1173 *(p++) = ','; 1174 maxlen--; 1175 } 1176 prev_part = part; 1177 } 1178 /* print ';' separator if there are other devices following */ 1179 if (dentry->next != &devices) { 1180 if (1 > maxlen) 1181 goto cleanup; 1182 *(p++) = ';'; 1183 maxlen--; 1184 } 1185 } 1186 1187 /* we still have at least one char left, as we decremented maxlen at 1188 * the begining */ 1189 *p = '\0'; 1190 1191 return 0; 1192 1193 cleanup: 1194 last_parts[0] = '\0'; 1195 return 1; 1196 } 1197 1198 /** 1199 * Call generate_mtdparts to process all devices and generate corresponding 1200 * mtdparts string, save it in mtdparts environment variable. 1201 * 1202 * @param buf output buffer holding generated mtdparts string (output) 1203 * @param buflen buffer size 1204 * @return 0 on success, 1 otherwise 1205 */ 1206 static int generate_mtdparts_save(char *buf, u32 buflen) 1207 { 1208 int ret; 1209 1210 ret = generate_mtdparts(buf, buflen); 1211 1212 if ((buf[0] != '\0') && (ret == 0)) 1213 env_set("mtdparts", buf); 1214 else 1215 env_set("mtdparts", NULL); 1216 1217 return ret; 1218 } 1219 1220 #if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) 1221 /** 1222 * Get the net size (w/o bad blocks) of the given partition. 1223 * 1224 * @param mtd the mtd info 1225 * @param part the partition 1226 * @return the calculated net size of this partition 1227 */ 1228 static uint64_t net_part_size(struct mtd_info *mtd, struct part_info *part) 1229 { 1230 uint64_t i, net_size = 0; 1231 1232 if (!mtd->block_isbad) 1233 return part->size; 1234 1235 for (i = 0; i < part->size; i += mtd->erasesize) { 1236 if (!mtd->block_isbad(mtd, part->offset + i)) 1237 net_size += mtd->erasesize; 1238 } 1239 1240 return net_size; 1241 } 1242 #endif 1243 1244 static void print_partition_table(void) 1245 { 1246 struct list_head *dentry, *pentry; 1247 struct part_info *part; 1248 struct mtd_device *dev; 1249 int part_num; 1250 1251 list_for_each(dentry, &devices) { 1252 dev = list_entry(dentry, struct mtd_device, link); 1253 /* list partitions for given device */ 1254 part_num = 0; 1255 #if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) 1256 struct mtd_info *mtd; 1257 1258 if (get_mtd_info(dev->id->type, dev->id->num, &mtd)) 1259 return; 1260 1261 printf("\ndevice %s%d <%s>, # parts = %d\n", 1262 MTD_DEV_TYPE(dev->id->type), dev->id->num, 1263 dev->id->mtd_id, dev->num_parts); 1264 printf(" #: name\t\tsize\t\tnet size\toffset\t\tmask_flags\n"); 1265 1266 list_for_each(pentry, &dev->parts) { 1267 u32 net_size; 1268 char *size_note; 1269 1270 part = list_entry(pentry, struct part_info, link); 1271 net_size = net_part_size(mtd, part); 1272 size_note = part->size == net_size ? " " : " (!)"; 1273 printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n", 1274 part_num, part->name, part->size, 1275 net_size, size_note, part->offset, 1276 part->mask_flags); 1277 #else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */ 1278 printf("\ndevice %s%d <%s>, # parts = %d\n", 1279 MTD_DEV_TYPE(dev->id->type), dev->id->num, 1280 dev->id->mtd_id, dev->num_parts); 1281 printf(" #: name\t\tsize\t\toffset\t\tmask_flags\n"); 1282 1283 list_for_each(pentry, &dev->parts) { 1284 part = list_entry(pentry, struct part_info, link); 1285 printf("%2d: %-20s0x%08llx\t0x%08llx\t%d\n", 1286 part_num, part->name, part->size, 1287 part->offset, part->mask_flags); 1288 #endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */ 1289 part_num++; 1290 } 1291 } 1292 1293 if (list_empty(&devices)) 1294 printf("no partitions defined\n"); 1295 } 1296 1297 /** 1298 * Format and print out a partition list for each device from global device 1299 * list. 1300 */ 1301 static void list_partitions(void) 1302 { 1303 struct part_info *part; 1304 1305 debug("\n---list_partitions---\n"); 1306 print_partition_table(); 1307 1308 /* current_mtd_dev is not NULL only when we have non empty device list */ 1309 if (current_mtd_dev) { 1310 part = mtd_part_info(current_mtd_dev, current_mtd_partnum); 1311 if (part) { 1312 printf("\nactive partition: %s%d,%d - (%s) 0x%08llx @ 0x%08llx\n", 1313 MTD_DEV_TYPE(current_mtd_dev->id->type), 1314 current_mtd_dev->id->num, current_mtd_partnum, 1315 part->name, part->size, part->offset); 1316 } else { 1317 printf("could not get current partition info\n\n"); 1318 } 1319 } 1320 1321 printf("\ndefaults:\n"); 1322 printf("mtdids : %s\n", 1323 mtdids_default ? mtdids_default : "none"); 1324 /* 1325 * Using printf() here results in printbuffer overflow 1326 * if default mtdparts string is greater than console 1327 * printbuffer. Use puts() to prevent system crashes. 1328 */ 1329 puts("mtdparts: "); 1330 puts(mtdparts_default ? mtdparts_default : "none"); 1331 puts("\n"); 1332 } 1333 1334 /** 1335 * Given partition identifier in form of <dev_type><dev_num>,<part_num> find 1336 * corresponding device and verify partition number. 1337 * 1338 * @param id string describing device and partition or partition name 1339 * @param dev pointer to the requested device (output) 1340 * @param part_num verified partition number (output) 1341 * @param part pointer to requested partition (output) 1342 * @return 0 on success, 1 otherwise 1343 */ 1344 int find_dev_and_part(const char *id, struct mtd_device **dev, 1345 u8 *part_num, struct part_info **part) 1346 { 1347 struct list_head *dentry, *pentry; 1348 u8 type, dnum, pnum; 1349 const char *p; 1350 1351 debug("--- find_dev_and_part ---\nid = %s\n", id); 1352 1353 list_for_each(dentry, &devices) { 1354 *part_num = 0; 1355 *dev = list_entry(dentry, struct mtd_device, link); 1356 list_for_each(pentry, &(*dev)->parts) { 1357 *part = list_entry(pentry, struct part_info, link); 1358 if (strcmp((*part)->name, id) == 0) 1359 return 0; 1360 (*part_num)++; 1361 } 1362 } 1363 1364 p = id; 1365 *dev = NULL; 1366 *part = NULL; 1367 *part_num = 0; 1368 1369 if (mtd_id_parse(p, &p, &type, &dnum) != 0) 1370 return 1; 1371 1372 if ((*p++ != ',') || (*p == '\0')) { 1373 printf("no partition number specified\n"); 1374 return 1; 1375 } 1376 pnum = simple_strtoul(p, (char **)&p, 0); 1377 if (*p != '\0') { 1378 printf("unexpected trailing character '%c'\n", *p); 1379 return 1; 1380 } 1381 1382 if ((*dev = device_find(type, dnum)) == NULL) { 1383 printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum); 1384 return 1; 1385 } 1386 1387 if ((*part = mtd_part_info(*dev, pnum)) == NULL) { 1388 printf("no such partition\n"); 1389 *dev = NULL; 1390 return 1; 1391 } 1392 1393 *part_num = pnum; 1394 1395 return 0; 1396 } 1397 1398 /** 1399 * Find and delete partition. For partition id format see find_dev_and_part(). 1400 * 1401 * @param id string describing device and partition 1402 * @return 0 on success, 1 otherwise 1403 */ 1404 static int delete_partition(const char *id) 1405 { 1406 u8 pnum; 1407 struct mtd_device *dev; 1408 struct part_info *part; 1409 1410 if (find_dev_and_part(id, &dev, &pnum, &part) == 0) { 1411 1412 debug("delete_partition: device = %s%d, partition %d = (%s) 0x%08llx@0x%08llx\n", 1413 MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum, 1414 part->name, part->size, part->offset); 1415 1416 if (part_del(dev, part) != 0) 1417 return 1; 1418 1419 if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { 1420 printf("generated mtdparts too long, resetting to null\n"); 1421 return 1; 1422 } 1423 return 0; 1424 } 1425 1426 printf("partition %s not found\n", id); 1427 return 1; 1428 } 1429 1430 #if defined(CONFIG_CMD_MTDPARTS_SPREAD) 1431 /** 1432 * Increase the size of the given partition so that it's net size is at least 1433 * as large as the size member and such that the next partition would start on a 1434 * good block if it were adjacent to this partition. 1435 * 1436 * @param mtd the mtd device 1437 * @param part the partition 1438 * @param next_offset pointer to the offset of the next partition after this 1439 * partition's size has been modified (output) 1440 */ 1441 static void spread_partition(struct mtd_info *mtd, struct part_info *part, 1442 uint64_t *next_offset) 1443 { 1444 uint64_t net_size, padding_size = 0; 1445 int truncated; 1446 1447 mtd_get_len_incl_bad(mtd, part->offset, part->size, &net_size, 1448 &truncated); 1449 1450 /* 1451 * Absorb bad blocks immediately following this 1452 * partition also into the partition, such that 1453 * the next partition starts with a good block. 1454 */ 1455 if (!truncated) { 1456 mtd_get_len_incl_bad(mtd, part->offset + net_size, 1457 mtd->erasesize, &padding_size, &truncated); 1458 if (truncated) 1459 padding_size = 0; 1460 else 1461 padding_size -= mtd->erasesize; 1462 } 1463 1464 if (truncated) { 1465 printf("truncated partition %s to %lld bytes\n", part->name, 1466 (uint64_t) net_size + padding_size); 1467 } 1468 1469 part->size = net_size + padding_size; 1470 *next_offset = part->offset + part->size; 1471 } 1472 1473 /** 1474 * Adjust all of the partition sizes, such that all partitions are at least 1475 * as big as their mtdparts environment variable sizes and they each start 1476 * on a good block. 1477 * 1478 * @return 0 on success, 1 otherwise 1479 */ 1480 static int spread_partitions(void) 1481 { 1482 struct list_head *dentry, *pentry; 1483 struct mtd_device *dev; 1484 struct part_info *part; 1485 struct mtd_info *mtd; 1486 int part_num; 1487 uint64_t cur_offs; 1488 1489 list_for_each(dentry, &devices) { 1490 dev = list_entry(dentry, struct mtd_device, link); 1491 1492 if (get_mtd_info(dev->id->type, dev->id->num, &mtd)) 1493 return 1; 1494 1495 part_num = 0; 1496 cur_offs = 0; 1497 list_for_each(pentry, &dev->parts) { 1498 part = list_entry(pentry, struct part_info, link); 1499 1500 debug("spread_partitions: device = %s%d, partition %d =" 1501 " (%s) 0x%08llx@0x%08llx\n", 1502 MTD_DEV_TYPE(dev->id->type), dev->id->num, 1503 part_num, part->name, part->size, 1504 part->offset); 1505 1506 if (cur_offs > part->offset) 1507 part->offset = cur_offs; 1508 1509 spread_partition(mtd, part, &cur_offs); 1510 1511 part_num++; 1512 } 1513 } 1514 1515 index_partitions(); 1516 1517 if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { 1518 printf("generated mtdparts too long, resetting to null\n"); 1519 return 1; 1520 } 1521 return 0; 1522 } 1523 #endif /* CONFIG_CMD_MTDPARTS_SPREAD */ 1524 1525 /** 1526 * The mtdparts variable tends to be long. If we need to access it 1527 * before the env is relocated, then we need to use our own stack 1528 * buffer. gd->env_buf will be too small. 1529 * 1530 * @param buf temporary buffer pointer MTDPARTS_MAXLEN long 1531 * @return mtdparts variable string, NULL if not found 1532 */ 1533 static const char *env_get_mtdparts(char *buf) 1534 { 1535 if (gd->flags & GD_FLG_ENV_READY) 1536 return env_get("mtdparts"); 1537 if (env_get_f("mtdparts", buf, MTDPARTS_MAXLEN) != -1) 1538 return buf; 1539 return NULL; 1540 } 1541 1542 /** 1543 * Accept character string describing mtd partitions and call device_parse() 1544 * for each entry. Add created devices to the global devices list. 1545 * 1546 * @param mtdparts string specifing mtd partitions 1547 * @return 0 on success, 1 otherwise 1548 */ 1549 static int parse_mtdparts(const char *const mtdparts) 1550 { 1551 const char *p; 1552 struct mtd_device *dev; 1553 int err = 1; 1554 char tmp_parts[MTDPARTS_MAXLEN]; 1555 1556 debug("\n---parse_mtdparts---\nmtdparts = %s\n\n", mtdparts); 1557 1558 /* delete all devices and partitions */ 1559 if (mtd_devices_init() != 0) { 1560 printf("could not initialise device list\n"); 1561 return err; 1562 } 1563 1564 /* re-read 'mtdparts' variable, mtd_devices_init may be updating env */ 1565 p = env_get_mtdparts(tmp_parts); 1566 if (!p) 1567 p = mtdparts; 1568 1569 if (strncmp(p, "mtdparts=", 9) != 0) { 1570 printf("mtdparts variable doesn't start with 'mtdparts='\n"); 1571 return err; 1572 } 1573 p += 9; 1574 1575 while (*p != '\0') { 1576 err = 1; 1577 if ((device_parse(p, &p, &dev) != 0) || (!dev)) 1578 break; 1579 1580 debug("+ device: %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type), 1581 dev->id->num, dev->id->mtd_id); 1582 1583 /* check if parsed device is already on the list */ 1584 if (device_find(dev->id->type, dev->id->num) != NULL) { 1585 printf("device %s%d redefined, please correct mtdparts variable\n", 1586 MTD_DEV_TYPE(dev->id->type), dev->id->num); 1587 break; 1588 } 1589 1590 list_add_tail(&dev->link, &devices); 1591 err = 0; 1592 } 1593 if (err == 1) { 1594 free(dev); 1595 device_delall(&devices); 1596 } 1597 1598 return err; 1599 } 1600 1601 /** 1602 * Parse provided string describing mtdids mapping (see file header for mtdids 1603 * variable format). Allocate memory for each entry and add all found entries 1604 * to the global mtdids list. 1605 * 1606 * @param ids mapping string 1607 * @return 0 on success, 1 otherwise 1608 */ 1609 static int parse_mtdids(const char *const ids) 1610 { 1611 const char *p = ids; 1612 const char *mtd_id; 1613 int mtd_id_len; 1614 struct mtdids *id; 1615 struct list_head *entry, *n; 1616 struct mtdids *id_tmp; 1617 u8 type, num; 1618 u64 size; 1619 int ret = 1; 1620 1621 debug("\n---parse_mtdids---\nmtdids = %s\n\n", ids); 1622 1623 /* clean global mtdids list */ 1624 list_for_each_safe(entry, n, &mtdids) { 1625 id_tmp = list_entry(entry, struct mtdids, link); 1626 debug("mtdids del: %d %d\n", id_tmp->type, id_tmp->num); 1627 list_del(entry); 1628 free(id_tmp); 1629 } 1630 last_ids[0] = '\0'; 1631 INIT_LIST_HEAD(&mtdids); 1632 1633 while(p && (*p != '\0')) { 1634 1635 ret = 1; 1636 /* parse 'nor'|'nand'|'onenand'<dev-num> */ 1637 if (mtd_id_parse(p, &p, &type, &num) != 0) 1638 break; 1639 1640 if (*p != '=') { 1641 printf("mtdids: incorrect <dev-num>\n"); 1642 break; 1643 } 1644 p++; 1645 1646 /* check if requested device exists */ 1647 if (mtd_device_validate(type, num, &size) != 0) 1648 return 1; 1649 1650 /* locate <mtd-id> */ 1651 mtd_id = p; 1652 if ((p = strchr(mtd_id, ',')) != NULL) { 1653 mtd_id_len = p - mtd_id + 1; 1654 p++; 1655 } else { 1656 mtd_id_len = strlen(mtd_id) + 1; 1657 } 1658 if (mtd_id_len == 0) { 1659 printf("mtdids: no <mtd-id> identifier\n"); 1660 break; 1661 } 1662 1663 /* check if this id is already on the list */ 1664 int double_entry = 0; 1665 list_for_each(entry, &mtdids) { 1666 id_tmp = list_entry(entry, struct mtdids, link); 1667 if ((id_tmp->type == type) && (id_tmp->num == num)) { 1668 double_entry = 1; 1669 break; 1670 } 1671 } 1672 if (double_entry) { 1673 printf("device id %s%d redefined, please correct mtdids variable\n", 1674 MTD_DEV_TYPE(type), num); 1675 break; 1676 } 1677 1678 /* allocate mtdids structure */ 1679 if (!(id = (struct mtdids *)malloc(sizeof(struct mtdids) + mtd_id_len))) { 1680 printf("out of memory\n"); 1681 break; 1682 } 1683 memset(id, 0, sizeof(struct mtdids) + mtd_id_len); 1684 id->num = num; 1685 id->type = type; 1686 id->size = size; 1687 id->mtd_id = (char *)(id + 1); 1688 strncpy(id->mtd_id, mtd_id, mtd_id_len - 1); 1689 id->mtd_id[mtd_id_len - 1] = '\0'; 1690 INIT_LIST_HEAD(&id->link); 1691 1692 debug("+ id %s%d\t%16lld bytes\t%s\n", 1693 MTD_DEV_TYPE(id->type), id->num, 1694 id->size, id->mtd_id); 1695 1696 list_add_tail(&id->link, &mtdids); 1697 ret = 0; 1698 } 1699 if (ret == 1) { 1700 /* clean mtdids list and free allocated memory */ 1701 list_for_each_safe(entry, n, &mtdids) { 1702 id_tmp = list_entry(entry, struct mtdids, link); 1703 list_del(entry); 1704 free(id_tmp); 1705 } 1706 return 1; 1707 } 1708 1709 return 0; 1710 } 1711 1712 1713 /** 1714 * Parse and initialize global mtdids mapping and create global 1715 * device/partition list. 1716 * 1717 * @return 0 on success, 1 otherwise 1718 */ 1719 int mtdparts_init(void) 1720 { 1721 static int initialized = 0; 1722 const char *ids, *parts; 1723 const char *current_partition; 1724 int ids_changed; 1725 char tmp_ep[PARTITION_MAXLEN + 1]; 1726 char tmp_parts[MTDPARTS_MAXLEN]; 1727 1728 debug("\n---mtdparts_init---\n"); 1729 if (!initialized) { 1730 INIT_LIST_HEAD(&mtdids); 1731 INIT_LIST_HEAD(&devices); 1732 memset(last_ids, 0, sizeof(last_ids)); 1733 memset(last_parts, 0, sizeof(last_parts)); 1734 memset(last_partition, 0, sizeof(last_partition)); 1735 #if defined(CONFIG_SYS_MTDPARTS_RUNTIME) 1736 board_mtdparts_default(&mtdids_default, &mtdparts_default); 1737 #endif 1738 use_defaults = 1; 1739 initialized = 1; 1740 } 1741 1742 /* get variables */ 1743 ids = env_get("mtdids"); 1744 parts = env_get_mtdparts(tmp_parts); 1745 current_partition = env_get("partition"); 1746 1747 /* save it for later parsing, cannot rely on current partition pointer 1748 * as 'partition' variable may be updated during init */ 1749 memset(tmp_parts, 0, sizeof(tmp_parts)); 1750 memset(tmp_ep, 0, sizeof(tmp_ep)); 1751 if (current_partition) 1752 strncpy(tmp_ep, current_partition, PARTITION_MAXLEN); 1753 1754 debug("last_ids : %s\n", last_ids); 1755 debug("env_ids : %s\n", ids); 1756 debug("last_parts: %s\n", last_parts); 1757 debug("env_parts : %s\n\n", parts); 1758 1759 debug("last_partition : %s\n", last_partition); 1760 debug("env_partition : %s\n", current_partition); 1761 1762 /* if mtdids variable is empty try to use defaults */ 1763 if (!ids) { 1764 if (mtdids_default) { 1765 debug("mtdids variable not defined, using default\n"); 1766 ids = mtdids_default; 1767 env_set("mtdids", (char *)ids); 1768 } else { 1769 printf("mtdids not defined, no default present\n"); 1770 return 1; 1771 } 1772 } 1773 if (strlen(ids) > MTDIDS_MAXLEN - 1) { 1774 printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN); 1775 return 1; 1776 } 1777 1778 /* use defaults when mtdparts variable is not defined 1779 * once mtdparts is saved environment, drop use_defaults flag */ 1780 if (!parts) { 1781 if (mtdparts_default && use_defaults) { 1782 parts = mtdparts_default; 1783 if (env_set("mtdparts", (char *)parts) == 0) 1784 use_defaults = 0; 1785 } else 1786 printf("mtdparts variable not set, see 'help mtdparts'\n"); 1787 } 1788 1789 if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) { 1790 printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN); 1791 return 1; 1792 } 1793 1794 /* check if we have already parsed those mtdids */ 1795 if ((last_ids[0] != '\0') && (strcmp(last_ids, ids) == 0)) { 1796 ids_changed = 0; 1797 } else { 1798 ids_changed = 1; 1799 1800 if (parse_mtdids(ids) != 0) { 1801 mtd_devices_init(); 1802 return 1; 1803 } 1804 1805 /* ok it's good, save new ids */ 1806 strncpy(last_ids, ids, MTDIDS_MAXLEN); 1807 } 1808 1809 /* parse partitions if either mtdparts or mtdids were updated */ 1810 if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) { 1811 if (parse_mtdparts(parts) != 0) 1812 return 1; 1813 1814 if (list_empty(&devices)) { 1815 printf("mtdparts_init: no valid partitions\n"); 1816 return 1; 1817 } 1818 1819 /* ok it's good, save new parts */ 1820 strncpy(last_parts, parts, MTDPARTS_MAXLEN); 1821 1822 /* reset first partition from first dev from the list as current */ 1823 current_mtd_dev = list_entry(devices.next, struct mtd_device, link); 1824 current_mtd_partnum = 0; 1825 current_save(); 1826 1827 debug("mtdparts_init: current_mtd_dev = %s%d, current_mtd_partnum = %d\n", 1828 MTD_DEV_TYPE(current_mtd_dev->id->type), 1829 current_mtd_dev->id->num, current_mtd_partnum); 1830 } 1831 1832 /* mtdparts variable was reset to NULL, delete all devices/partitions */ 1833 if (!parts && (last_parts[0] != '\0')) 1834 return mtd_devices_init(); 1835 1836 /* do not process current partition if mtdparts variable is null */ 1837 if (!parts) 1838 return 0; 1839 1840 /* is current partition set in environment? if so, use it */ 1841 if ((tmp_ep[0] != '\0') && (strcmp(tmp_ep, last_partition) != 0)) { 1842 struct part_info *p; 1843 struct mtd_device *cdev; 1844 u8 pnum; 1845 1846 debug("--- getting current partition: %s\n", tmp_ep); 1847 1848 if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) { 1849 current_mtd_dev = cdev; 1850 current_mtd_partnum = pnum; 1851 current_save(); 1852 } 1853 } else if (env_get("partition") == NULL) { 1854 debug("no partition variable set, setting...\n"); 1855 current_save(); 1856 } 1857 1858 return 0; 1859 } 1860 1861 /** 1862 * Return pointer to the partition of a requested number from a requested 1863 * device. 1864 * 1865 * @param dev device that is to be searched for a partition 1866 * @param part_num requested partition number 1867 * @return pointer to the part_info, NULL otherwise 1868 */ 1869 static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part_num) 1870 { 1871 struct list_head *entry; 1872 struct part_info *part; 1873 int num; 1874 1875 if (!dev) 1876 return NULL; 1877 1878 debug("\n--- mtd_part_info: partition number %d for device %s%d (%s)\n", 1879 part_num, MTD_DEV_TYPE(dev->id->type), 1880 dev->id->num, dev->id->mtd_id); 1881 1882 if (part_num >= dev->num_parts) { 1883 printf("invalid partition number %d for device %s%d (%s)\n", 1884 part_num, MTD_DEV_TYPE(dev->id->type), 1885 dev->id->num, dev->id->mtd_id); 1886 return NULL; 1887 } 1888 1889 /* locate partition number, return it */ 1890 num = 0; 1891 list_for_each(entry, &dev->parts) { 1892 part = list_entry(entry, struct part_info, link); 1893 1894 if (part_num == num++) { 1895 return part; 1896 } 1897 } 1898 1899 return NULL; 1900 } 1901 1902 /***************************************************/ 1903 /* U-Boot commands */ 1904 /***************************************************/ 1905 /* command line only */ 1906 /** 1907 * Routine implementing u-boot chpart command. Sets new current partition based 1908 * on the user supplied partition id. For partition id format see find_dev_and_part(). 1909 * 1910 * @param cmdtp command internal data 1911 * @param flag command flag 1912 * @param argc number of arguments supplied to the command 1913 * @param argv arguments list 1914 * @return 0 on success, 1 otherwise 1915 */ 1916 static int do_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 1917 { 1918 /* command line only */ 1919 struct mtd_device *dev; 1920 struct part_info *part; 1921 u8 pnum; 1922 1923 if (mtdparts_init() !=0) 1924 return 1; 1925 1926 if (argc < 2) { 1927 printf("no partition id specified\n"); 1928 return 1; 1929 } 1930 1931 if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0) 1932 return 1; 1933 1934 current_mtd_dev = dev; 1935 current_mtd_partnum = pnum; 1936 current_save(); 1937 1938 printf("partition changed to %s%d,%d\n", 1939 MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum); 1940 1941 return 0; 1942 } 1943 1944 /** 1945 * Routine implementing u-boot mtdparts command. Initialize/update default global 1946 * partition list and process user partition request (list, add, del). 1947 * 1948 * @param cmdtp command internal data 1949 * @param flag command flag 1950 * @param argc number of arguments supplied to the command 1951 * @param argv arguments list 1952 * @return 0 on success, 1 otherwise 1953 */ 1954 static int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, 1955 char * const argv[]) 1956 { 1957 if (argc == 2) { 1958 if (strcmp(argv[1], "default") == 0) { 1959 env_set("mtdids", NULL); 1960 env_set("mtdparts", NULL); 1961 env_set("partition", NULL); 1962 use_defaults = 1; 1963 1964 mtdparts_init(); 1965 return 0; 1966 } else if (strcmp(argv[1], "delall") == 0) { 1967 /* this may be the first run, initialize lists if needed */ 1968 mtdparts_init(); 1969 1970 env_set("mtdparts", NULL); 1971 1972 /* mtd_devices_init() calls current_save() */ 1973 return mtd_devices_init(); 1974 } 1975 } 1976 1977 /* make sure we are in sync with env variables */ 1978 if (mtdparts_init() != 0) 1979 return 1; 1980 1981 if (argc == 1) { 1982 list_partitions(); 1983 return 0; 1984 } 1985 1986 /* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */ 1987 if (((argc == 5) || (argc == 6)) && (strncmp(argv[1], "add", 3) == 0)) { 1988 #define PART_ADD_DESC_MAXLEN 64 1989 char tmpbuf[PART_ADD_DESC_MAXLEN]; 1990 #if defined(CONFIG_CMD_MTDPARTS_SPREAD) 1991 struct mtd_info *mtd; 1992 uint64_t next_offset; 1993 #endif 1994 u8 type, num, len; 1995 struct mtd_device *dev; 1996 struct mtd_device *dev_tmp; 1997 struct mtdids *id; 1998 struct part_info *p; 1999 2000 if (mtd_id_parse(argv[2], NULL, &type, &num) != 0) 2001 return 1; 2002 2003 if ((id = id_find(type, num)) == NULL) { 2004 printf("no such device %s defined in mtdids variable\n", argv[2]); 2005 return 1; 2006 } 2007 2008 len = strlen(id->mtd_id) + 1; /* 'mtd_id:' */ 2009 len += strlen(argv[3]); /* size@offset */ 2010 len += strlen(argv[4]) + 2; /* '(' name ')' */ 2011 if (argv[5] && (strlen(argv[5]) == 2)) 2012 len += 2; /* 'ro' */ 2013 2014 if (len >= PART_ADD_DESC_MAXLEN) { 2015 printf("too long partition description\n"); 2016 return 1; 2017 } 2018 sprintf(tmpbuf, "%s:%s(%s)%s", 2019 id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : ""); 2020 debug("add tmpbuf: %s\n", tmpbuf); 2021 2022 if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev)) 2023 return 1; 2024 2025 debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type), 2026 dev->id->num, dev->id->mtd_id); 2027 2028 p = list_entry(dev->parts.next, struct part_info, link); 2029 2030 #if defined(CONFIG_CMD_MTDPARTS_SPREAD) 2031 if (get_mtd_info(dev->id->type, dev->id->num, &mtd)) 2032 return 1; 2033 2034 if (!strcmp(&argv[1][3], ".spread")) { 2035 spread_partition(mtd, p, &next_offset); 2036 debug("increased %s to %llu bytes\n", p->name, p->size); 2037 } 2038 #endif 2039 2040 dev_tmp = device_find(dev->id->type, dev->id->num); 2041 if (dev_tmp == NULL) { 2042 device_add(dev); 2043 } else if (part_add(dev_tmp, p) != 0) { 2044 /* merge new partition with existing ones*/ 2045 device_del(dev); 2046 return 1; 2047 } 2048 2049 if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { 2050 printf("generated mtdparts too long, resetting to null\n"); 2051 return 1; 2052 } 2053 2054 return 0; 2055 } 2056 2057 /* mtdparts del part-id */ 2058 if ((argc == 3) && (strcmp(argv[1], "del") == 0)) { 2059 debug("del: part-id = %s\n", argv[2]); 2060 2061 return delete_partition(argv[2]); 2062 } 2063 2064 #if defined(CONFIG_CMD_MTDPARTS_SPREAD) 2065 if ((argc == 2) && (strcmp(argv[1], "spread") == 0)) 2066 return spread_partitions(); 2067 #endif /* CONFIG_CMD_MTDPARTS_SPREAD */ 2068 2069 return CMD_RET_USAGE; 2070 } 2071 2072 /***************************************************/ 2073 U_BOOT_CMD( 2074 chpart, 2, 0, do_chpart, 2075 "change active partition", 2076 "part-id\n" 2077 " - change active partition (e.g. part-id = nand0,1)" 2078 ); 2079 2080 #ifdef CONFIG_SYS_LONGHELP 2081 static char mtdparts_help_text[] = 2082 "\n" 2083 " - list partition table\n" 2084 "mtdparts delall\n" 2085 " - delete all partitions\n" 2086 "mtdparts del part-id\n" 2087 " - delete partition (e.g. part-id = nand0,1)\n" 2088 "mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n" 2089 " - add partition\n" 2090 #if defined(CONFIG_CMD_MTDPARTS_SPREAD) 2091 "mtdparts add.spread <mtd-dev> <size>[@<offset>] [<name>] [ro]\n" 2092 " - add partition, padding size by skipping bad blocks\n" 2093 #endif 2094 "mtdparts default\n" 2095 " - reset partition table to defaults\n" 2096 #if defined(CONFIG_CMD_MTDPARTS_SPREAD) 2097 "mtdparts spread\n" 2098 " - adjust the sizes of the partitions so they are\n" 2099 " at least as big as the mtdparts variable specifies\n" 2100 " and they each start on a good block\n\n" 2101 #else 2102 "\n" 2103 #endif /* CONFIG_CMD_MTDPARTS_SPREAD */ 2104 "-----\n\n" 2105 "this command uses three environment variables:\n\n" 2106 "'partition' - keeps current partition identifier\n\n" 2107 "partition := <part-id>\n" 2108 "<part-id> := <dev-id>,part_num\n\n" 2109 "'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n" 2110 "mtdids=<idmap>[,<idmap>,...]\n\n" 2111 "<idmap> := <dev-id>=<mtd-id>\n" 2112 "<dev-id> := 'nand'|'nor'|'onenand'<dev-num>\n" 2113 "<dev-num> := mtd device number, 0...\n" 2114 "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n" 2115 "'mtdparts' - partition list\n\n" 2116 "mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]\n\n" 2117 "<mtd-def> := <mtd-id>:<part-def>[,<part-def>...]\n" 2118 "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n" 2119 "<part-def> := <size>[@<offset>][<name>][<ro-flag>]\n" 2120 "<size> := standard linux memsize OR '-' to denote all remaining space\n" 2121 "<offset> := partition start offset within the device\n" 2122 "<name> := '(' NAME ')'\n" 2123 "<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)"; 2124 #endif 2125 2126 U_BOOT_CMD( 2127 mtdparts, 6, 0, do_mtdparts, 2128 "define flash/nand partitions", mtdparts_help_text 2129 ); 2130 /***************************************************/ 2131