iomux-v3: Take MX6D in consideration for imx_iomux_v3_setup_pad()
[oweals/u-boot.git] / fs / fs.c
1 /*
2  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 #include <config.h>
18 #include <errno.h>
19 #include <common.h>
20 #include <mapmem.h>
21 #include <part.h>
22 #include <ext4fs.h>
23 #include <fat.h>
24 #include <fs.h>
25 #include <sandboxfs.h>
26 #include <ubifs_uboot.h>
27 #include <asm/io.h>
28 #include <div64.h>
29 #include <linux/math64.h>
30
31 DECLARE_GLOBAL_DATA_PTR;
32
33 static block_dev_desc_t *fs_dev_desc;
34 static disk_partition_t fs_partition;
35 static int fs_type = FS_TYPE_ANY;
36
37 static inline int fs_probe_unsupported(block_dev_desc_t *fs_dev_desc,
38                                       disk_partition_t *fs_partition)
39 {
40         printf("** Unrecognized filesystem type **\n");
41         return -1;
42 }
43
44 static inline int fs_ls_unsupported(const char *dirname)
45 {
46         return -1;
47 }
48
49 static inline int fs_exists_unsupported(const char *filename)
50 {
51         return 0;
52 }
53
54 static inline int fs_size_unsupported(const char *filename, loff_t *size)
55 {
56         return -1;
57 }
58
59 static inline int fs_read_unsupported(const char *filename, void *buf,
60                                       loff_t offset, loff_t len,
61                                       loff_t *actread)
62 {
63         return -1;
64 }
65
66 static inline int fs_write_unsupported(const char *filename, void *buf,
67                                       loff_t offset, loff_t len,
68                                       loff_t *actwrite)
69 {
70         return -1;
71 }
72
73 static inline void fs_close_unsupported(void)
74 {
75 }
76
77 static inline int fs_uuid_unsupported(char *uuid_str)
78 {
79         return -1;
80 }
81
82 struct fstype_info {
83         int fstype;
84         char *name;
85         /*
86          * Is it legal to pass NULL as .probe()'s  fs_dev_desc parameter? This
87          * should be false in most cases. For "virtual" filesystems which
88          * aren't based on a U-Boot block device (e.g. sandbox), this can be
89          * set to true. This should also be true for the dumm entry at the end
90          * of fstypes[], since that is essentially a "virtual" (non-existent)
91          * filesystem.
92          */
93         bool null_dev_desc_ok;
94         int (*probe)(block_dev_desc_t *fs_dev_desc,
95                      disk_partition_t *fs_partition);
96         int (*ls)(const char *dirname);
97         int (*exists)(const char *filename);
98         int (*size)(const char *filename, loff_t *size);
99         int (*read)(const char *filename, void *buf, loff_t offset,
100                     loff_t len, loff_t *actread);
101         int (*write)(const char *filename, void *buf, loff_t offset,
102                      loff_t len, loff_t *actwrite);
103         void (*close)(void);
104         int (*uuid)(char *uuid_str);
105 };
106
107 static struct fstype_info fstypes[] = {
108 #ifdef CONFIG_FS_FAT
109         {
110                 .fstype = FS_TYPE_FAT,
111                 .name = "fat",
112                 .null_dev_desc_ok = false,
113                 .probe = fat_set_blk_dev,
114                 .close = fat_close,
115                 .ls = file_fat_ls,
116                 .exists = fat_exists,
117                 .size = fat_size,
118                 .read = fat_read_file,
119 #ifdef CONFIG_FAT_WRITE
120                 .write = file_fat_write,
121 #else
122                 .write = fs_write_unsupported,
123 #endif
124                 .uuid = fs_uuid_unsupported,
125         },
126 #endif
127 #ifdef CONFIG_FS_EXT4
128         {
129                 .fstype = FS_TYPE_EXT,
130                 .name = "ext4",
131                 .null_dev_desc_ok = false,
132                 .probe = ext4fs_probe,
133                 .close = ext4fs_close,
134                 .ls = ext4fs_ls,
135                 .exists = ext4fs_exists,
136                 .size = ext4fs_size,
137                 .read = ext4_read_file,
138 #ifdef CONFIG_CMD_EXT4_WRITE
139                 .write = ext4_write_file,
140 #else
141                 .write = fs_write_unsupported,
142 #endif
143                 .uuid = ext4fs_uuid,
144         },
145 #endif
146 #ifdef CONFIG_SANDBOX
147         {
148                 .fstype = FS_TYPE_SANDBOX,
149                 .name = "sandbox",
150                 .null_dev_desc_ok = true,
151                 .probe = sandbox_fs_set_blk_dev,
152                 .close = sandbox_fs_close,
153                 .ls = sandbox_fs_ls,
154                 .exists = sandbox_fs_exists,
155                 .size = sandbox_fs_size,
156                 .read = fs_read_sandbox,
157                 .write = fs_write_sandbox,
158                 .uuid = fs_uuid_unsupported,
159         },
160 #endif
161 #ifdef CONFIG_CMD_UBIFS
162         {
163                 .fstype = FS_TYPE_UBIFS,
164                 .name = "ubifs",
165                 .null_dev_desc_ok = true,
166                 .probe = ubifs_set_blk_dev,
167                 .close = ubifs_close,
168                 .ls = ubifs_ls,
169                 .exists = ubifs_exists,
170                 .size = ubifs_size,
171                 .read = ubifs_read,
172                 .write = fs_write_unsupported,
173                 .uuid = fs_uuid_unsupported,
174         },
175 #endif
176         {
177                 .fstype = FS_TYPE_ANY,
178                 .name = "unsupported",
179                 .null_dev_desc_ok = true,
180                 .probe = fs_probe_unsupported,
181                 .close = fs_close_unsupported,
182                 .ls = fs_ls_unsupported,
183                 .exists = fs_exists_unsupported,
184                 .size = fs_size_unsupported,
185                 .read = fs_read_unsupported,
186                 .write = fs_write_unsupported,
187                 .uuid = fs_uuid_unsupported,
188         },
189 };
190
191 static struct fstype_info *fs_get_info(int fstype)
192 {
193         struct fstype_info *info;
194         int i;
195
196         for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
197                 if (fstype == info->fstype)
198                         return info;
199         }
200
201         /* Return the 'unsupported' sentinel */
202         return info;
203 }
204
205 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
206 {
207         struct fstype_info *info;
208         int part, i;
209 #ifdef CONFIG_NEEDS_MANUAL_RELOC
210         static int relocated;
211
212         if (!relocated) {
213                 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
214                                 i++, info++) {
215                         info->name += gd->reloc_off;
216                         info->probe += gd->reloc_off;
217                         info->close += gd->reloc_off;
218                         info->ls += gd->reloc_off;
219                         info->read += gd->reloc_off;
220                         info->write += gd->reloc_off;
221                 }
222                 relocated = 1;
223         }
224 #endif
225
226         part = get_device_and_partition(ifname, dev_part_str, &fs_dev_desc,
227                                         &fs_partition, 1);
228         if (part < 0)
229                 return -1;
230
231         for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
232                 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
233                                 fstype != info->fstype)
234                         continue;
235
236                 if (!fs_dev_desc && !info->null_dev_desc_ok)
237                         continue;
238
239                 if (!info->probe(fs_dev_desc, &fs_partition)) {
240                         fs_type = info->fstype;
241                         return 0;
242                 }
243         }
244
245         return -1;
246 }
247
248 static void fs_close(void)
249 {
250         struct fstype_info *info = fs_get_info(fs_type);
251
252         info->close();
253
254         fs_type = FS_TYPE_ANY;
255 }
256
257 int fs_uuid(char *uuid_str)
258 {
259         struct fstype_info *info = fs_get_info(fs_type);
260
261         return info->uuid(uuid_str);
262 }
263
264 int fs_ls(const char *dirname)
265 {
266         int ret;
267
268         struct fstype_info *info = fs_get_info(fs_type);
269
270         ret = info->ls(dirname);
271
272         fs_type = FS_TYPE_ANY;
273         fs_close();
274
275         return ret;
276 }
277
278 int fs_exists(const char *filename)
279 {
280         int ret;
281
282         struct fstype_info *info = fs_get_info(fs_type);
283
284         ret = info->exists(filename);
285
286         fs_close();
287
288         return ret;
289 }
290
291 int fs_size(const char *filename, loff_t *size)
292 {
293         int ret;
294
295         struct fstype_info *info = fs_get_info(fs_type);
296
297         ret = info->size(filename, size);
298
299         fs_close();
300
301         return ret;
302 }
303
304 int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
305             loff_t *actread)
306 {
307         struct fstype_info *info = fs_get_info(fs_type);
308         void *buf;
309         int ret;
310
311         /*
312          * We don't actually know how many bytes are being read, since len==0
313          * means read the whole file.
314          */
315         buf = map_sysmem(addr, len);
316         ret = info->read(filename, buf, offset, len, actread);
317         unmap_sysmem(buf);
318
319         /* If we requested a specific number of bytes, check we got it */
320         if (ret == 0 && len && *actread != len)
321                 printf("** %s shorter than offset + len **\n", filename);
322         fs_close();
323
324         return ret;
325 }
326
327 int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
328              loff_t *actwrite)
329 {
330         struct fstype_info *info = fs_get_info(fs_type);
331         void *buf;
332         int ret;
333
334         buf = map_sysmem(addr, len);
335         ret = info->write(filename, buf, offset, len, actwrite);
336         unmap_sysmem(buf);
337
338         if (ret < 0 && len != *actwrite) {
339                 printf("** Unable to write file %s **\n", filename);
340                 ret = -1;
341         }
342         fs_close();
343
344         return ret;
345 }
346
347 int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
348                 int fstype)
349 {
350         loff_t size;
351
352         if (argc != 4)
353                 return CMD_RET_USAGE;
354
355         if (fs_set_blk_dev(argv[1], argv[2], fstype))
356                 return 1;
357
358         if (fs_size(argv[3], &size) < 0)
359                 return CMD_RET_FAILURE;
360
361         setenv_hex("filesize", size);
362
363         return 0;
364 }
365
366 int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
367                 int fstype)
368 {
369         unsigned long addr;
370         const char *addr_str;
371         const char *filename;
372         loff_t bytes;
373         loff_t pos;
374         loff_t len_read;
375         int ret;
376         unsigned long time;
377         char *ep;
378
379         if (argc < 2)
380                 return CMD_RET_USAGE;
381         if (argc > 7)
382                 return CMD_RET_USAGE;
383
384         if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
385                 return 1;
386
387         if (argc >= 4) {
388                 addr = simple_strtoul(argv[3], &ep, 16);
389                 if (ep == argv[3] || *ep != '\0')
390                         return CMD_RET_USAGE;
391         } else {
392                 addr_str = getenv("loadaddr");
393                 if (addr_str != NULL)
394                         addr = simple_strtoul(addr_str, NULL, 16);
395                 else
396                         addr = CONFIG_SYS_LOAD_ADDR;
397         }
398         if (argc >= 5) {
399                 filename = argv[4];
400         } else {
401                 filename = getenv("bootfile");
402                 if (!filename) {
403                         puts("** No boot file defined **\n");
404                         return 1;
405                 }
406         }
407         if (argc >= 6)
408                 bytes = simple_strtoul(argv[5], NULL, 16);
409         else
410                 bytes = 0;
411         if (argc >= 7)
412                 pos = simple_strtoul(argv[6], NULL, 16);
413         else
414                 pos = 0;
415
416         time = get_timer(0);
417         ret = fs_read(filename, addr, pos, bytes, &len_read);
418         time = get_timer(time);
419         if (ret < 0)
420                 return 1;
421
422         printf("%llu bytes read in %lu ms", len_read, time);
423         if (time > 0) {
424                 puts(" (");
425                 print_size(div_u64(len_read, time) * 1000, "/s");
426                 puts(")");
427         }
428         puts("\n");
429
430         setenv_hex("filesize", len_read);
431
432         return 0;
433 }
434
435 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
436         int fstype)
437 {
438         if (argc < 2)
439                 return CMD_RET_USAGE;
440         if (argc > 4)
441                 return CMD_RET_USAGE;
442
443         if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
444                 return 1;
445
446         if (fs_ls(argc >= 4 ? argv[3] : "/"))
447                 return 1;
448
449         return 0;
450 }
451
452 int file_exists(const char *dev_type, const char *dev_part, const char *file,
453                 int fstype)
454 {
455         if (fs_set_blk_dev(dev_type, dev_part, fstype))
456                 return 0;
457
458         return fs_exists(file);
459 }
460
461 int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
462                 int fstype)
463 {
464         unsigned long addr;
465         const char *filename;
466         loff_t bytes;
467         loff_t pos;
468         loff_t len;
469         int ret;
470         unsigned long time;
471
472         if (argc < 6 || argc > 7)
473                 return CMD_RET_USAGE;
474
475         if (fs_set_blk_dev(argv[1], argv[2], fstype))
476                 return 1;
477
478         addr = simple_strtoul(argv[3], NULL, 16);
479         filename = argv[4];
480         bytes = simple_strtoul(argv[5], NULL, 16);
481         if (argc >= 7)
482                 pos = simple_strtoul(argv[6], NULL, 16);
483         else
484                 pos = 0;
485
486         time = get_timer(0);
487         ret = fs_write(filename, addr, pos, bytes, &len);
488         time = get_timer(time);
489         if (ret < 0)
490                 return 1;
491
492         printf("%llu bytes written in %lu ms", len, time);
493         if (time > 0) {
494                 puts(" (");
495                 print_size(div_u64(len, time) * 1000, "/s");
496                 puts(")");
497         }
498         puts("\n");
499
500         return 0;
501 }
502
503 int do_fs_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
504                 int fstype)
505 {
506         int ret;
507         char uuid[37];
508         memset(uuid, 0, sizeof(uuid));
509
510         if (argc < 3 || argc > 4)
511                 return CMD_RET_USAGE;
512
513         if (fs_set_blk_dev(argv[1], argv[2], fstype))
514                 return 1;
515
516         ret = fs_uuid(uuid);
517         if (ret)
518                 return CMD_RET_FAILURE;
519
520         if (argc == 4)
521                 setenv(argv[3], uuid);
522         else
523                 printf("%s\n", uuid);
524
525         return CMD_RET_SUCCESS;
526 }
527
528 int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
529 {
530         struct fstype_info *info;
531
532         if (argc < 3 || argc > 4)
533                 return CMD_RET_USAGE;
534
535         if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
536                 return 1;
537
538         info = fs_get_info(fs_type);
539
540         if (argc == 4)
541                 setenv(argv[3], info->name);
542         else
543                 printf("%s\n", info->name);
544
545         return CMD_RET_SUCCESS;
546 }
547