blob: 95c882e2029270c86f414f5ad29a98509631e6e0 [file] [log] [blame]
Stephen Warren045fa1e2012-10-22 06:43:51 +00001/*
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>
Simon Glass117e0502012-12-26 09:53:32 +000023#include <asm/io.h>
Stephen Warren045fa1e2012-10-22 06:43:51 +000024
Stephen Warrena1b231c2012-10-30 07:50:47 +000025DECLARE_GLOBAL_DATA_PTR;
26
Stephen Warren045fa1e2012-10-22 06:43:51 +000027static block_dev_desc_t *fs_dev_desc;
28static disk_partition_t fs_partition;
29static int fs_type = FS_TYPE_ANY;
30
Simon Glass2ded0d42012-12-26 09:53:31 +000031static inline int fs_probe_unsupported(block_dev_desc_t *fs_dev_desc,
32 disk_partition_t *fs_partition)
Simon Glass436e2b72012-12-26 09:53:29 +000033{
34 printf("** Unrecognized filesystem type **\n");
35 return -1;
36}
37
Stephen Warren045fa1e2012-10-22 06:43:51 +000038static inline int fs_ls_unsupported(const char *dirname)
39{
Stephen Warren045fa1e2012-10-22 06:43:51 +000040 return -1;
41}
42
Simon Glass117e0502012-12-26 09:53:32 +000043static inline int fs_read_unsupported(const char *filename, void *buf,
Stephen Warren045fa1e2012-10-22 06:43:51 +000044 int offset, int len)
45{
Stephen Warren045fa1e2012-10-22 06:43:51 +000046 return -1;
47}
48
Simon Glass436e2b72012-12-26 09:53:29 +000049static inline void fs_close_unsupported(void)
50{
51}
52
Simon Glass436e2b72012-12-26 09:53:29 +000053struct fstype_info {
Stephen Warren045fa1e2012-10-22 06:43:51 +000054 int fstype;
Simon Glass2ded0d42012-12-26 09:53:31 +000055 int (*probe)(block_dev_desc_t *fs_dev_desc,
56 disk_partition_t *fs_partition);
Simon Glass436e2b72012-12-26 09:53:29 +000057 int (*ls)(const char *dirname);
Simon Glass117e0502012-12-26 09:53:32 +000058 int (*read)(const char *filename, void *buf, int offset, int len);
Simon Glass436e2b72012-12-26 09:53:29 +000059 void (*close)(void);
60};
61
62static struct fstype_info fstypes[] = {
63#ifdef CONFIG_FS_FAT
Stephen Warren045fa1e2012-10-22 06:43:51 +000064 {
65 .fstype = FS_TYPE_FAT,
Simon Glasse6d52412012-12-26 09:53:33 +000066 .probe = fat_set_blk_dev,
67 .close = fat_close,
Simon Glass436e2b72012-12-26 09:53:29 +000068 .ls = file_fat_ls,
Simon Glasse6d52412012-12-26 09:53:33 +000069 .read = fat_read_file,
Stephen Warren045fa1e2012-10-22 06:43:51 +000070 },
Simon Glass436e2b72012-12-26 09:53:29 +000071#endif
72#ifdef CONFIG_FS_EXT4
Stephen Warren045fa1e2012-10-22 06:43:51 +000073 {
74 .fstype = FS_TYPE_EXT,
Simon Glasse6d52412012-12-26 09:53:33 +000075 .probe = ext4fs_probe,
76 .close = ext4fs_close,
Simon Glass436e2b72012-12-26 09:53:29 +000077 .ls = ext4fs_ls,
Simon Glasse6d52412012-12-26 09:53:33 +000078 .read = ext4_read_file,
Simon Glass436e2b72012-12-26 09:53:29 +000079 },
80#endif
81 {
82 .fstype = FS_TYPE_ANY,
83 .probe = fs_probe_unsupported,
84 .close = fs_close_unsupported,
85 .ls = fs_ls_unsupported,
86 .read = fs_read_unsupported,
Stephen Warren045fa1e2012-10-22 06:43:51 +000087 },
88};
89
Simon Glassc6f548d2012-12-26 09:53:30 +000090static struct fstype_info *fs_get_info(int fstype)
91{
92 struct fstype_info *info;
93 int i;
94
95 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
96 if (fstype == info->fstype)
97 return info;
98 }
99
100 /* Return the 'unsupported' sentinel */
101 return info;
102}
103
Stephen Warren045fa1e2012-10-22 06:43:51 +0000104int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
105{
Simon Glass436e2b72012-12-26 09:53:29 +0000106 struct fstype_info *info;
Stephen Warren045fa1e2012-10-22 06:43:51 +0000107 int part, i;
Stephen Warrena1b231c2012-10-30 07:50:47 +0000108#ifdef CONFIG_NEEDS_MANUAL_RELOC
109 static int relocated;
110
111 if (!relocated) {
Simon Glass436e2b72012-12-26 09:53:29 +0000112 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
113 i++, info++) {
114 info->probe += gd->reloc_off;
115 info->close += gd->reloc_off;
116 info->ls += gd->reloc_off;
117 info->read += gd->reloc_off;
118 }
Stephen Warrena1b231c2012-10-30 07:50:47 +0000119 relocated = 1;
120 }
121#endif
Stephen Warren045fa1e2012-10-22 06:43:51 +0000122
123 part = get_device_and_partition(ifname, dev_part_str, &fs_dev_desc,
124 &fs_partition, 1);
125 if (part < 0)
126 return -1;
127
Simon Glass436e2b72012-12-26 09:53:29 +0000128 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
129 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
130 fstype != info->fstype)
Stephen Warren045fa1e2012-10-22 06:43:51 +0000131 continue;
132
Simon Glass2ded0d42012-12-26 09:53:31 +0000133 if (!info->probe(fs_dev_desc, &fs_partition)) {
Simon Glass436e2b72012-12-26 09:53:29 +0000134 fs_type = info->fstype;
Stephen Warren045fa1e2012-10-22 06:43:51 +0000135 return 0;
136 }
137 }
138
Stephen Warren045fa1e2012-10-22 06:43:51 +0000139 return -1;
140}
141
142static void fs_close(void)
143{
Simon Glassc6f548d2012-12-26 09:53:30 +0000144 struct fstype_info *info = fs_get_info(fs_type);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000145
Simon Glassc6f548d2012-12-26 09:53:30 +0000146 info->close();
Simon Glasse6d52412012-12-26 09:53:33 +0000147
Stephen Warren045fa1e2012-10-22 06:43:51 +0000148 fs_type = FS_TYPE_ANY;
149}
150
151int fs_ls(const char *dirname)
152{
153 int ret;
154
Simon Glassc6f548d2012-12-26 09:53:30 +0000155 struct fstype_info *info = fs_get_info(fs_type);
156
157 ret = info->ls(dirname);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000158
Simon Glasse6d52412012-12-26 09:53:33 +0000159 fs_type = FS_TYPE_ANY;
Stephen Warren045fa1e2012-10-22 06:43:51 +0000160 fs_close();
161
162 return ret;
163}
164
165int fs_read(const char *filename, ulong addr, int offset, int len)
166{
Simon Glassc6f548d2012-12-26 09:53:30 +0000167 struct fstype_info *info = fs_get_info(fs_type);
Simon Glass117e0502012-12-26 09:53:32 +0000168 void *buf;
Stephen Warren045fa1e2012-10-22 06:43:51 +0000169 int ret;
170
Simon Glass117e0502012-12-26 09:53:32 +0000171 /*
172 * We don't actually know how many bytes are being read, since len==0
173 * means read the whole file.
174 */
175 buf = map_sysmem(addr, len);
176 ret = info->read(filename, buf, offset, len);
177 unmap_sysmem(buf);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000178
Simon Glassc6f548d2012-12-26 09:53:30 +0000179 /* If we requested a specific number of bytes, check we got it */
180 if (ret >= 0 && len && ret != len) {
181 printf("** Unable to read file %s **\n", filename);
182 ret = -1;
183 }
Stephen Warren045fa1e2012-10-22 06:43:51 +0000184 fs_close();
185
186 return ret;
187}
188
Stephen Warrenf9b55e22012-10-31 11:05:07 +0000189int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
Stephen Warren3f83c872012-10-30 12:04:19 +0000190 int fstype, int cmdline_base)
Stephen Warren045fa1e2012-10-22 06:43:51 +0000191{
192 unsigned long addr;
193 const char *addr_str;
194 const char *filename;
195 unsigned long bytes;
196 unsigned long pos;
197 int len_read;
Andreas Bießmannda1fd962012-11-14 13:32:37 +0100198 unsigned long time;
Stephen Warren045fa1e2012-10-22 06:43:51 +0000199
Stephen Warrene9b0f992012-10-30 12:04:17 +0000200 if (argc < 2)
201 return CMD_RET_USAGE;
202 if (argc > 7)
Stephen Warren045fa1e2012-10-22 06:43:51 +0000203 return CMD_RET_USAGE;
204
Stephen Warrene9b0f992012-10-30 12:04:17 +0000205 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
Stephen Warren045fa1e2012-10-22 06:43:51 +0000206 return 1;
207
208 if (argc >= 4) {
Stephen Warren3f83c872012-10-30 12:04:19 +0000209 addr = simple_strtoul(argv[3], NULL, cmdline_base);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000210 } else {
211 addr_str = getenv("loadaddr");
212 if (addr_str != NULL)
213 addr = simple_strtoul(addr_str, NULL, 16);
214 else
215 addr = CONFIG_SYS_LOAD_ADDR;
216 }
217 if (argc >= 5) {
218 filename = argv[4];
219 } else {
220 filename = getenv("bootfile");
221 if (!filename) {
222 puts("** No boot file defined **\n");
223 return 1;
224 }
225 }
226 if (argc >= 6)
Stephen Warren3f83c872012-10-30 12:04:19 +0000227 bytes = simple_strtoul(argv[5], NULL, cmdline_base);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000228 else
229 bytes = 0;
230 if (argc >= 7)
Stephen Warren3f83c872012-10-30 12:04:19 +0000231 pos = simple_strtoul(argv[6], NULL, cmdline_base);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000232 else
233 pos = 0;
234
Andreas Bießmannda1fd962012-11-14 13:32:37 +0100235 time = get_timer(0);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000236 len_read = fs_read(filename, addr, pos, bytes);
Andreas Bießmannda1fd962012-11-14 13:32:37 +0100237 time = get_timer(time);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000238 if (len_read <= 0)
239 return 1;
240
Andreas Bießmannda1fd962012-11-14 13:32:37 +0100241 printf("%d bytes read in %lu ms", len_read, time);
242 if (time > 0) {
243 puts(" (");
244 print_size(len_read / time * 1000, "/s");
245 puts(")");
246 }
247 puts("\n");
Stephen Warren045fa1e2012-10-22 06:43:51 +0000248
Simon Glass49c4f032013-02-24 17:33:23 +0000249 setenv_hex("filesize", len_read);
Stephen Warren045fa1e2012-10-22 06:43:51 +0000250
251 return 0;
252}
253
254int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
255 int fstype)
256{
257 if (argc < 2)
258 return CMD_RET_USAGE;
Stephen Warrene9b0f992012-10-30 12:04:17 +0000259 if (argc > 4)
260 return CMD_RET_USAGE;
Stephen Warren045fa1e2012-10-22 06:43:51 +0000261
262 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
263 return 1;
264
Stephen Warrene9b0f992012-10-30 12:04:17 +0000265 if (fs_ls(argc >= 4 ? argv[3] : "/"))
Stephen Warren045fa1e2012-10-22 06:43:51 +0000266 return 1;
267
268 return 0;
269}