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