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