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