1/* 2 * Unsorted Block Image commands 3 * 4 * Copyright (C) 2008 Samsung Electronics 5 * Kyungmin Park <kyungmin.park@samsung.com> 6 * 7 * Copyright 2008-2009 Stefan Roese <sr@denx.de>, DENX Software Engineering 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 14#include <common.h> 15#include <command.h> 16#include <env.h> 17#include <exports.h> 18#include <malloc.h> 19#include <memalign.h> 20#include <mtd.h> 21#include <nand.h> 22#include <onenand_uboot.h> 23#include <dm/devres.h> 24#include <linux/mtd/mtd.h> 25#include <linux/mtd/partitions.h> 26#include <linux/err.h> 27#include <ubi_uboot.h> 28#include <linux/errno.h> 29#include <jffs2/load_kernel.h> 30#include <linux/log2.h> 31 32#undef ubi_msg 33#define ubi_msg(fmt, ...) printf("UBI: " fmt "\n", ##__VA_ARGS__) 34 35/* Private own data */ 36static struct ubi_device *ubi; 37 38#ifdef CONFIG_CMD_UBIFS 39#include <ubifs_uboot.h> 40#endif 41 42static void display_volume_info(struct ubi_device *ubi) 43{ 44 int i; 45 46 for (i = 0; i < (ubi->vtbl_slots + 1); i++) { 47 if (!ubi->volumes[i]) 48 continue; /* Empty record */ 49 ubi_dump_vol_info(ubi->volumes[i]); 50 } 51} 52 53static void display_ubi_info(struct ubi_device *ubi) 54{ 55 ubi_msg("MTD device name: \"%s\"", ubi->mtd->name); 56 ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); 57 ubi_msg("physical eraseblock size: %d bytes (%d KiB)", 58 ubi->peb_size, ubi->peb_size >> 10); 59 ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); 60 ubi_msg("number of good PEBs: %d", ubi->good_peb_count); 61 ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count); 62 ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); 63 ubi_msg("VID header offset: %d (aligned %d)", 64 ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); 65 ubi_msg("data offset: %d", ubi->leb_start); 66 ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots); 67 ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD); 68 ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT); 69 ubi_msg("number of user volumes: %d", 70 ubi->vol_count - UBI_INT_VOL_COUNT); 71 ubi_msg("available PEBs: %d", ubi->avail_pebs); 72 ubi_msg("total number of reserved PEBs: %d", ubi->rsvd_pebs); 73 ubi_msg("number of PEBs reserved for bad PEB handling: %d", 74 ubi->beb_rsvd_pebs); 75 ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec); 76} 77 78static int ubi_info(int layout) 79{ 80 if (layout) 81 display_volume_info(ubi); 82 else 83 display_ubi_info(ubi); 84 85 return 0; 86} 87 88static int ubi_list(const char *var, int numeric) 89{ 90 size_t namelen, len, size; 91 char *str, *str2; 92 int i; 93 94 if (!var) { 95 for (i = 0; i < (ubi->vtbl_slots + 1); i++) { 96 if (!ubi->volumes[i]) 97 continue; 98 if (ubi->volumes[i]->vol_id >= UBI_INTERNAL_VOL_START) 99 continue; 100 printf("%d: %s\n", 101 ubi->volumes[i]->vol_id, 102 ubi->volumes[i]->name); 103 } 104 return 0; 105 } 106 107 len = 0; 108 size = 16; 109 str = malloc(size); 110 if (!str) 111 return 1; 112 113 for (i = 0; i < (ubi->vtbl_slots + 1); i++) { 114 if (!ubi->volumes[i]) 115 continue; 116 if (ubi->volumes[i]->vol_id >= UBI_INTERNAL_VOL_START) 117 continue; 118 119 if (numeric) 120 namelen = 10; /* strlen(stringify(INT_MAX)) */ 121 else 122 namelen = strlen(ubi->volumes[i]->name); 123 124 if (len + namelen + 1 > size) { 125 size = roundup_pow_of_two(len + namelen + 1) * 2; 126 str2 = realloc(str, size); 127 if (!str2) { 128 free(str); 129 return 1; 130 } 131 str = str2; 132 } 133 134 if (len) 135 str[len++] = ' '; 136 137 if (numeric) { 138 len += sprintf(str + len, "%d", ubi->volumes[i]->vol_id) + 1; 139 } else { 140 memcpy(str + len, ubi->volumes[i]->name, namelen); 141 len += namelen; 142 str[len] = 0; 143 } 144 } 145 146 env_set(var, str); 147 free(str); 148 149 return 0; 150} 151 152static int ubi_check_volumename(const struct ubi_volume *vol, char *name) 153{ 154 return strcmp(vol->name, name); 155} 156 157static int ubi_check(char *name) 158{ 159 int i; 160 161 for (i = 0; i < (ubi->vtbl_slots + 1); i++) { 162 if (!ubi->volumes[i]) 163 continue; /* Empty record */ 164 165 if (!ubi_check_volumename(ubi->volumes[i], name)) 166 return 0; 167 } 168 169 return 1; 170} 171 172static int verify_mkvol_req(const struct ubi_device *ubi, 173 const struct ubi_mkvol_req *req) 174{ 175 int n, err = EINVAL; 176 177 if (req->bytes < 0 || req->alignment < 0 || req->vol_type < 0 || 178 req->name_len < 0) 179 goto bad; 180 181 if ((req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) && 182 req->vol_id != UBI_VOL_NUM_AUTO) 183 goto bad; 184 185 if (req->alignment == 0) 186 goto bad; 187 188 if (req->bytes == 0) { 189 printf("No space left in UBI device!\n"); 190 err = ENOMEM; 191 goto bad; 192 } 193 194 if (req->vol_type != UBI_DYNAMIC_VOLUME && 195 req->vol_type != UBI_STATIC_VOLUME) 196 goto bad; 197 198 if (req->alignment > ubi->leb_size) 199 goto bad; 200 201 n = req->alignment % ubi->min_io_size; 202 if (req->alignment != 1 && n) 203 goto bad; 204 205 if (req->name_len > UBI_VOL_NAME_MAX) { 206 printf("Name too long!\n"); 207 err = ENAMETOOLONG; 208 goto bad; 209 } 210 211 return 0; 212bad: 213 return err; 214} 215 216static int ubi_create_vol(char *volume, int64_t size, int dynamic, int vol_id, 217 bool skipcheck) 218{ 219 struct ubi_mkvol_req req; 220 int err; 221 222 if (dynamic) 223 req.vol_type = UBI_DYNAMIC_VOLUME; 224 else 225 req.vol_type = UBI_STATIC_VOLUME; 226 227 req.vol_id = vol_id; 228 req.alignment = 1; 229 req.bytes = size; 230 231 strcpy(req.name, volume); 232 req.name_len = strlen(volume); 233 req.name[req.name_len] = '\0'; 234 req.flags = 0; 235 if (skipcheck) 236 req.flags |= UBI_VOL_SKIP_CRC_CHECK_FLG; 237 238 /* It's duplicated at drivers/mtd/ubi/cdev.c */ 239 err = verify_mkvol_req(ubi, &req); 240 if (err) { 241 printf("verify_mkvol_req failed %d\n", err); 242 return err; 243 } 244 printf("Creating %s volume %s of size %lld\n", 245 dynamic ? "dynamic" : "static", volume, size); 246 /* Call real ubi create volume */ 247 return ubi_create_volume(ubi, &req); 248} 249 250static struct ubi_volume *ubi_find_volume(char *volume) 251{ 252 struct ubi_volume *vol = NULL; 253 int i; 254 255 for (i = 0; i < ubi->vtbl_slots; i++) { 256 vol = ubi->volumes[i]; 257 if (vol && !strcmp(vol->name, volume)) 258 return vol; 259 } 260 261 printf("Volume %s not found!\n", volume); 262 return NULL; 263} 264 265static int ubi_remove_vol(char *volume) 266{ 267 int err, reserved_pebs, i; 268 struct ubi_volume *vol; 269 270 vol = ubi_find_volume(volume); 271 if (vol == NULL) 272 return ENODEV; 273 274 printf("Remove UBI volume %s (id %d)\n", vol->name, vol->vol_id); 275 276 if (ubi->ro_mode) { 277 printf("It's read-only mode\n"); 278 err = EROFS; 279 goto out_err; 280 } 281 282 err = ubi_change_vtbl_record(ubi, vol->vol_id, NULL); 283 if (err) { 284 printf("Error changing Vol tabel record err=%x\n", err); 285 goto out_err; 286 } 287 reserved_pebs = vol->reserved_pebs; 288 for (i = 0; i < vol->reserved_pebs; i++) { 289 err = ubi_eba_unmap_leb(ubi, vol, i); 290 if (err) 291 goto out_err; 292 } 293 294 kfree(vol->eba_tbl); 295 ubi->volumes[vol->vol_id]->eba_tbl = NULL; 296 ubi->volumes[vol->vol_id] = NULL; 297 298 ubi->rsvd_pebs -= reserved_pebs; 299 ubi->avail_pebs += reserved_pebs; 300 i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs; 301 if (i > 0) { 302 i = ubi->avail_pebs >= i ? i : ubi->avail_pebs; 303 ubi->avail_pebs -= i; 304 ubi->rsvd_pebs += i; 305 ubi->beb_rsvd_pebs += i; 306 if (i > 0) 307 ubi_msg("reserve more %d PEBs", i); 308 } 309 ubi->vol_count -= 1; 310 311 return 0; 312out_err: 313 ubi_err(ubi, "cannot remove volume %s, error %d", volume, err); 314 if (err < 0) 315 err = -err; 316 return err; 317} 318 319static int ubi_rename_vol(char *oldname, char *newname) 320{ 321 struct ubi_volume *vol; 322 struct ubi_rename_entry rename; 323 struct ubi_volume_desc desc; 324 struct list_head list; 325 326 vol = ubi_find_volume(oldname); 327 if (!vol) { 328 printf("%s: volume %s doesn't exist\n", __func__, oldname); 329 return ENODEV; 330 } 331 332 if (!ubi_check(newname)) { 333 printf("%s: volume %s already exist\n", __func__, newname); 334 return EINVAL; 335 } 336 337 printf("Rename UBI volume %s to %s\n", oldname, newname); 338 339 if (ubi->ro_mode) { 340 printf("%s: ubi device is in read-only mode\n", __func__); 341 return EROFS; 342 } 343 344 rename.new_name_len = strlen(newname); 345 strcpy(rename.new_name, newname); 346 rename.remove = 0; 347 desc.vol = vol; 348 desc.mode = 0; 349 rename.desc = &desc; 350 INIT_LIST_HEAD(&rename.list); 351 INIT_LIST_HEAD(&list); 352 list_add(&rename.list, &list); 353 354 return ubi_rename_volumes(ubi, &list); 355} 356 357static int ubi_volume_continue_write(char *volume, void *buf, size_t size) 358{ 359 int err = 1; 360 struct ubi_volume *vol; 361 362 vol = ubi_find_volume(volume); 363 if (vol == NULL) 364 return ENODEV; 365 366 err = ubi_more_update_data(ubi, vol, buf, size); 367 if (err < 0) { 368 printf("Couldnt or partially wrote data\n"); 369 return -err; 370 } 371 372 if (err) { 373 size = err; 374 375 err = ubi_check_volume(ubi, vol->vol_id); 376 if (err < 0) 377 return -err; 378 379 if (err) { 380 ubi_warn(ubi, "volume %d on UBI device %d is corrupt", 381 vol->vol_id, ubi->ubi_num); 382 vol->corrupted = 1; 383 } 384 385 vol->checked = 1; 386 ubi_gluebi_updated(vol); 387 } 388 389 return 0; 390} 391 392int ubi_volume_begin_write(char *volume, void *buf, size_t size, 393 size_t full_size) 394{ 395 int err = 1; 396 int rsvd_bytes = 0; 397 struct ubi_volume *vol; 398 399 vol = ubi_find_volume(volume); 400 if (vol == NULL) 401 return ENODEV; 402 403 rsvd_bytes = vol->reserved_pebs * (ubi->leb_size - vol->data_pad); 404 if (size > rsvd_bytes) { 405 printf("size > volume size! Aborting!\n"); 406 return EINVAL; 407 } 408 409 err = ubi_start_update(ubi, vol, full_size); 410 if (err < 0) { 411 printf("Cannot start volume update\n"); 412 return -err; 413 } 414 415 return ubi_volume_continue_write(volume, buf, size); 416} 417 418int ubi_volume_write(char *volume, void *buf, size_t size) 419{ 420 return ubi_volume_begin_write(volume, buf, size, size); 421} 422 423int ubi_volume_read(char *volume, char *buf, size_t size) 424{ 425 int err, lnum, off, len, tbuf_size; 426 void *tbuf; 427 unsigned long long tmp; 428 struct ubi_volume *vol; 429 loff_t offp = 0; 430 size_t len_read; 431 432 vol = ubi_find_volume(volume); 433 if (vol == NULL) 434 return ENODEV; 435 436 if (vol->updating) { 437 printf("updating"); 438 return EBUSY; 439 } 440 if (vol->upd_marker) { 441 printf("damaged volume, update marker is set"); 442 return EBADF; 443 } 444 if (offp == vol->used_bytes) 445 return 0; 446 447 if (size == 0) { 448 printf("No size specified -> Using max size (%lld)\n", vol->used_bytes); 449 size = vol->used_bytes; 450 } 451 452 printf("Read %zu bytes from volume %s to %p\n", size, volume, buf); 453 454 if (vol->corrupted) 455 printf("read from corrupted volume %d", vol->vol_id); 456 if (offp + size > vol->used_bytes) 457 size = vol->used_bytes - offp; 458 459 tbuf_size = vol->usable_leb_size; 460 if (size < tbuf_size) 461 tbuf_size = ALIGN(size, ubi->min_io_size); 462 tbuf = malloc_cache_aligned(tbuf_size); 463 if (!tbuf) { 464 printf("NO MEM\n"); 465 return ENOMEM; 466 } 467 len = size > tbuf_size ? tbuf_size : size; 468 469 tmp = offp; 470 off = do_div(tmp, vol->usable_leb_size); 471 lnum = tmp; 472 len_read = size; 473 do { 474 if (off + len >= vol->usable_leb_size) 475 len = vol->usable_leb_size - off; 476 477 err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0); 478 if (err) { 479 printf("read err %x\n", err); 480 err = -err; 481 break; 482 } 483 off += len; 484 if (off == vol->usable_leb_size) { 485 lnum += 1; 486 off -= vol->usable_leb_size; 487 } 488 489 size -= len; 490 offp += len; 491 492 memcpy(buf, tbuf, len); 493 494 buf += len; 495 len = size > tbuf_size ? tbuf_size : size; 496 } while (size); 497 498 if (!size) 499 env_set_hex("filesize", len_read); 500 501 free(tbuf); 502 return err; 503} 504 505static int ubi_dev_scan(struct mtd_info *info, const char *vid_header_offset) 506{ 507 char ubi_mtd_param_buffer[80]; 508 int err; 509 510 if (!vid_header_offset) 511 sprintf(ubi_mtd_param_buffer, "%s", info->name); 512 else 513 sprintf(ubi_mtd_param_buffer, "%s,%s", info->name, 514 vid_header_offset); 515 516 err = ubi_mtd_param_parse(ubi_mtd_param_buffer, NULL); 517 if (err) 518 return -err; 519 520 err = ubi_init(); 521 if (err) 522 return -err; 523 524 return 0; 525} 526 527static int ubi_set_skip_check(char *volume, bool skip_check) 528{ 529 struct ubi_vtbl_record vtbl_rec; 530 struct ubi_volume *vol; 531 532 vol = ubi_find_volume(volume); 533 if (!vol) 534 return ENODEV; 535 536 printf("%sing skip_check on volume %s\n", 537 skip_check ? "Sett" : "Clear", volume); 538 539 vtbl_rec = ubi->vtbl[vol->vol_id]; 540 if (skip_check) { 541 vtbl_rec.flags |= UBI_VTBL_SKIP_CRC_CHECK_FLG; 542 vol->skip_check = 1; 543 } else { 544 vtbl_rec.flags &= ~UBI_VTBL_SKIP_CRC_CHECK_FLG; 545 vol->skip_check = 0; 546 } 547 548 return ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); 549} 550 551static int ubi_detach(void) 552{ 553#ifdef CONFIG_CMD_UBIFS 554 /* 555 * Automatically unmount UBIFS partition when user 556 * changes the UBI device. Otherwise the following 557 * UBIFS commands will crash. 558 */ 559 if (ubifs_is_mounted()) 560 cmd_ubifs_umount(); 561#endif 562 563 /* 564 * Call ubi_exit() before re-initializing the UBI subsystem 565 */ 566 if (ubi) 567 ubi_exit(); 568 569 ubi = NULL; 570 571 return 0; 572} 573 574int ubi_part(char *part_name, const char *vid_header_offset) 575{ 576 struct mtd_info *mtd; 577 int err = 0; 578 579 if (ubi && ubi->mtd && !strcmp(ubi->mtd->name, part_name)) { 580 printf("UBI partition '%s' already selected\n", part_name); 581 return 0; 582 } 583 584 ubi_detach(); 585 586 mtd_probe_devices(); 587 mtd = get_mtd_device_nm(part_name); 588 if (IS_ERR(mtd)) { 589 printf("Partition %s not found!\n", part_name); 590 return 1; 591 } 592 put_mtd_device(mtd); 593 594 err = ubi_dev_scan(mtd, vid_header_offset); 595 if (err) { 596 printf("UBI init error %d\n", err); 597 printf("Please check, if the correct MTD partition is used (size big enough?)\n"); 598 return err; 599 } 600 601 ubi = ubi_devices[0]; 602 603 return 0; 604} 605 606static int do_ubi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) 607{ 608 int64_t size = 0; 609 ulong addr = 0; 610 bool skipcheck = false; 611 612 if (argc < 2) 613 return CMD_RET_USAGE; 614 615 if (strcmp(argv[1], "detach") == 0) 616 return ubi_detach(); 617 618 if (strcmp(argv[1], "part") == 0) { 619 const char *vid_header_offset = NULL; 620 621 /* Print current partition */ 622 if (argc == 2) { 623 if (!ubi) { 624 printf("Error, no UBI device selected!\n"); 625 return 1; 626 } 627 628 printf("Device %d: %s, MTD partition %s\n", 629 ubi->ubi_num, ubi->ubi_name, ubi->mtd->name); 630 return 0; 631 } 632 633 if (argc < 3) 634 return CMD_RET_USAGE; 635 636 if (argc > 3) 637 vid_header_offset = argv[3]; 638 639 return ubi_part(argv[2], vid_header_offset); 640 } 641 642 if ((strcmp(argv[1], "part") != 0) && !ubi) { 643 printf("Error, no UBI device selected!\n"); 644 return 1; 645 } 646 647 if (strcmp(argv[1], "info") == 0) { 648 int layout = 0; 649 if (argc > 2 && !strncmp(argv[2], "l", 1)) 650 layout = 1; 651 return ubi_info(layout); 652 } 653 654 if (strcmp(argv[1], "list") == 0) { 655 int numeric = 0; 656 if (argc >= 3 && argv[2][0] == '-') { 657 if (strcmp(argv[2], "-numeric") == 0) 658 numeric = 1; 659 else 660 return CMD_RET_USAGE; 661 } 662 if (!numeric && argc != 2 && argc != 3) 663 return CMD_RET_USAGE; 664 if (numeric && argc != 3 && argc != 4) 665 return CMD_RET_USAGE; 666 return ubi_list(argv[numeric ? 3 : 2], numeric); 667 } 668 669 if (strcmp(argv[1], "check") == 0) { 670 if (argc > 2) 671 return ubi_check(argv[2]); 672 673 printf("Error, no volume name passed\n"); 674 return 1; 675 } 676 677 if (strncmp(argv[1], "create", 6) == 0) { 678 int dynamic = 1; /* default: dynamic volume */ 679 int id = UBI_VOL_NUM_AUTO; 680 681 /* Use maximum available size */ 682 size = 0; 683 684 /* E.g., create volume with "skipcheck" bit set */ 685 if (argc == 7) { 686 skipcheck = strncmp(argv[6], "--skipcheck", 11) == 0; 687 argc--; 688 } 689 690 /* E.g., create volume size type vol_id */ 691 if (argc == 6) { 692 id = simple_strtoull(argv[5], NULL, 16); 693 argc--; 694 } 695 696 /* E.g., create volume size type */ 697 if (argc == 5) { 698 if (strncmp(argv[4], "s", 1) == 0) 699 dynamic = 0; 700 else if (strncmp(argv[4], "d", 1) != 0) { 701 printf("Incorrect type\n"); 702 return 1; 703 } 704 argc--; 705 } 706 /* E.g., create volume size */ 707 if (argc == 4) { 708 if (argv[3][0] != '-') 709 size = simple_strtoull(argv[3], NULL, 16); 710 argc--; 711 } 712 /* Use maximum available size */ 713 if (!size) { 714 size = (int64_t)ubi->avail_pebs * ubi->leb_size; 715 printf("No size specified -> Using max size (%lld)\n", size); 716 } 717 /* E.g., create volume */ 718 if (argc == 3) { 719 return ubi_create_vol(argv[2], size, dynamic, id, 720 skipcheck); 721 } 722 } 723 724 if (strncmp(argv[1], "remove", 6) == 0) { 725 /* E.g., remove volume */ 726 if (argc == 3) 727 return ubi_remove_vol(argv[2]); 728 } 729 730 if (IS_ENABLED(CONFIG_CMD_UBI_RENAME) && !strncmp(argv[1], "rename", 6)) 731 return ubi_rename_vol(argv[2], argv[3]); 732 733 if (strncmp(argv[1], "skipcheck", 9) == 0) { 734 /* E.g., change skip_check flag */ 735 if (argc == 4) { 736 skipcheck = strncmp(argv[3], "on", 2) == 0; 737 return ubi_set_skip_check(argv[2], skipcheck); 738 } 739 } 740 741 if (strncmp(argv[1], "write", 5) == 0) { 742 int ret; 743 744 if (argc < 5) { 745 printf("Please see usage\n"); 746 return 1; 747 } 748 749 addr = hextoul(argv[2], NULL); 750 size = hextoul(argv[4], NULL); 751 752 if (strlen(argv[1]) == 10 && 753 strncmp(argv[1] + 5, ".part", 5) == 0) { 754 if (argc < 6) { 755 ret = ubi_volume_continue_write(argv[3], 756 (void *)addr, size); 757 } else { 758 size_t full_size; 759 full_size = hextoul(argv[5], NULL); 760 ret = ubi_volume_begin_write(argv[3], 761 (void *)addr, size, full_size); 762 } 763 } else { 764 ret = ubi_volume_write(argv[3], (void *)addr, size); 765 } 766 if (!ret) { 767 printf("%lld bytes written to volume %s\n", size, 768 argv[3]); 769 } 770 771 return ret; 772 } 773 774 if (strncmp(argv[1], "read", 4) == 0) { 775 size = 0; 776 777 /* E.g., read volume size */ 778 if (argc == 5) { 779 size = hextoul(argv[4], NULL); 780 argc--; 781 } 782 783 /* E.g., read volume */ 784 if (argc == 4) { 785 addr = hextoul(argv[2], NULL); 786 argc--; 787 } 788 789 if (argc == 3) { 790 return ubi_volume_read(argv[3], (char *)addr, size); 791 } 792 } 793 794 printf("Please see usage\n"); 795 return 1; 796} 797 798U_BOOT_CMD( 799 ubi, 7, 1, do_ubi, 800 "ubi commands", 801 "detach" 802 " - detach ubi from a mtd partition\n" 803 "ubi part [part] [offset]\n" 804 " - Show or set current partition (with optional VID" 805 " header offset)\n" 806 "ubi info [l[ayout]]" 807 " - Display volume and ubi layout information\n" 808 "ubi list [flags]" 809 " - print the list of volumes\n" 810 "ubi list [flags] <varname>" 811 " - set environment variable to the list of volumes" 812 " (flags can be -numeric)\n" 813 "ubi check volumename" 814 " - check if volumename exists\n" 815 "ubi create[vol] volume [size] [type] [id] [--skipcheck]\n" 816 " - create volume name with size ('-' for maximum" 817 " available size)\n" 818 "ubi write[vol] address volume size" 819 " - Write volume from address with size\n" 820 "ubi write.part address volume size [fullsize]\n" 821 " - Write part of a volume from address\n" 822 "ubi read[vol] address volume [size]" 823 " - Read volume to address with size\n" 824 "ubi remove[vol] volume" 825 " - Remove volume\n" 826#if IS_ENABLED(CONFIG_CMD_UBI_RENAME) 827 "ubi rename oldname newname\n" 828#endif 829 "ubi skipcheck volume on/off - Set or clear skip_check flag in volume header\n" 830 "[Legends]\n" 831 " volume: character name\n" 832 " size: specified in bytes\n" 833 " type: s[tatic] or d[ynamic] (default=dynamic)" 834); 835