1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 4 */ 5 6#define LOG_CATEGORY LOGC_CORE 7 8#include <command.h> 9#include <config.h> 10#include <display_options.h> 11#include <errno.h> 12#include <common.h> 13#include <env.h> 14#include <lmb.h> 15#include <log.h> 16#include <malloc.h> 17#include <mapmem.h> 18#include <part.h> 19#include <ext4fs.h> 20#include <fat.h> 21#include <fs.h> 22#include <sandboxfs.h> 23#include <semihostingfs.h> 24#include <ubifs_uboot.h> 25#include <btrfs.h> 26#include <asm/global_data.h> 27#include <asm/io.h> 28#include <div64.h> 29#include <linux/math64.h> 30#include <linux/sizes.h> 31#include <efi_loader.h> 32#include <squashfs.h> 33#include <erofs.h> 34 35DECLARE_GLOBAL_DATA_PTR; 36 37static struct blk_desc *fs_dev_desc; 38static int fs_dev_part; 39static struct disk_partition fs_partition; 40static int fs_type = FS_TYPE_ANY; 41 42void fs_set_type(int type) 43{ 44 fs_type = type; 45} 46 47static inline int fs_probe_unsupported(struct blk_desc *fs_dev_desc, 48 struct disk_partition *fs_partition) 49{ 50 log_debug("Unrecognized filesystem type\n"); 51 return -1; 52} 53 54static inline int fs_ls_unsupported(const char *dirname) 55{ 56 return -1; 57} 58 59/* generic implementation of ls in terms of opendir/readdir/closedir */ 60__maybe_unused 61static int fs_ls_generic(const char *dirname) 62{ 63 struct fs_dir_stream *dirs; 64 struct fs_dirent *dent; 65 int nfiles = 0, ndirs = 0; 66 67 dirs = fs_opendir(dirname); 68 if (!dirs) 69 return -errno; 70 71 while ((dent = fs_readdir(dirs))) { 72 if (dent->type == FS_DT_DIR) { 73 printf(" %s/\n", dent->name); 74 ndirs++; 75 } else if (dent->type == FS_DT_LNK) { 76 printf(" <SYM> %s\n", dent->name); 77 nfiles++; 78 } else { 79 printf(" %8lld %s\n", dent->size, dent->name); 80 nfiles++; 81 } 82 } 83 84 fs_closedir(dirs); 85 86 printf("\n%d file(s), %d dir(s)\n\n", nfiles, ndirs); 87 88 return 0; 89} 90 91static inline int fs_exists_unsupported(const char *filename) 92{ 93 return 0; 94} 95 96static inline int fs_size_unsupported(const char *filename, loff_t *size) 97{ 98 return -1; 99} 100 101static inline int fs_read_unsupported(const char *filename, void *buf, 102 loff_t offset, loff_t len, 103 loff_t *actread) 104{ 105 return -1; 106} 107 108static inline int fs_write_unsupported(const char *filename, void *buf, 109 loff_t offset, loff_t len, 110 loff_t *actwrite) 111{ 112 return -1; 113} 114 115static inline int fs_ln_unsupported(const char *filename, const char *target) 116{ 117 return -1; 118} 119 120static inline void fs_close_unsupported(void) 121{ 122} 123 124static inline int fs_uuid_unsupported(char *uuid_str) 125{ 126 return -1; 127} 128 129static inline int fs_opendir_unsupported(const char *filename, 130 struct fs_dir_stream **dirs) 131{ 132 return -EACCES; 133} 134 135static inline int fs_unlink_unsupported(const char *filename) 136{ 137 return -1; 138} 139 140static inline int fs_mkdir_unsupported(const char *dirname) 141{ 142 return -1; 143} 144 145struct fstype_info { 146 int fstype; 147 char *name; 148 /* 149 * Is it legal to pass NULL as .probe()'s fs_dev_desc parameter? This 150 * should be false in most cases. For "virtual" filesystems which 151 * aren't based on a U-Boot block device (e.g. sandbox), this can be 152 * set to true. This should also be true for the dummy entry at the end 153 * of fstypes[], since that is essentially a "virtual" (non-existent) 154 * filesystem. 155 */ 156 bool null_dev_desc_ok; 157 int (*probe)(struct blk_desc *fs_dev_desc, 158 struct disk_partition *fs_partition); 159 int (*ls)(const char *dirname); 160 int (*exists)(const char *filename); 161 int (*size)(const char *filename, loff_t *size); 162 int (*read)(const char *filename, void *buf, loff_t offset, 163 loff_t len, loff_t *actread); 164 int (*write)(const char *filename, void *buf, loff_t offset, 165 loff_t len, loff_t *actwrite); 166 void (*close)(void); 167 int (*uuid)(char *uuid_str); 168 /* 169 * Open a directory stream. On success return 0 and directory 170 * stream pointer via 'dirsp'. On error, return -errno. See 171 * fs_opendir(). 172 */ 173 int (*opendir)(const char *filename, struct fs_dir_stream **dirsp); 174 /* 175 * Read next entry from directory stream. On success return 0 176 * and directory entry pointer via 'dentp'. On error return 177 * -errno. See fs_readdir(). 178 */ 179 int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp); 180 /* see fs_closedir() */ 181 void (*closedir)(struct fs_dir_stream *dirs); 182 int (*unlink)(const char *filename); 183 int (*mkdir)(const char *dirname); 184 int (*ln)(const char *filename, const char *target); 185}; 186 187static struct fstype_info fstypes[] = { 188#if CONFIG_IS_ENABLED(FS_FAT) 189 { 190 .fstype = FS_TYPE_FAT, 191 .name = "fat", 192 .null_dev_desc_ok = false, 193 .probe = fat_set_blk_dev, 194 .close = fat_close, 195 .ls = fs_ls_generic, 196 .exists = fat_exists, 197 .size = fat_size, 198 .read = fat_read_file, 199#if CONFIG_IS_ENABLED(FAT_WRITE) 200 .write = file_fat_write, 201 .unlink = fat_unlink, 202 .mkdir = fat_mkdir, 203#else 204 .write = fs_write_unsupported, 205 .unlink = fs_unlink_unsupported, 206 .mkdir = fs_mkdir_unsupported, 207#endif 208 .uuid = fat_uuid, 209 .opendir = fat_opendir, 210 .readdir = fat_readdir, 211 .closedir = fat_closedir, 212 .ln = fs_ln_unsupported, 213 }, 214#endif 215 216#if CONFIG_IS_ENABLED(FS_EXT4) 217 { 218 .fstype = FS_TYPE_EXT, 219 .name = "ext4", 220 .null_dev_desc_ok = false, 221 .probe = ext4fs_probe, 222 .close = ext4fs_close, 223 .ls = ext4fs_ls, 224 .exists = ext4fs_exists, 225 .size = ext4fs_size, 226 .read = ext4_read_file, 227#ifdef CONFIG_CMD_EXT4_WRITE 228 .write = ext4_write_file, 229 .ln = ext4fs_create_link, 230#else 231 .write = fs_write_unsupported, 232 .ln = fs_ln_unsupported, 233#endif 234 .uuid = ext4fs_uuid, 235 .opendir = fs_opendir_unsupported, 236 .unlink = fs_unlink_unsupported, 237 .mkdir = fs_mkdir_unsupported, 238 }, 239#endif 240#if IS_ENABLED(CONFIG_SANDBOX) && !IS_ENABLED(CONFIG_SPL_BUILD) 241 { 242 .fstype = FS_TYPE_SANDBOX, 243 .name = "sandbox", 244 .null_dev_desc_ok = true, 245 .probe = sandbox_fs_set_blk_dev, 246 .close = sandbox_fs_close, 247 .ls = sandbox_fs_ls, 248 .exists = sandbox_fs_exists, 249 .size = sandbox_fs_size, 250 .read = fs_read_sandbox, 251 .write = fs_write_sandbox, 252 .uuid = fs_uuid_unsupported, 253 .opendir = fs_opendir_unsupported, 254 .unlink = fs_unlink_unsupported, 255 .mkdir = fs_mkdir_unsupported, 256 .ln = fs_ln_unsupported, 257 }, 258#endif 259#if CONFIG_IS_ENABLED(SEMIHOSTING) 260 { 261 .fstype = FS_TYPE_SEMIHOSTING, 262 .name = "semihosting", 263 .null_dev_desc_ok = true, 264 .probe = smh_fs_set_blk_dev, 265 .close = fs_close_unsupported, 266 .ls = fs_ls_unsupported, 267 .exists = fs_exists_unsupported, 268 .size = smh_fs_size, 269 .read = smh_fs_read, 270 .write = smh_fs_write, 271 .uuid = fs_uuid_unsupported, 272 .opendir = fs_opendir_unsupported, 273 .unlink = fs_unlink_unsupported, 274 .mkdir = fs_mkdir_unsupported, 275 .ln = fs_ln_unsupported, 276 }, 277#endif 278#ifndef CONFIG_SPL_BUILD 279#ifdef CONFIG_CMD_UBIFS 280 { 281 .fstype = FS_TYPE_UBIFS, 282 .name = "ubifs", 283 .null_dev_desc_ok = true, 284 .probe = ubifs_set_blk_dev, 285 .close = ubifs_close, 286 .ls = ubifs_ls, 287 .exists = ubifs_exists, 288 .size = ubifs_size, 289 .read = ubifs_read, 290 .write = fs_write_unsupported, 291 .uuid = fs_uuid_unsupported, 292 .opendir = fs_opendir_unsupported, 293 .unlink = fs_unlink_unsupported, 294 .mkdir = fs_mkdir_unsupported, 295 .ln = fs_ln_unsupported, 296 }, 297#endif 298#endif 299#ifndef CONFIG_SPL_BUILD 300#ifdef CONFIG_FS_BTRFS 301 { 302 .fstype = FS_TYPE_BTRFS, 303 .name = "btrfs", 304 .null_dev_desc_ok = false, 305 .probe = btrfs_probe, 306 .close = btrfs_close, 307 .ls = btrfs_ls, 308 .exists = btrfs_exists, 309 .size = btrfs_size, 310 .read = btrfs_read, 311 .write = fs_write_unsupported, 312 .uuid = btrfs_uuid, 313 .opendir = fs_opendir_unsupported, 314 .unlink = fs_unlink_unsupported, 315 .mkdir = fs_mkdir_unsupported, 316 .ln = fs_ln_unsupported, 317 }, 318#endif 319#endif 320#if CONFIG_IS_ENABLED(FS_SQUASHFS) 321 { 322 .fstype = FS_TYPE_SQUASHFS, 323 .name = "squashfs", 324 .null_dev_desc_ok = false, 325 .probe = sqfs_probe, 326 .opendir = sqfs_opendir, 327 .readdir = sqfs_readdir, 328 .ls = fs_ls_generic, 329 .read = sqfs_read, 330 .size = sqfs_size, 331 .close = sqfs_close, 332 .closedir = sqfs_closedir, 333 .exists = sqfs_exists, 334 .uuid = fs_uuid_unsupported, 335 .write = fs_write_unsupported, 336 .ln = fs_ln_unsupported, 337 .unlink = fs_unlink_unsupported, 338 .mkdir = fs_mkdir_unsupported, 339 }, 340#endif 341#if IS_ENABLED(CONFIG_FS_EROFS) 342 { 343 .fstype = FS_TYPE_EROFS, 344 .name = "erofs", 345 .null_dev_desc_ok = false, 346 .probe = erofs_probe, 347 .opendir = erofs_opendir, 348 .readdir = erofs_readdir, 349 .ls = fs_ls_generic, 350 .read = erofs_read, 351 .size = erofs_size, 352 .close = erofs_close, 353 .closedir = erofs_closedir, 354 .exists = erofs_exists, 355 .uuid = fs_uuid_unsupported, 356 .write = fs_write_unsupported, 357 .ln = fs_ln_unsupported, 358 .unlink = fs_unlink_unsupported, 359 .mkdir = fs_mkdir_unsupported, 360 }, 361#endif 362 { 363 .fstype = FS_TYPE_ANY, 364 .name = "unsupported", 365 .null_dev_desc_ok = true, 366 .probe = fs_probe_unsupported, 367 .close = fs_close_unsupported, 368 .ls = fs_ls_unsupported, 369 .exists = fs_exists_unsupported, 370 .size = fs_size_unsupported, 371 .read = fs_read_unsupported, 372 .write = fs_write_unsupported, 373 .uuid = fs_uuid_unsupported, 374 .opendir = fs_opendir_unsupported, 375 .unlink = fs_unlink_unsupported, 376 .mkdir = fs_mkdir_unsupported, 377 .ln = fs_ln_unsupported, 378 }, 379}; 380 381static struct fstype_info *fs_get_info(int fstype) 382{ 383 struct fstype_info *info; 384 int i; 385 386 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) { 387 if (fstype == info->fstype) 388 return info; 389 } 390 391 /* Return the 'unsupported' sentinel */ 392 return info; 393} 394 395/** 396 * fs_get_type() - Get type of current filesystem 397 * 398 * Return: filesystem type 399 * 400 * Returns filesystem type representing the current filesystem, or 401 * FS_TYPE_ANY for any unrecognised filesystem. 402 */ 403int fs_get_type(void) 404{ 405 return fs_type; 406} 407 408/** 409 * fs_get_type_name() - Get type of current filesystem 410 * 411 * Return: Pointer to filesystem name 412 * 413 * Returns a string describing the current filesystem, or the sentinel 414 * "unsupported" for any unrecognised filesystem. 415 */ 416const char *fs_get_type_name(void) 417{ 418 return fs_get_info(fs_type)->name; 419} 420 421int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype) 422{ 423 struct fstype_info *info; 424 int part, i; 425 426 part = part_get_info_by_dev_and_name_or_num(ifname, dev_part_str, &fs_dev_desc, 427 &fs_partition, 1); 428 if (part < 0) 429 return -1; 430 431 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) { 432 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY && 433 fstype != info->fstype) 434 continue; 435 436 if (!fs_dev_desc && !info->null_dev_desc_ok) 437 continue; 438 439 if (!info->probe(fs_dev_desc, &fs_partition)) { 440 fs_type = info->fstype; 441 fs_dev_part = part; 442 return 0; 443 } 444 } 445 446 return -1; 447} 448 449/* set current blk device w/ blk_desc + partition # */ 450int fs_set_blk_dev_with_part(struct blk_desc *desc, int part) 451{ 452 struct fstype_info *info; 453 int ret, i; 454 455 if (part >= 1) 456 ret = part_get_info(desc, part, &fs_partition); 457 else 458 ret = part_get_info_whole_disk(desc, &fs_partition); 459 if (ret) 460 return ret; 461 fs_dev_desc = desc; 462 463 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) { 464 if (!info->probe(fs_dev_desc, &fs_partition)) { 465 fs_type = info->fstype; 466 fs_dev_part = part; 467 return 0; 468 } 469 } 470 471 return -1; 472} 473 474void fs_close(void) 475{ 476 struct fstype_info *info = fs_get_info(fs_type); 477 478 info->close(); 479 480 fs_type = FS_TYPE_ANY; 481} 482 483int fs_uuid(char *uuid_str) 484{ 485 struct fstype_info *info = fs_get_info(fs_type); 486 487 return info->uuid(uuid_str); 488} 489 490int fs_ls(const char *dirname) 491{ 492 int ret; 493 494 struct fstype_info *info = fs_get_info(fs_type); 495 496 ret = info->ls(dirname); 497 498 fs_close(); 499 500 return ret; 501} 502 503int fs_exists(const char *filename) 504{ 505 int ret; 506 507 struct fstype_info *info = fs_get_info(fs_type); 508 509 ret = info->exists(filename); 510 511 fs_close(); 512 513 return ret; 514} 515 516int fs_size(const char *filename, loff_t *size) 517{ 518 int ret; 519 520 struct fstype_info *info = fs_get_info(fs_type); 521 522 ret = info->size(filename, size); 523 524 fs_close(); 525 526 return ret; 527} 528 529#ifdef CONFIG_LMB 530/* Check if a file may be read to the given address */ 531static int fs_read_lmb_check(const char *filename, ulong addr, loff_t offset, 532 loff_t len, struct fstype_info *info) 533{ 534 struct lmb lmb; 535 int ret; 536 loff_t size; 537 loff_t read_len; 538 539 /* get the actual size of the file */ 540 ret = info->size(filename, &size); 541 if (ret) 542 return ret; 543 if (offset >= size) { 544 /* offset >= EOF, no bytes will be written */ 545 return 0; 546 } 547 read_len = size - offset; 548 549 /* limit to 'len' if it is smaller */ 550 if (len && len < read_len) 551 read_len = len; 552 553 lmb_init_and_reserve(&lmb, gd->bd, (void *)gd->fdt_blob); 554 lmb_dump_all(&lmb); 555 556 if (lmb_alloc_addr(&lmb, addr, read_len) == addr) 557 return 0; 558 559 log_err("** Reading file would overwrite reserved memory **\n"); 560 return -ENOSPC; 561} 562#endif 563 564static int _fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, 565 int do_lmb_check, loff_t *actread) 566{ 567 struct fstype_info *info = fs_get_info(fs_type); 568 void *buf; 569 int ret; 570 571#ifdef CONFIG_LMB 572 if (do_lmb_check) { 573 ret = fs_read_lmb_check(filename, addr, offset, len, info); 574 if (ret) 575 return ret; 576 } 577#endif 578 579 /* 580 * We don't actually know how many bytes are being read, since len==0 581 * means read the whole file. 582 */ 583 buf = map_sysmem(addr, len); 584 ret = info->read(filename, buf, offset, len, actread); 585 unmap_sysmem(buf); 586 587 /* If we requested a specific number of bytes, check we got it */ 588 if (ret == 0 && len && *actread != len) 589 log_debug("** %s shorter than offset + len **\n", filename); 590 fs_close(); 591 592 return ret; 593} 594 595int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, 596 loff_t *actread) 597{ 598 return _fs_read(filename, addr, offset, len, 0, actread); 599} 600 601int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, 602 loff_t *actwrite) 603{ 604 struct fstype_info *info = fs_get_info(fs_type); 605 void *buf; 606 int ret; 607 608 buf = map_sysmem(addr, len); 609 ret = info->write(filename, buf, offset, len, actwrite); 610 unmap_sysmem(buf); 611 612 if (ret < 0 && len != *actwrite) { 613 log_err("** Unable to write file %s **\n", filename); 614 ret = -1; 615 } 616 fs_close(); 617 618 return ret; 619} 620 621struct fs_dir_stream *fs_opendir(const char *filename) 622{ 623 struct fstype_info *info = fs_get_info(fs_type); 624 struct fs_dir_stream *dirs = NULL; 625 int ret; 626 627 ret = info->opendir(filename, &dirs); 628 fs_close(); 629 if (ret) { 630 errno = -ret; 631 return NULL; 632 } 633 634 dirs->desc = fs_dev_desc; 635 dirs->part = fs_dev_part; 636 637 return dirs; 638} 639 640struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs) 641{ 642 struct fstype_info *info; 643 struct fs_dirent *dirent; 644 int ret; 645 646 fs_set_blk_dev_with_part(dirs->desc, dirs->part); 647 info = fs_get_info(fs_type); 648 649 ret = info->readdir(dirs, &dirent); 650 fs_close(); 651 if (ret) { 652 errno = -ret; 653 return NULL; 654 } 655 656 return dirent; 657} 658 659void fs_closedir(struct fs_dir_stream *dirs) 660{ 661 struct fstype_info *info; 662 663 if (!dirs) 664 return; 665 666 fs_set_blk_dev_with_part(dirs->desc, dirs->part); 667 info = fs_get_info(fs_type); 668 669 info->closedir(dirs); 670 fs_close(); 671} 672 673int fs_unlink(const char *filename) 674{ 675 int ret; 676 677 struct fstype_info *info = fs_get_info(fs_type); 678 679 ret = info->unlink(filename); 680 681 fs_close(); 682 683 return ret; 684} 685 686int fs_mkdir(const char *dirname) 687{ 688 int ret; 689 690 struct fstype_info *info = fs_get_info(fs_type); 691 692 ret = info->mkdir(dirname); 693 694 fs_close(); 695 696 return ret; 697} 698 699int fs_ln(const char *fname, const char *target) 700{ 701 struct fstype_info *info = fs_get_info(fs_type); 702 int ret; 703 704 ret = info->ln(fname, target); 705 706 if (ret < 0) { 707 log_err("** Unable to create link %s -> %s **\n", fname, target); 708 ret = -1; 709 } 710 fs_close(); 711 712 return ret; 713} 714 715int do_size(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], 716 int fstype) 717{ 718 loff_t size; 719 720 if (argc != 4) 721 return CMD_RET_USAGE; 722 723 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 724 return 1; 725 726 if (fs_size(argv[3], &size) < 0) 727 return CMD_RET_FAILURE; 728 729 env_set_hex("filesize", size); 730 731 return 0; 732} 733 734int do_load(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], 735 int fstype) 736{ 737 unsigned long addr; 738 const char *addr_str; 739 const char *filename; 740 loff_t bytes; 741 loff_t pos; 742 loff_t len_read; 743 int ret; 744 unsigned long time; 745 char *ep; 746 747 if (argc < 2) 748 return CMD_RET_USAGE; 749 if (argc > 7) 750 return CMD_RET_USAGE; 751 752 if (fs_set_blk_dev(argv[1], cmd_arg2(argc, argv), fstype)) { 753 log_err("Can't set block device\n"); 754 return 1; 755 } 756 757 if (argc >= 4) { 758 addr = hextoul(argv[3], &ep); 759 if (ep == argv[3] || *ep != '\0') 760 return CMD_RET_USAGE; 761 } else { 762 addr_str = env_get("loadaddr"); 763 if (addr_str != NULL) 764 addr = hextoul(addr_str, NULL); 765 else 766 addr = CONFIG_SYS_LOAD_ADDR; 767 } 768 if (argc >= 5) { 769 filename = argv[4]; 770 } else { 771 filename = env_get("bootfile"); 772 if (!filename) { 773 puts("** No boot file defined **\n"); 774 return 1; 775 } 776 } 777 if (argc >= 6) 778 bytes = hextoul(argv[5], NULL); 779 else 780 bytes = 0; 781 if (argc >= 7) 782 pos = hextoul(argv[6], NULL); 783 else 784 pos = 0; 785 786 time = get_timer(0); 787 ret = _fs_read(filename, addr, pos, bytes, 1, &len_read); 788 time = get_timer(time); 789 if (ret < 0) { 790 log_err("Failed to load '%s'\n", filename); 791 return 1; 792 } 793 794 efi_set_bootdev(argv[1], (argc > 2) ? argv[2] : "", 795 (argc > 4) ? argv[4] : "", map_sysmem(addr, 0), 796 len_read); 797 798 printf("%llu bytes read in %lu ms", len_read, time); 799 if (time > 0) { 800 puts(" ("); 801 print_size(div_u64(len_read, time) * 1000, "/s"); 802 puts(")"); 803 } 804 puts("\n"); 805 806 env_set_hex("fileaddr", addr); 807 env_set_hex("filesize", len_read); 808 809 return 0; 810} 811 812int do_ls(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], 813 int fstype) 814{ 815 if (argc < 2) 816 return CMD_RET_USAGE; 817 if (argc > 4) 818 return CMD_RET_USAGE; 819 820 if (fs_set_blk_dev(argv[1], cmd_arg2(argc, argv), fstype)) 821 return 1; 822 823 if (fs_ls(argc >= 4 ? argv[3] : "/")) 824 return 1; 825 826 return 0; 827} 828 829int file_exists(const char *dev_type, const char *dev_part, const char *file, 830 int fstype) 831{ 832 if (fs_set_blk_dev(dev_type, dev_part, fstype)) 833 return 0; 834 835 return fs_exists(file); 836} 837 838int do_save(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], 839 int fstype) 840{ 841 unsigned long addr; 842 const char *filename; 843 loff_t bytes; 844 loff_t pos; 845 loff_t len; 846 int ret; 847 unsigned long time; 848 849 if (argc < 6 || argc > 7) 850 return CMD_RET_USAGE; 851 852 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 853 return 1; 854 855 addr = hextoul(argv[3], NULL); 856 filename = argv[4]; 857 bytes = hextoul(argv[5], NULL); 858 if (argc >= 7) 859 pos = hextoul(argv[6], NULL); 860 else 861 pos = 0; 862 863 time = get_timer(0); 864 ret = fs_write(filename, addr, pos, bytes, &len); 865 time = get_timer(time); 866 if (ret < 0) 867 return 1; 868 869 printf("%llu bytes written in %lu ms", len, time); 870 if (time > 0) { 871 puts(" ("); 872 print_size(div_u64(len, time) * 1000, "/s"); 873 puts(")"); 874 } 875 puts("\n"); 876 877 return 0; 878} 879 880int do_fs_uuid(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], 881 int fstype) 882{ 883 int ret; 884 char uuid[37]; 885 memset(uuid, 0, sizeof(uuid)); 886 887 if (argc < 3 || argc > 4) 888 return CMD_RET_USAGE; 889 890 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 891 return 1; 892 893 ret = fs_uuid(uuid); 894 if (ret) 895 return CMD_RET_FAILURE; 896 897 if (argc == 4) 898 env_set(argv[3], uuid); 899 else 900 printf("%s\n", uuid); 901 902 return CMD_RET_SUCCESS; 903} 904 905int do_fs_type(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) 906{ 907 struct fstype_info *info; 908 909 if (argc < 3 || argc > 4) 910 return CMD_RET_USAGE; 911 912 if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY)) 913 return 1; 914 915 info = fs_get_info(fs_type); 916 917 if (argc == 4) 918 env_set(argv[3], info->name); 919 else 920 printf("%s\n", info->name); 921 922 fs_close(); 923 924 return CMD_RET_SUCCESS; 925} 926 927int do_rm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], 928 int fstype) 929{ 930 if (argc != 4) 931 return CMD_RET_USAGE; 932 933 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 934 return 1; 935 936 if (fs_unlink(argv[3])) 937 return 1; 938 939 return 0; 940} 941 942int do_mkdir(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], 943 int fstype) 944{ 945 int ret; 946 947 if (argc != 4) 948 return CMD_RET_USAGE; 949 950 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 951 return 1; 952 953 ret = fs_mkdir(argv[3]); 954 if (ret) { 955 log_err("** Unable to create a directory \"%s\" **\n", argv[3]); 956 return 1; 957 } 958 959 return 0; 960} 961 962int do_ln(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[], 963 int fstype) 964{ 965 if (argc != 5) 966 return CMD_RET_USAGE; 967 968 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 969 return 1; 970 971 if (fs_ln(argv[3], argv[4])) 972 return 1; 973 974 return 0; 975} 976 977int do_fs_types(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) 978{ 979 struct fstype_info *drv = fstypes; 980 const int n_ents = ARRAY_SIZE(fstypes); 981 struct fstype_info *entry; 982 int i = 0; 983 984 puts("Supported filesystems"); 985 for (entry = drv; entry != drv + n_ents; entry++) { 986 if (entry->fstype != FS_TYPE_ANY) { 987 printf("%c %s", i ? ',' : ':', entry->name); 988 i++; 989 } 990 } 991 if (!i) 992 puts(": <none>"); 993 puts("\n"); 994 return CMD_RET_SUCCESS; 995} 996 997int fs_read_alloc(const char *fname, ulong size, uint align, void **bufp) 998{ 999 loff_t bytes_read; 1000 ulong addr; 1001 char *buf; 1002 int ret; 1003 1004 buf = memalign(align, size + 1); 1005 if (!buf) 1006 return log_msg_ret("buf", -ENOMEM); 1007 addr = map_to_sysmem(buf); 1008 1009 ret = fs_read(fname, addr, 0, size, &bytes_read); 1010 if (ret) { 1011 free(buf); 1012 return log_msg_ret("read", ret); 1013 } 1014 if (size != bytes_read) 1015 return log_msg_ret("bread", -EIO); 1016 buf[size] = '\0'; 1017 1018 *bufp = buf; 1019 1020 return 0; 1021} 1022 1023int fs_load_alloc(const char *ifname, const char *dev_part_str, 1024 const char *fname, ulong max_size, ulong align, void **bufp, 1025 ulong *sizep) 1026{ 1027 loff_t size; 1028 void *buf; 1029 int ret; 1030 1031 if (fs_set_blk_dev(ifname, dev_part_str, FS_TYPE_ANY)) 1032 return log_msg_ret("set", -ENOMEDIUM); 1033 1034 ret = fs_size(fname, &size); 1035 if (ret) 1036 return log_msg_ret("sz", -ENOENT); 1037 1038 if (size >= (max_size ?: SZ_1G)) 1039 return log_msg_ret("sz", -E2BIG); 1040 1041 if (fs_set_blk_dev(ifname, dev_part_str, FS_TYPE_ANY)) 1042 return log_msg_ret("set", -ENOMEDIUM); 1043 1044 ret = fs_read_alloc(fname, size, align, &buf); 1045 if (ret) 1046 return log_msg_ret("al", ret); 1047 *sizep = size; 1048 *bufp = buf; 1049 1050 return 0; 1051} 1052