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