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 .opendir = fs_opendir_unsupported, 237 }, 238 #endif 239 { 240 .fstype = FS_TYPE_ANY, 241 .name = "unsupported", 242 .null_dev_desc_ok = true, 243 .probe = fs_probe_unsupported, 244 .close = fs_close_unsupported, 245 .ls = fs_ls_unsupported, 246 .exists = fs_exists_unsupported, 247 .size = fs_size_unsupported, 248 .read = fs_read_unsupported, 249 .write = fs_write_unsupported, 250 .uuid = fs_uuid_unsupported, 251 .opendir = fs_opendir_unsupported, 252 }, 253 }; 254 255 static struct fstype_info *fs_get_info(int fstype) 256 { 257 struct fstype_info *info; 258 int i; 259 260 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) { 261 if (fstype == info->fstype) 262 return info; 263 } 264 265 /* Return the 'unsupported' sentinel */ 266 return info; 267 } 268 269 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype) 270 { 271 struct fstype_info *info; 272 int part, i; 273 #ifdef CONFIG_NEEDS_MANUAL_RELOC 274 static int relocated; 275 276 if (!relocated) { 277 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); 278 i++, info++) { 279 info->name += gd->reloc_off; 280 info->probe += gd->reloc_off; 281 info->close += gd->reloc_off; 282 info->ls += gd->reloc_off; 283 info->read += gd->reloc_off; 284 info->write += gd->reloc_off; 285 } 286 relocated = 1; 287 } 288 #endif 289 290 part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc, 291 &fs_partition, 1); 292 if (part < 0) 293 return -1; 294 295 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) { 296 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY && 297 fstype != info->fstype) 298 continue; 299 300 if (!fs_dev_desc && !info->null_dev_desc_ok) 301 continue; 302 303 if (!info->probe(fs_dev_desc, &fs_partition)) { 304 fs_type = info->fstype; 305 fs_dev_part = part; 306 return 0; 307 } 308 } 309 310 return -1; 311 } 312 313 /* set current blk device w/ blk_desc + partition # */ 314 int fs_set_blk_dev_with_part(struct blk_desc *desc, int part) 315 { 316 struct fstype_info *info; 317 int ret, i; 318 319 if (part >= 1) 320 ret = part_get_info(desc, part, &fs_partition); 321 else 322 ret = part_get_info_whole_disk(desc, &fs_partition); 323 if (ret) 324 return ret; 325 fs_dev_desc = desc; 326 327 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) { 328 if (!info->probe(fs_dev_desc, &fs_partition)) { 329 fs_type = info->fstype; 330 return 0; 331 } 332 } 333 334 return -1; 335 } 336 337 static void fs_close(void) 338 { 339 struct fstype_info *info = fs_get_info(fs_type); 340 341 info->close(); 342 343 fs_type = FS_TYPE_ANY; 344 } 345 346 int fs_uuid(char *uuid_str) 347 { 348 struct fstype_info *info = fs_get_info(fs_type); 349 350 return info->uuid(uuid_str); 351 } 352 353 int fs_ls(const char *dirname) 354 { 355 int ret; 356 357 struct fstype_info *info = fs_get_info(fs_type); 358 359 ret = info->ls(dirname); 360 361 fs_type = FS_TYPE_ANY; 362 fs_close(); 363 364 return ret; 365 } 366 367 int fs_exists(const char *filename) 368 { 369 int ret; 370 371 struct fstype_info *info = fs_get_info(fs_type); 372 373 ret = info->exists(filename); 374 375 fs_close(); 376 377 return ret; 378 } 379 380 int fs_size(const char *filename, loff_t *size) 381 { 382 int ret; 383 384 struct fstype_info *info = fs_get_info(fs_type); 385 386 ret = info->size(filename, size); 387 388 fs_close(); 389 390 return ret; 391 } 392 393 int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, 394 loff_t *actread) 395 { 396 struct fstype_info *info = fs_get_info(fs_type); 397 void *buf; 398 int ret; 399 400 /* 401 * We don't actually know how many bytes are being read, since len==0 402 * means read the whole file. 403 */ 404 buf = map_sysmem(addr, len); 405 ret = info->read(filename, buf, offset, len, actread); 406 unmap_sysmem(buf); 407 408 /* If we requested a specific number of bytes, check we got it */ 409 if (ret == 0 && len && *actread != len) 410 printf("** %s shorter than offset + len **\n", filename); 411 fs_close(); 412 413 return ret; 414 } 415 416 int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, 417 loff_t *actwrite) 418 { 419 struct fstype_info *info = fs_get_info(fs_type); 420 void *buf; 421 int ret; 422 423 buf = map_sysmem(addr, len); 424 ret = info->write(filename, buf, offset, len, actwrite); 425 unmap_sysmem(buf); 426 427 if (ret < 0 && len != *actwrite) { 428 printf("** Unable to write file %s **\n", filename); 429 ret = -1; 430 } 431 fs_close(); 432 433 return ret; 434 } 435 436 struct fs_dir_stream *fs_opendir(const char *filename) 437 { 438 struct fstype_info *info = fs_get_info(fs_type); 439 struct fs_dir_stream *dirs = NULL; 440 int ret; 441 442 ret = info->opendir(filename, &dirs); 443 fs_close(); 444 if (ret) { 445 errno = -ret; 446 return NULL; 447 } 448 449 dirs->desc = fs_dev_desc; 450 dirs->part = fs_dev_part; 451 452 return dirs; 453 } 454 455 struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs) 456 { 457 struct fstype_info *info; 458 struct fs_dirent *dirent; 459 int ret; 460 461 fs_set_blk_dev_with_part(dirs->desc, dirs->part); 462 info = fs_get_info(fs_type); 463 464 ret = info->readdir(dirs, &dirent); 465 fs_close(); 466 if (ret) { 467 errno = -ret; 468 return NULL; 469 } 470 471 return dirent; 472 } 473 474 void fs_closedir(struct fs_dir_stream *dirs) 475 { 476 struct fstype_info *info; 477 478 if (!dirs) 479 return; 480 481 fs_set_blk_dev_with_part(dirs->desc, dirs->part); 482 info = fs_get_info(fs_type); 483 484 info->closedir(dirs); 485 fs_close(); 486 } 487 488 489 int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 490 int fstype) 491 { 492 loff_t size; 493 494 if (argc != 4) 495 return CMD_RET_USAGE; 496 497 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 498 return 1; 499 500 if (fs_size(argv[3], &size) < 0) 501 return CMD_RET_FAILURE; 502 503 env_set_hex("filesize", size); 504 505 return 0; 506 } 507 508 int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 509 int fstype) 510 { 511 unsigned long addr; 512 const char *addr_str; 513 const char *filename; 514 loff_t bytes; 515 loff_t pos; 516 loff_t len_read; 517 int ret; 518 unsigned long time; 519 char *ep; 520 521 if (argc < 2) 522 return CMD_RET_USAGE; 523 if (argc > 7) 524 return CMD_RET_USAGE; 525 526 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype)) 527 return 1; 528 529 if (argc >= 4) { 530 addr = simple_strtoul(argv[3], &ep, 16); 531 if (ep == argv[3] || *ep != '\0') 532 return CMD_RET_USAGE; 533 } else { 534 addr_str = env_get("loadaddr"); 535 if (addr_str != NULL) 536 addr = simple_strtoul(addr_str, NULL, 16); 537 else 538 addr = CONFIG_SYS_LOAD_ADDR; 539 } 540 if (argc >= 5) { 541 filename = argv[4]; 542 } else { 543 filename = env_get("bootfile"); 544 if (!filename) { 545 puts("** No boot file defined **\n"); 546 return 1; 547 } 548 } 549 if (argc >= 6) 550 bytes = simple_strtoul(argv[5], NULL, 16); 551 else 552 bytes = 0; 553 if (argc >= 7) 554 pos = simple_strtoul(argv[6], NULL, 16); 555 else 556 pos = 0; 557 558 time = get_timer(0); 559 ret = fs_read(filename, addr, pos, bytes, &len_read); 560 time = get_timer(time); 561 if (ret < 0) 562 return 1; 563 564 printf("%llu bytes read in %lu ms", len_read, time); 565 if (time > 0) { 566 puts(" ("); 567 print_size(div_u64(len_read, time) * 1000, "/s"); 568 puts(")"); 569 } 570 puts("\n"); 571 572 env_set_hex("fileaddr", addr); 573 env_set_hex("filesize", len_read); 574 575 return 0; 576 } 577 578 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 579 int fstype) 580 { 581 if (argc < 2) 582 return CMD_RET_USAGE; 583 if (argc > 4) 584 return CMD_RET_USAGE; 585 586 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype)) 587 return 1; 588 589 if (fs_ls(argc >= 4 ? argv[3] : "/")) 590 return 1; 591 592 return 0; 593 } 594 595 int file_exists(const char *dev_type, const char *dev_part, const char *file, 596 int fstype) 597 { 598 if (fs_set_blk_dev(dev_type, dev_part, fstype)) 599 return 0; 600 601 return fs_exists(file); 602 } 603 604 int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 605 int fstype) 606 { 607 unsigned long addr; 608 const char *filename; 609 loff_t bytes; 610 loff_t pos; 611 loff_t len; 612 int ret; 613 unsigned long time; 614 615 if (argc < 6 || argc > 7) 616 return CMD_RET_USAGE; 617 618 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 619 return 1; 620 621 addr = simple_strtoul(argv[3], NULL, 16); 622 filename = argv[4]; 623 bytes = simple_strtoul(argv[5], NULL, 16); 624 if (argc >= 7) 625 pos = simple_strtoul(argv[6], NULL, 16); 626 else 627 pos = 0; 628 629 time = get_timer(0); 630 ret = fs_write(filename, addr, pos, bytes, &len); 631 time = get_timer(time); 632 if (ret < 0) 633 return 1; 634 635 printf("%llu bytes written in %lu ms", len, time); 636 if (time > 0) { 637 puts(" ("); 638 print_size(div_u64(len, time) * 1000, "/s"); 639 puts(")"); 640 } 641 puts("\n"); 642 643 return 0; 644 } 645 646 int do_fs_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 647 int fstype) 648 { 649 int ret; 650 char uuid[37]; 651 memset(uuid, 0, sizeof(uuid)); 652 653 if (argc < 3 || argc > 4) 654 return CMD_RET_USAGE; 655 656 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 657 return 1; 658 659 ret = fs_uuid(uuid); 660 if (ret) 661 return CMD_RET_FAILURE; 662 663 if (argc == 4) 664 env_set(argv[3], uuid); 665 else 666 printf("%s\n", uuid); 667 668 return CMD_RET_SUCCESS; 669 } 670 671 int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 672 { 673 struct fstype_info *info; 674 675 if (argc < 3 || argc > 4) 676 return CMD_RET_USAGE; 677 678 if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY)) 679 return 1; 680 681 info = fs_get_info(fs_type); 682 683 if (argc == 4) 684 env_set(argv[3], info->name); 685 else 686 printf("%s\n", info->name); 687 688 return CMD_RET_SUCCESS; 689 } 690 691