]> git.sur5r.net Git - u-boot/blob - fs/fs.c
0cbec9958e7631001138c56fb2f1c20df28aa4ce
[u-boot] / 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 <common.h>
19 #include <part.h>
20 #include <ext4fs.h>
21 #include <fat.h>
22 #include <fs.h>
23 #include <asm/io.h>
24
25 DECLARE_GLOBAL_DATA_PTR;
26
27 static block_dev_desc_t *fs_dev_desc;
28 static disk_partition_t fs_partition;
29 static int fs_type = FS_TYPE_ANY;
30
31 static inline int fs_probe_unsupported(block_dev_desc_t *fs_dev_desc,
32                                       disk_partition_t *fs_partition)
33 {
34         printf("** Unrecognized filesystem type **\n");
35         return -1;
36 }
37
38 static inline int fs_ls_unsupported(const char *dirname)
39 {
40         return -1;
41 }
42
43 static inline int fs_read_unsupported(const char *filename, void *buf,
44                                       int offset, int len)
45 {
46         return -1;
47 }
48
49 static inline void fs_close_unsupported(void)
50 {
51 }
52
53 #ifdef CONFIG_FS_FAT
54 static int fs_probe_fat(block_dev_desc_t *fs_dev_desc,
55                         disk_partition_t *fs_partition)
56 {
57         return fat_set_blk_dev(fs_dev_desc, fs_partition);
58 }
59
60 static void fs_close_fat(void)
61 {
62 }
63
64 #define fs_ls_fat file_fat_ls
65
66 static int fs_read_fat(const char *filename, void *buf, int offset, int len)
67 {
68         int len_read;
69
70         len_read = file_fat_read_at(filename, offset, buf, len);
71         if (len_read == -1) {
72                 printf("** Unable to read file %s **\n", filename);
73                 return -1;
74         }
75
76         return len_read;
77 }
78 #else
79 static inline int fs_probe_fat(void)
80 {
81         return -1;
82 }
83
84 static inline void fs_close_fat(void)
85 {
86 }
87
88 #define fs_ls_fat fs_ls_unsupported
89 #define fs_read_fat fs_read_unsupported
90 #endif
91
92 #ifdef CONFIG_FS_EXT4
93 static int fs_probe_ext(block_dev_desc_t *fs_dev_desc,
94                         disk_partition_t *fs_partition)
95 {
96         ext4fs_set_blk_dev(fs_dev_desc, fs_partition);
97
98         if (!ext4fs_mount(fs_partition->size)) {
99                 ext4fs_close();
100                 return -1;
101         }
102
103         return 0;
104 }
105
106 static void fs_close_ext(void)
107 {
108         ext4fs_close();
109 }
110
111 #define fs_ls_ext ext4fs_ls
112
113 static int fs_read_ext(const char *filename, void *buf, int offset, int len)
114 {
115         int file_len;
116         int len_read;
117
118         if (offset != 0) {
119                 printf("** Cannot support non-zero offset **\n");
120                 return -1;
121         }
122
123         file_len = ext4fs_open(filename);
124         if (file_len < 0) {
125                 printf("** File not found %s **\n", filename);
126                 ext4fs_close();
127                 return -1;
128         }
129
130         if (len == 0)
131                 len = file_len;
132
133         len_read = ext4fs_read(buf, len);
134         ext4fs_close();
135
136         if (len_read != len) {
137                 printf("** Unable to read file %s **\n", filename);
138                 return -1;
139         }
140
141         return len_read;
142 }
143 #else
144 static inline int fs_probe_ext(void)
145 {
146         return -1;
147 }
148
149 static inline void fs_close_ext(void)
150 {
151 }
152
153 #define fs_ls_ext fs_ls_unsupported
154 #define fs_read_ext fs_read_unsupported
155 #endif
156
157 struct fstype_info {
158         int fstype;
159         int (*probe)(block_dev_desc_t *fs_dev_desc,
160                      disk_partition_t *fs_partition);
161         int (*ls)(const char *dirname);
162         int (*read)(const char *filename, void *buf, int offset, int len);
163         void (*close)(void);
164 };
165
166 static struct fstype_info fstypes[] = {
167 #ifdef CONFIG_FS_FAT
168         {
169                 .fstype = FS_TYPE_FAT,
170                 .probe = fs_probe_fat,
171                 .close = fs_close_fat,
172                 .ls = file_fat_ls,
173                 .read = fs_read_fat,
174         },
175 #endif
176 #ifdef CONFIG_FS_EXT4
177         {
178                 .fstype = FS_TYPE_EXT,
179                 .probe = fs_probe_ext,
180                 .close = fs_close_ext,
181                 .ls = ext4fs_ls,
182                 .read = fs_read_ext,
183         },
184 #endif
185         {
186                 .fstype = FS_TYPE_ANY,
187                 .probe = fs_probe_unsupported,
188                 .close = fs_close_unsupported,
189                 .ls = fs_ls_unsupported,
190                 .read = fs_read_unsupported,
191         },
192 };
193
194 static struct fstype_info *fs_get_info(int fstype)
195 {
196         struct fstype_info *info;
197         int i;
198
199         for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
200                 if (fstype == info->fstype)
201                         return info;
202         }
203
204         /* Return the 'unsupported' sentinel */
205         return info;
206 }
207
208 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
209 {
210         struct fstype_info *info;
211         int part, i;
212 #ifdef CONFIG_NEEDS_MANUAL_RELOC
213         static int relocated;
214
215         if (!relocated) {
216                 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
217                                 i++, info++) {
218                         info->probe += gd->reloc_off;
219                         info->close += gd->reloc_off;
220                         info->ls += gd->reloc_off;
221                         info->read += gd->reloc_off;
222                 }
223                 relocated = 1;
224         }
225 #endif
226
227         part = get_device_and_partition(ifname, dev_part_str, &fs_dev_desc,
228                                         &fs_partition, 1);
229         if (part < 0)
230                 return -1;
231
232         for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
233                 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
234                                 fstype != info->fstype)
235                         continue;
236
237                 if (!info->probe(fs_dev_desc, &fs_partition)) {
238                         fs_type = info->fstype;
239                         return 0;
240                 }
241         }
242
243         return -1;
244 }
245
246 static void fs_close(void)
247 {
248         struct fstype_info *info = fs_get_info(fs_type);
249
250         info->close();
251         fs_type = FS_TYPE_ANY;
252 }
253
254 int fs_ls(const char *dirname)
255 {
256         int ret;
257
258         struct fstype_info *info = fs_get_info(fs_type);
259
260         ret = info->ls(dirname);
261
262         fs_close();
263
264         return ret;
265 }
266
267 int fs_read(const char *filename, ulong addr, int offset, int len)
268 {
269         struct fstype_info *info = fs_get_info(fs_type);
270         void *buf;
271         int ret;
272
273         /*
274          * We don't actually know how many bytes are being read, since len==0
275          * means read the whole file.
276          */
277         buf = map_sysmem(addr, len);
278         ret = info->read(filename, buf, offset, len);
279         unmap_sysmem(buf);
280
281         /* If we requested a specific number of bytes, check we got it */
282         if (ret >= 0 && len && ret != len) {
283                 printf("** Unable to read file %s **\n", filename);
284                 ret = -1;
285         }
286         fs_close();
287
288         return ret;
289 }
290
291 int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
292                 int fstype, int cmdline_base)
293 {
294         unsigned long addr;
295         const char *addr_str;
296         const char *filename;
297         unsigned long bytes;
298         unsigned long pos;
299         int len_read;
300         unsigned long time;
301
302         if (argc < 2)
303                 return CMD_RET_USAGE;
304         if (argc > 7)
305                 return CMD_RET_USAGE;
306
307         if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
308                 return 1;
309
310         if (argc >= 4) {
311                 addr = simple_strtoul(argv[3], NULL, cmdline_base);
312         } else {
313                 addr_str = getenv("loadaddr");
314                 if (addr_str != NULL)
315                         addr = simple_strtoul(addr_str, NULL, 16);
316                 else
317                         addr = CONFIG_SYS_LOAD_ADDR;
318         }
319         if (argc >= 5) {
320                 filename = argv[4];
321         } else {
322                 filename = getenv("bootfile");
323                 if (!filename) {
324                         puts("** No boot file defined **\n");
325                         return 1;
326                 }
327         }
328         if (argc >= 6)
329                 bytes = simple_strtoul(argv[5], NULL, cmdline_base);
330         else
331                 bytes = 0;
332         if (argc >= 7)
333                 pos = simple_strtoul(argv[6], NULL, cmdline_base);
334         else
335                 pos = 0;
336
337         time = get_timer(0);
338         len_read = fs_read(filename, addr, pos, bytes);
339         time = get_timer(time);
340         if (len_read <= 0)
341                 return 1;
342
343         printf("%d bytes read in %lu ms", len_read, time);
344         if (time > 0) {
345                 puts(" (");
346                 print_size(len_read / time * 1000, "/s");
347                 puts(")");
348         }
349         puts("\n");
350
351         setenv_hex("filesize", len_read);
352
353         return 0;
354 }
355
356 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
357         int fstype)
358 {
359         if (argc < 2)
360                 return CMD_RET_USAGE;
361         if (argc > 4)
362                 return CMD_RET_USAGE;
363
364         if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
365                 return 1;
366
367         if (fs_ls(argc >= 4 ? argv[3] : "/"))
368                 return 1;
369
370         return 0;
371 }