1 /* 2 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 3 * 4 * SPDX-License-Identifier: GPL-2.0 5 */ 6 7 #include <config.h> 8 #include <errno.h> 9 #include <common.h> 10 #include <mapmem.h> 11 #include <part.h> 12 #include <ext4fs.h> 13 #include <fat.h> 14 #include <fs.h> 15 #include <sandboxfs.h> 16 #include <ubifs_uboot.h> 17 #include <btrfs.h> 18 #include <asm/io.h> 19 #include <div64.h> 20 #include <linux/math64.h> 21 22 DECLARE_GLOBAL_DATA_PTR; 23 24 static struct blk_desc *fs_dev_desc; 25 static int fs_dev_part; 26 static disk_partition_t fs_partition; 27 static int fs_type = FS_TYPE_ANY; 28 29 static inline int fs_probe_unsupported(struct blk_desc *fs_dev_desc, 30 disk_partition_t *fs_partition) 31 { 32 printf("** Unrecognized filesystem type **\n"); 33 return -1; 34 } 35 36 static inline int fs_ls_unsupported(const char *dirname) 37 { 38 return -1; 39 } 40 41 /* generic implementation of ls in terms of opendir/readdir/closedir */ 42 __maybe_unused 43 static int fs_ls_generic(const char *dirname) 44 { 45 struct fs_dir_stream *dirs; 46 struct fs_dirent *dent; 47 int nfiles = 0, ndirs = 0; 48 49 dirs = fs_opendir(dirname); 50 if (!dirs) 51 return -errno; 52 53 while ((dent = fs_readdir(dirs))) { 54 if (dent->type == FS_DT_DIR) { 55 printf(" %s/\n", dent->name); 56 ndirs++; 57 } else { 58 printf(" %8lld %s\n", dent->size, dent->name); 59 nfiles++; 60 } 61 } 62 63 fs_closedir(dirs); 64 65 printf("\n%d file(s), %d dir(s)\n\n", nfiles, ndirs); 66 67 return 0; 68 } 69 70 static inline int fs_exists_unsupported(const char *filename) 71 { 72 return 0; 73 } 74 75 static inline int fs_size_unsupported(const char *filename, loff_t *size) 76 { 77 return -1; 78 } 79 80 static inline int fs_read_unsupported(const char *filename, void *buf, 81 loff_t offset, loff_t len, 82 loff_t *actread) 83 { 84 return -1; 85 } 86 87 static inline int fs_write_unsupported(const char *filename, void *buf, 88 loff_t offset, loff_t len, 89 loff_t *actwrite) 90 { 91 return -1; 92 } 93 94 static inline void fs_close_unsupported(void) 95 { 96 } 97 98 static inline int fs_uuid_unsupported(char *uuid_str) 99 { 100 return -1; 101 } 102 103 static inline int fs_opendir_unsupported(const char *filename, 104 struct fs_dir_stream **dirs) 105 { 106 return -EACCES; 107 } 108 109 struct fstype_info { 110 int fstype; 111 char *name; 112 /* 113 * Is it legal to pass NULL as .probe()'s fs_dev_desc parameter? This 114 * should be false in most cases. For "virtual" filesystems which 115 * aren't based on a U-Boot block device (e.g. sandbox), this can be 116 * set to true. This should also be true for the dumm entry at the end 117 * of fstypes[], since that is essentially a "virtual" (non-existent) 118 * filesystem. 119 */ 120 bool null_dev_desc_ok; 121 int (*probe)(struct blk_desc *fs_dev_desc, 122 disk_partition_t *fs_partition); 123 int (*ls)(const char *dirname); 124 int (*exists)(const char *filename); 125 int (*size)(const char *filename, loff_t *size); 126 int (*read)(const char *filename, void *buf, loff_t offset, 127 loff_t len, loff_t *actread); 128 int (*write)(const char *filename, void *buf, loff_t offset, 129 loff_t len, loff_t *actwrite); 130 void (*close)(void); 131 int (*uuid)(char *uuid_str); 132 /* 133 * Open a directory stream. On success return 0 and directory 134 * stream pointer via 'dirsp'. On error, return -errno. See 135 * fs_opendir(). 136 */ 137 int (*opendir)(const char *filename, struct fs_dir_stream **dirsp); 138 /* 139 * Read next entry from directory stream. On success return 0 140 * and directory entry pointer via 'dentp'. On error return 141 * -errno. See fs_readdir(). 142 */ 143 int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp); 144 /* see fs_closedir() */ 145 void (*closedir)(struct fs_dir_stream *dirs); 146 }; 147 148 static struct fstype_info fstypes[] = { 149 #ifdef CONFIG_FS_FAT 150 { 151 .fstype = FS_TYPE_FAT, 152 .name = "fat", 153 .null_dev_desc_ok = false, 154 .probe = fat_set_blk_dev, 155 .close = fat_close, 156 .ls = fs_ls_generic, 157 .exists = fat_exists, 158 .size = fat_size, 159 .read = fat_read_file, 160 #ifdef CONFIG_FAT_WRITE 161 .write = file_fat_write, 162 #else 163 .write = fs_write_unsupported, 164 #endif 165 .uuid = fs_uuid_unsupported, 166 .opendir = fat_opendir, 167 .readdir = fat_readdir, 168 .closedir = fat_closedir, 169 }, 170 #endif 171 #ifdef CONFIG_FS_EXT4 172 { 173 .fstype = FS_TYPE_EXT, 174 .name = "ext4", 175 .null_dev_desc_ok = false, 176 .probe = ext4fs_probe, 177 .close = ext4fs_close, 178 .ls = ext4fs_ls, 179 .exists = ext4fs_exists, 180 .size = ext4fs_size, 181 .read = ext4_read_file, 182 #ifdef CONFIG_CMD_EXT4_WRITE 183 .write = ext4_write_file, 184 #else 185 .write = fs_write_unsupported, 186 #endif 187 .uuid = ext4fs_uuid, 188 .opendir = fs_opendir_unsupported, 189 }, 190 #endif 191 #ifdef CONFIG_SANDBOX 192 { 193 .fstype = FS_TYPE_SANDBOX, 194 .name = "sandbox", 195 .null_dev_desc_ok = true, 196 .probe = sandbox_fs_set_blk_dev, 197 .close = sandbox_fs_close, 198 .ls = sandbox_fs_ls, 199 .exists = sandbox_fs_exists, 200 .size = sandbox_fs_size, 201 .read = fs_read_sandbox, 202 .write = fs_write_sandbox, 203 .uuid = fs_uuid_unsupported, 204 .opendir = fs_opendir_unsupported, 205 }, 206 #endif 207 #ifdef CONFIG_CMD_UBIFS 208 { 209 .fstype = FS_TYPE_UBIFS, 210 .name = "ubifs", 211 .null_dev_desc_ok = true, 212 .probe = ubifs_set_blk_dev, 213 .close = ubifs_close, 214 .ls = ubifs_ls, 215 .exists = ubifs_exists, 216 .size = ubifs_size, 217 .read = ubifs_read, 218 .write = fs_write_unsupported, 219 .uuid = fs_uuid_unsupported, 220 .opendir = fs_opendir_unsupported, 221 }, 222 #endif 223 #ifdef CONFIG_FS_BTRFS 224 { 225 .fstype = FS_TYPE_BTRFS, 226 .name = "btrfs", 227 .null_dev_desc_ok = false, 228 .probe = btrfs_probe, 229 .close = btrfs_close, 230 .ls = btrfs_ls, 231 .exists = btrfs_exists, 232 .size = btrfs_size, 233 .read = btrfs_read, 234 .write = fs_write_unsupported, 235 .uuid = btrfs_uuid, 236 }, 237 #endif 238 { 239 .fstype = FS_TYPE_ANY, 240 .name = "unsupported", 241 .null_dev_desc_ok = true, 242 .probe = fs_probe_unsupported, 243 .close = fs_close_unsupported, 244 .ls = fs_ls_unsupported, 245 .exists = fs_exists_unsupported, 246 .size = fs_size_unsupported, 247 .read = fs_read_unsupported, 248 .write = fs_write_unsupported, 249 .uuid = fs_uuid_unsupported, 250 .opendir = fs_opendir_unsupported, 251 }, 252 }; 253 254 static struct fstype_info *fs_get_info(int fstype) 255 { 256 struct fstype_info *info; 257 int i; 258 259 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) { 260 if (fstype == info->fstype) 261 return info; 262 } 263 264 /* Return the 'unsupported' sentinel */ 265 return info; 266 } 267 268 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype) 269 { 270 struct fstype_info *info; 271 int part, i; 272 #ifdef CONFIG_NEEDS_MANUAL_RELOC 273 static int relocated; 274 275 if (!relocated) { 276 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); 277 i++, info++) { 278 info->name += gd->reloc_off; 279 info->probe += gd->reloc_off; 280 info->close += gd->reloc_off; 281 info->ls += gd->reloc_off; 282 info->read += gd->reloc_off; 283 info->write += gd->reloc_off; 284 } 285 relocated = 1; 286 } 287 #endif 288 289 part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc, 290 &fs_partition, 1); 291 if (part < 0) 292 return -1; 293 294 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) { 295 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY && 296 fstype != info->fstype) 297 continue; 298 299 if (!fs_dev_desc && !info->null_dev_desc_ok) 300 continue; 301 302 if (!info->probe(fs_dev_desc, &fs_partition)) { 303 fs_type = info->fstype; 304 fs_dev_part = part; 305 return 0; 306 } 307 } 308 309 return -1; 310 } 311 312 /* set current blk device w/ blk_desc + partition # */ 313 int fs_set_blk_dev_with_part(struct blk_desc *desc, int part) 314 { 315 struct fstype_info *info; 316 int ret, i; 317 318 if (part >= 1) 319 ret = part_get_info(desc, part, &fs_partition); 320 else 321 ret = part_get_info_whole_disk(desc, &fs_partition); 322 if (ret) 323 return ret; 324 fs_dev_desc = desc; 325 326 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) { 327 if (!info->probe(fs_dev_desc, &fs_partition)) { 328 fs_type = info->fstype; 329 return 0; 330 } 331 } 332 333 return -1; 334 } 335 336 static void fs_close(void) 337 { 338 struct fstype_info *info = fs_get_info(fs_type); 339 340 info->close(); 341 342 fs_type = FS_TYPE_ANY; 343 } 344 345 int fs_uuid(char *uuid_str) 346 { 347 struct fstype_info *info = fs_get_info(fs_type); 348 349 return info->uuid(uuid_str); 350 } 351 352 int fs_ls(const char *dirname) 353 { 354 int ret; 355 356 struct fstype_info *info = fs_get_info(fs_type); 357 358 ret = info->ls(dirname); 359 360 fs_type = FS_TYPE_ANY; 361 fs_close(); 362 363 return ret; 364 } 365 366 int fs_exists(const char *filename) 367 { 368 int ret; 369 370 struct fstype_info *info = fs_get_info(fs_type); 371 372 ret = info->exists(filename); 373 374 fs_close(); 375 376 return ret; 377 } 378 379 int fs_size(const char *filename, loff_t *size) 380 { 381 int ret; 382 383 struct fstype_info *info = fs_get_info(fs_type); 384 385 ret = info->size(filename, size); 386 387 fs_close(); 388 389 return ret; 390 } 391 392 int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, 393 loff_t *actread) 394 { 395 struct fstype_info *info = fs_get_info(fs_type); 396 void *buf; 397 int ret; 398 399 /* 400 * We don't actually know how many bytes are being read, since len==0 401 * means read the whole file. 402 */ 403 buf = map_sysmem(addr, len); 404 ret = info->read(filename, buf, offset, len, actread); 405 unmap_sysmem(buf); 406 407 /* If we requested a specific number of bytes, check we got it */ 408 if (ret == 0 && len && *actread != len) 409 printf("** %s shorter than offset + len **\n", filename); 410 fs_close(); 411 412 return ret; 413 } 414 415 int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, 416 loff_t *actwrite) 417 { 418 struct fstype_info *info = fs_get_info(fs_type); 419 void *buf; 420 int ret; 421 422 buf = map_sysmem(addr, len); 423 ret = info->write(filename, buf, offset, len, actwrite); 424 unmap_sysmem(buf); 425 426 if (ret < 0 && len != *actwrite) { 427 printf("** Unable to write file %s **\n", filename); 428 ret = -1; 429 } 430 fs_close(); 431 432 return ret; 433 } 434 435 struct fs_dir_stream *fs_opendir(const char *filename) 436 { 437 struct fstype_info *info = fs_get_info(fs_type); 438 struct fs_dir_stream *dirs = NULL; 439 int ret; 440 441 ret = info->opendir(filename, &dirs); 442 fs_close(); 443 if (ret) { 444 errno = -ret; 445 return NULL; 446 } 447 448 dirs->desc = fs_dev_desc; 449 dirs->part = fs_dev_part; 450 451 return dirs; 452 } 453 454 struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs) 455 { 456 struct fstype_info *info; 457 struct fs_dirent *dirent; 458 int ret; 459 460 fs_set_blk_dev_with_part(dirs->desc, dirs->part); 461 info = fs_get_info(fs_type); 462 463 ret = info->readdir(dirs, &dirent); 464 fs_close(); 465 if (ret) { 466 errno = -ret; 467 return NULL; 468 } 469 470 return dirent; 471 } 472 473 void fs_closedir(struct fs_dir_stream *dirs) 474 { 475 struct fstype_info *info; 476 477 if (!dirs) 478 return; 479 480 fs_set_blk_dev_with_part(dirs->desc, dirs->part); 481 info = fs_get_info(fs_type); 482 483 info->closedir(dirs); 484 fs_close(); 485 } 486 487 488 int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 489 int fstype) 490 { 491 loff_t size; 492 493 if (argc != 4) 494 return CMD_RET_USAGE; 495 496 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 497 return 1; 498 499 if (fs_size(argv[3], &size) < 0) 500 return CMD_RET_FAILURE; 501 502 env_set_hex("filesize", size); 503 504 return 0; 505 } 506 507 int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 508 int fstype) 509 { 510 unsigned long addr; 511 const char *addr_str; 512 const char *filename; 513 loff_t bytes; 514 loff_t pos; 515 loff_t len_read; 516 int ret; 517 unsigned long time; 518 char *ep; 519 520 if (argc < 2) 521 return CMD_RET_USAGE; 522 if (argc > 7) 523 return CMD_RET_USAGE; 524 525 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype)) 526 return 1; 527 528 if (argc >= 4) { 529 addr = simple_strtoul(argv[3], &ep, 16); 530 if (ep == argv[3] || *ep != '\0') 531 return CMD_RET_USAGE; 532 } else { 533 addr_str = env_get("loadaddr"); 534 if (addr_str != NULL) 535 addr = simple_strtoul(addr_str, NULL, 16); 536 else 537 addr = CONFIG_SYS_LOAD_ADDR; 538 } 539 if (argc >= 5) { 540 filename = argv[4]; 541 } else { 542 filename = env_get("bootfile"); 543 if (!filename) { 544 puts("** No boot file defined **\n"); 545 return 1; 546 } 547 } 548 if (argc >= 6) 549 bytes = simple_strtoul(argv[5], NULL, 16); 550 else 551 bytes = 0; 552 if (argc >= 7) 553 pos = simple_strtoul(argv[6], NULL, 16); 554 else 555 pos = 0; 556 557 time = get_timer(0); 558 ret = fs_read(filename, addr, pos, bytes, &len_read); 559 time = get_timer(time); 560 if (ret < 0) 561 return 1; 562 563 printf("%llu bytes read in %lu ms", len_read, time); 564 if (time > 0) { 565 puts(" ("); 566 print_size(div_u64(len_read, time) * 1000, "/s"); 567 puts(")"); 568 } 569 puts("\n"); 570 571 env_set_hex("fileaddr", addr); 572 env_set_hex("filesize", len_read); 573 574 return 0; 575 } 576 577 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 578 int fstype) 579 { 580 if (argc < 2) 581 return CMD_RET_USAGE; 582 if (argc > 4) 583 return CMD_RET_USAGE; 584 585 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype)) 586 return 1; 587 588 if (fs_ls(argc >= 4 ? argv[3] : "/")) 589 return 1; 590 591 return 0; 592 } 593 594 int file_exists(const char *dev_type, const char *dev_part, const char *file, 595 int fstype) 596 { 597 if (fs_set_blk_dev(dev_type, dev_part, fstype)) 598 return 0; 599 600 return fs_exists(file); 601 } 602 603 int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 604 int fstype) 605 { 606 unsigned long addr; 607 const char *filename; 608 loff_t bytes; 609 loff_t pos; 610 loff_t len; 611 int ret; 612 unsigned long time; 613 614 if (argc < 6 || argc > 7) 615 return CMD_RET_USAGE; 616 617 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 618 return 1; 619 620 addr = simple_strtoul(argv[3], NULL, 16); 621 filename = argv[4]; 622 bytes = simple_strtoul(argv[5], NULL, 16); 623 if (argc >= 7) 624 pos = simple_strtoul(argv[6], NULL, 16); 625 else 626 pos = 0; 627 628 time = get_timer(0); 629 ret = fs_write(filename, addr, pos, bytes, &len); 630 time = get_timer(time); 631 if (ret < 0) 632 return 1; 633 634 printf("%llu bytes written in %lu ms", len, time); 635 if (time > 0) { 636 puts(" ("); 637 print_size(div_u64(len, time) * 1000, "/s"); 638 puts(")"); 639 } 640 puts("\n"); 641 642 return 0; 643 } 644 645 int do_fs_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 646 int fstype) 647 { 648 int ret; 649 char uuid[37]; 650 memset(uuid, 0, sizeof(uuid)); 651 652 if (argc < 3 || argc > 4) 653 return CMD_RET_USAGE; 654 655 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 656 return 1; 657 658 ret = fs_uuid(uuid); 659 if (ret) 660 return CMD_RET_FAILURE; 661 662 if (argc == 4) 663 env_set(argv[3], uuid); 664 else 665 printf("%s\n", uuid); 666 667 return CMD_RET_SUCCESS; 668 } 669 670 int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 671 { 672 struct fstype_info *info; 673 674 if (argc < 3 || argc > 4) 675 return CMD_RET_USAGE; 676 677 if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY)) 678 return 1; 679 680 info = fs_get_info(fs_type); 681 682 if (argc == 4) 683 env_set(argv[3], info->name); 684 else 685 printf("%s\n", info->name); 686 687 return CMD_RET_SUCCESS; 688 } 689 690