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 static void fs_close(void) 321 { 322 struct fstype_info *info = fs_get_info(fs_type); 323 324 info->close(); 325 326 fs_type = FS_TYPE_ANY; 327 } 328 329 int fs_uuid(char *uuid_str) 330 { 331 struct fstype_info *info = fs_get_info(fs_type); 332 333 return info->uuid(uuid_str); 334 } 335 336 int fs_ls(const char *dirname) 337 { 338 int ret; 339 340 struct fstype_info *info = fs_get_info(fs_type); 341 342 ret = info->ls(dirname); 343 344 fs_type = FS_TYPE_ANY; 345 fs_close(); 346 347 return ret; 348 } 349 350 int fs_exists(const char *filename) 351 { 352 int ret; 353 354 struct fstype_info *info = fs_get_info(fs_type); 355 356 ret = info->exists(filename); 357 358 fs_close(); 359 360 return ret; 361 } 362 363 int fs_size(const char *filename, loff_t *size) 364 { 365 int ret; 366 367 struct fstype_info *info = fs_get_info(fs_type); 368 369 ret = info->size(filename, size); 370 371 fs_close(); 372 373 return ret; 374 } 375 376 int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, 377 loff_t *actread) 378 { 379 struct fstype_info *info = fs_get_info(fs_type); 380 void *buf; 381 int ret; 382 383 /* 384 * We don't actually know how many bytes are being read, since len==0 385 * means read the whole file. 386 */ 387 buf = map_sysmem(addr, len); 388 ret = info->read(filename, buf, offset, len, actread); 389 unmap_sysmem(buf); 390 391 /* If we requested a specific number of bytes, check we got it */ 392 if (ret == 0 && len && *actread != len) 393 printf("** %s shorter than offset + len **\n", filename); 394 fs_close(); 395 396 return ret; 397 } 398 399 int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, 400 loff_t *actwrite) 401 { 402 struct fstype_info *info = fs_get_info(fs_type); 403 void *buf; 404 int ret; 405 406 buf = map_sysmem(addr, len); 407 ret = info->write(filename, buf, offset, len, actwrite); 408 unmap_sysmem(buf); 409 410 if (ret < 0 && len != *actwrite) { 411 printf("** Unable to write file %s **\n", filename); 412 ret = -1; 413 } 414 fs_close(); 415 416 return ret; 417 } 418 419 struct fs_dir_stream *fs_opendir(const char *filename) 420 { 421 struct fstype_info *info = fs_get_info(fs_type); 422 struct fs_dir_stream *dirs = NULL; 423 int ret; 424 425 ret = info->opendir(filename, &dirs); 426 fs_close(); 427 if (ret) { 428 errno = -ret; 429 return NULL; 430 } 431 432 dirs->desc = fs_dev_desc; 433 dirs->part = fs_dev_part; 434 435 return dirs; 436 } 437 438 struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs) 439 { 440 struct fstype_info *info; 441 struct fs_dirent *dirent; 442 int ret; 443 444 fs_set_blk_dev_with_part(dirs->desc, dirs->part); 445 info = fs_get_info(fs_type); 446 447 ret = info->readdir(dirs, &dirent); 448 fs_close(); 449 if (ret) { 450 errno = -ret; 451 return NULL; 452 } 453 454 return dirent; 455 } 456 457 void fs_closedir(struct fs_dir_stream *dirs) 458 { 459 struct fstype_info *info; 460 461 if (!dirs) 462 return; 463 464 fs_set_blk_dev_with_part(dirs->desc, dirs->part); 465 info = fs_get_info(fs_type); 466 467 info->closedir(dirs); 468 fs_close(); 469 } 470 471 472 int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 473 int fstype) 474 { 475 loff_t size; 476 477 if (argc != 4) 478 return CMD_RET_USAGE; 479 480 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 481 return 1; 482 483 if (fs_size(argv[3], &size) < 0) 484 return CMD_RET_FAILURE; 485 486 env_set_hex("filesize", size); 487 488 return 0; 489 } 490 491 int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 492 int fstype) 493 { 494 unsigned long addr; 495 const char *addr_str; 496 const char *filename; 497 loff_t bytes; 498 loff_t pos; 499 loff_t len_read; 500 int ret; 501 unsigned long time; 502 char *ep; 503 504 if (argc < 2) 505 return CMD_RET_USAGE; 506 if (argc > 7) 507 return CMD_RET_USAGE; 508 509 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype)) 510 return 1; 511 512 if (argc >= 4) { 513 addr = simple_strtoul(argv[3], &ep, 16); 514 if (ep == argv[3] || *ep != '\0') 515 return CMD_RET_USAGE; 516 } else { 517 addr_str = env_get("loadaddr"); 518 if (addr_str != NULL) 519 addr = simple_strtoul(addr_str, NULL, 16); 520 else 521 addr = CONFIG_SYS_LOAD_ADDR; 522 } 523 if (argc >= 5) { 524 filename = argv[4]; 525 } else { 526 filename = env_get("bootfile"); 527 if (!filename) { 528 puts("** No boot file defined **\n"); 529 return 1; 530 } 531 } 532 if (argc >= 6) 533 bytes = simple_strtoul(argv[5], NULL, 16); 534 else 535 bytes = 0; 536 if (argc >= 7) 537 pos = simple_strtoul(argv[6], NULL, 16); 538 else 539 pos = 0; 540 541 time = get_timer(0); 542 ret = fs_read(filename, addr, pos, bytes, &len_read); 543 time = get_timer(time); 544 if (ret < 0) 545 return 1; 546 547 printf("%llu bytes read in %lu ms", len_read, time); 548 if (time > 0) { 549 puts(" ("); 550 print_size(div_u64(len_read, time) * 1000, "/s"); 551 puts(")"); 552 } 553 puts("\n"); 554 555 env_set_hex("fileaddr", addr); 556 env_set_hex("filesize", len_read); 557 558 return 0; 559 } 560 561 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 562 int fstype) 563 { 564 if (argc < 2) 565 return CMD_RET_USAGE; 566 if (argc > 4) 567 return CMD_RET_USAGE; 568 569 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype)) 570 return 1; 571 572 if (fs_ls(argc >= 4 ? argv[3] : "/")) 573 return 1; 574 575 return 0; 576 } 577 578 int file_exists(const char *dev_type, const char *dev_part, const char *file, 579 int fstype) 580 { 581 if (fs_set_blk_dev(dev_type, dev_part, fstype)) 582 return 0; 583 584 return fs_exists(file); 585 } 586 587 int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 588 int fstype) 589 { 590 unsigned long addr; 591 const char *filename; 592 loff_t bytes; 593 loff_t pos; 594 loff_t len; 595 int ret; 596 unsigned long time; 597 598 if (argc < 6 || argc > 7) 599 return CMD_RET_USAGE; 600 601 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 602 return 1; 603 604 addr = simple_strtoul(argv[3], NULL, 16); 605 filename = argv[4]; 606 bytes = simple_strtoul(argv[5], NULL, 16); 607 if (argc >= 7) 608 pos = simple_strtoul(argv[6], NULL, 16); 609 else 610 pos = 0; 611 612 time = get_timer(0); 613 ret = fs_write(filename, addr, pos, bytes, &len); 614 time = get_timer(time); 615 if (ret < 0) 616 return 1; 617 618 printf("%llu bytes written in %lu ms", len, time); 619 if (time > 0) { 620 puts(" ("); 621 print_size(div_u64(len, time) * 1000, "/s"); 622 puts(")"); 623 } 624 puts("\n"); 625 626 return 0; 627 } 628 629 int do_fs_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 630 int fstype) 631 { 632 int ret; 633 char uuid[37]; 634 memset(uuid, 0, sizeof(uuid)); 635 636 if (argc < 3 || argc > 4) 637 return CMD_RET_USAGE; 638 639 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 640 return 1; 641 642 ret = fs_uuid(uuid); 643 if (ret) 644 return CMD_RET_FAILURE; 645 646 if (argc == 4) 647 env_set(argv[3], uuid); 648 else 649 printf("%s\n", uuid); 650 651 return CMD_RET_SUCCESS; 652 } 653 654 int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 655 { 656 struct fstype_info *info; 657 658 if (argc < 3 || argc > 4) 659 return CMD_RET_USAGE; 660 661 if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY)) 662 return 1; 663 664 info = fs_get_info(fs_type); 665 666 if (argc == 4) 667 env_set(argv[3], info->name); 668 else 669 printf("%s\n", info->name); 670 671 return CMD_RET_SUCCESS; 672 } 673 674