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