Blame view

fs/fs.c 8.32 KB
045fa1e11   Stephen Warren   fs: add filesyste...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /*
   * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms and conditions of the GNU General Public License,
   * version 2, as published by the Free Software Foundation.
   *
   * This program is distributed in the hope it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   * more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  #include <config.h>
  #include <common.h>
  #include <part.h>
  #include <ext4fs.h>
  #include <fat.h>
  #include <fs.h>
92ccc96bf   Simon Glass   sandbox: Add host...
23
  #include <sandboxfs.h>
117e05072   Simon Glass   fs: Use map_sysme...
24
  #include <asm/io.h>
045fa1e11   Stephen Warren   fs: add filesyste...
25

a1b231cef   Stephen Warren   fs: handle CONFIG...
26
  DECLARE_GLOBAL_DATA_PTR;
045fa1e11   Stephen Warren   fs: add filesyste...
27
28
29
  static block_dev_desc_t *fs_dev_desc;
  static disk_partition_t fs_partition;
  static int fs_type = FS_TYPE_ANY;
2ded0d471   Simon Glass   fs: Tell probe fu...
30
31
  static inline int fs_probe_unsupported(block_dev_desc_t *fs_dev_desc,
  				      disk_partition_t *fs_partition)
436e2b731   Simon Glass   fs: Fully populat...
32
33
34
35
36
  {
  	printf("** Unrecognized filesystem type **
  ");
  	return -1;
  }
045fa1e11   Stephen Warren   fs: add filesyste...
37
38
  static inline int fs_ls_unsupported(const char *dirname)
  {
045fa1e11   Stephen Warren   fs: add filesyste...
39
40
  	return -1;
  }
6152916a9   Stephen Warren   fs: implement inf...
41
42
43
44
  static inline int fs_exists_unsupported(const char *filename)
  {
  	return 0;
  }
117e05072   Simon Glass   fs: Use map_sysme...
45
  static inline int fs_read_unsupported(const char *filename, void *buf,
045fa1e11   Stephen Warren   fs: add filesyste...
46
47
  				      int offset, int len)
  {
045fa1e11   Stephen Warren   fs: add filesyste...
48
49
  	return -1;
  }
a8f6ab522   Simon Glass   fs: Add support f...
50
51
52
53
54
  static inline int fs_write_unsupported(const char *filename, void *buf,
  				      int offset, int len)
  {
  	return -1;
  }
436e2b731   Simon Glass   fs: Fully populat...
55
56
57
  static inline void fs_close_unsupported(void)
  {
  }
436e2b731   Simon Glass   fs: Fully populat...
58
  struct fstype_info {
045fa1e11   Stephen Warren   fs: add filesyste...
59
  	int fstype;
377202b56   Stephen Warren   fs: don't pass NU...
60
61
62
63
64
65
66
67
68
  	/*
  	 * Is it legal to pass NULL as .probe()'s  fs_dev_desc parameter? This
  	 * should be false in most cases. For "virtual" filesystems which
  	 * aren't based on a U-Boot block device (e.g. sandbox), this can be
  	 * set to true. This should also be true for the dumm entry at the end
  	 * of fstypes[], since that is essentially a "virtual" (non-existent)
  	 * filesystem.
  	 */
  	bool null_dev_desc_ok;
2ded0d471   Simon Glass   fs: Tell probe fu...
69
70
  	int (*probe)(block_dev_desc_t *fs_dev_desc,
  		     disk_partition_t *fs_partition);
436e2b731   Simon Glass   fs: Fully populat...
71
  	int (*ls)(const char *dirname);
6152916a9   Stephen Warren   fs: implement inf...
72
  	int (*exists)(const char *filename);
117e05072   Simon Glass   fs: Use map_sysme...
73
  	int (*read)(const char *filename, void *buf, int offset, int len);
a8f6ab522   Simon Glass   fs: Add support f...
74
  	int (*write)(const char *filename, void *buf, int offset, int len);
436e2b731   Simon Glass   fs: Fully populat...
75
76
77
78
79
  	void (*close)(void);
  };
  
  static struct fstype_info fstypes[] = {
  #ifdef CONFIG_FS_FAT
045fa1e11   Stephen Warren   fs: add filesyste...
80
81
  	{
  		.fstype = FS_TYPE_FAT,
377202b56   Stephen Warren   fs: don't pass NU...
82
  		.null_dev_desc_ok = false,
e6d524153   Simon Glass   fs: Move ls and r...
83
84
  		.probe = fat_set_blk_dev,
  		.close = fat_close,
436e2b731   Simon Glass   fs: Fully populat...
85
  		.ls = file_fat_ls,
b7b5f3195   Stephen Warren   fat: implement ex...
86
  		.exists = fat_exists,
e6d524153   Simon Glass   fs: Move ls and r...
87
  		.read = fat_read_file,
bd6fb31fa   Stephen Warren   fs: fix generic s...
88
  		.write = fs_write_unsupported,
045fa1e11   Stephen Warren   fs: add filesyste...
89
  	},
436e2b731   Simon Glass   fs: Fully populat...
90
91
  #endif
  #ifdef CONFIG_FS_EXT4
045fa1e11   Stephen Warren   fs: add filesyste...
92
93
  	{
  		.fstype = FS_TYPE_EXT,
377202b56   Stephen Warren   fs: don't pass NU...
94
  		.null_dev_desc_ok = false,
e6d524153   Simon Glass   fs: Move ls and r...
95
96
  		.probe = ext4fs_probe,
  		.close = ext4fs_close,
436e2b731   Simon Glass   fs: Fully populat...
97
  		.ls = ext4fs_ls,
55af5c931   Stephen Warren   ext4: implement e...
98
  		.exists = ext4fs_exists,
e6d524153   Simon Glass   fs: Move ls and r...
99
  		.read = ext4_read_file,
bd6fb31fa   Stephen Warren   fs: fix generic s...
100
  		.write = fs_write_unsupported,
436e2b731   Simon Glass   fs: Fully populat...
101
102
  	},
  #endif
92ccc96bf   Simon Glass   sandbox: Add host...
103
104
105
  #ifdef CONFIG_SANDBOX
  	{
  		.fstype = FS_TYPE_SANDBOX,
377202b56   Stephen Warren   fs: don't pass NU...
106
  		.null_dev_desc_ok = true,
92ccc96bf   Simon Glass   sandbox: Add host...
107
108
109
  		.probe = sandbox_fs_set_blk_dev,
  		.close = sandbox_fs_close,
  		.ls = sandbox_fs_ls,
0a30aa1e7   Stephen Warren   sandbox: implemen...
110
  		.exists = sandbox_fs_exists,
92ccc96bf   Simon Glass   sandbox: Add host...
111
  		.read = fs_read_sandbox,
7eb2c8d57   Simon Glass   sandbox: fs: Add ...
112
  		.write = fs_write_sandbox,
92ccc96bf   Simon Glass   sandbox: Add host...
113
114
  	},
  #endif
436e2b731   Simon Glass   fs: Fully populat...
115
116
  	{
  		.fstype = FS_TYPE_ANY,
377202b56   Stephen Warren   fs: don't pass NU...
117
  		.null_dev_desc_ok = true,
436e2b731   Simon Glass   fs: Fully populat...
118
119
120
  		.probe = fs_probe_unsupported,
  		.close = fs_close_unsupported,
  		.ls = fs_ls_unsupported,
6152916a9   Stephen Warren   fs: implement inf...
121
  		.exists = fs_exists_unsupported,
436e2b731   Simon Glass   fs: Fully populat...
122
  		.read = fs_read_unsupported,
a8f6ab522   Simon Glass   fs: Add support f...
123
  		.write = fs_write_unsupported,
045fa1e11   Stephen Warren   fs: add filesyste...
124
125
  	},
  };
c6f548d23   Simon Glass   fs: Use filesyste...
126
127
128
129
130
131
132
133
134
135
136
137
138
  static struct fstype_info *fs_get_info(int fstype)
  {
  	struct fstype_info *info;
  	int i;
  
  	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
  		if (fstype == info->fstype)
  			return info;
  	}
  
  	/* Return the 'unsupported' sentinel */
  	return info;
  }
045fa1e11   Stephen Warren   fs: add filesyste...
139
140
  int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
  {
436e2b731   Simon Glass   fs: Fully populat...
141
  	struct fstype_info *info;
045fa1e11   Stephen Warren   fs: add filesyste...
142
  	int part, i;
a1b231cef   Stephen Warren   fs: handle CONFIG...
143
144
145
146
  #ifdef CONFIG_NEEDS_MANUAL_RELOC
  	static int relocated;
  
  	if (!relocated) {
436e2b731   Simon Glass   fs: Fully populat...
147
148
149
150
151
152
  		for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
  				i++, info++) {
  			info->probe += gd->reloc_off;
  			info->close += gd->reloc_off;
  			info->ls += gd->reloc_off;
  			info->read += gd->reloc_off;
a8f6ab522   Simon Glass   fs: Add support f...
153
  			info->write += gd->reloc_off;
436e2b731   Simon Glass   fs: Fully populat...
154
  		}
a1b231cef   Stephen Warren   fs: handle CONFIG...
155
156
157
  		relocated = 1;
  	}
  #endif
045fa1e11   Stephen Warren   fs: add filesyste...
158
159
160
161
162
  
  	part = get_device_and_partition(ifname, dev_part_str, &fs_dev_desc,
  					&fs_partition, 1);
  	if (part < 0)
  		return -1;
436e2b731   Simon Glass   fs: Fully populat...
163
164
165
  	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
  		if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
  				fstype != info->fstype)
045fa1e11   Stephen Warren   fs: add filesyste...
166
  			continue;
377202b56   Stephen Warren   fs: don't pass NU...
167
168
  		if (!fs_dev_desc && !info->null_dev_desc_ok)
  			continue;
2ded0d471   Simon Glass   fs: Tell probe fu...
169
  		if (!info->probe(fs_dev_desc, &fs_partition)) {
436e2b731   Simon Glass   fs: Fully populat...
170
  			fs_type = info->fstype;
045fa1e11   Stephen Warren   fs: add filesyste...
171
172
173
  			return 0;
  		}
  	}
045fa1e11   Stephen Warren   fs: add filesyste...
174
175
176
177
178
  	return -1;
  }
  
  static void fs_close(void)
  {
c6f548d23   Simon Glass   fs: Use filesyste...
179
  	struct fstype_info *info = fs_get_info(fs_type);
045fa1e11   Stephen Warren   fs: add filesyste...
180

c6f548d23   Simon Glass   fs: Use filesyste...
181
  	info->close();
e6d524153   Simon Glass   fs: Move ls and r...
182

045fa1e11   Stephen Warren   fs: add filesyste...
183
184
185
186
187
188
  	fs_type = FS_TYPE_ANY;
  }
  
  int fs_ls(const char *dirname)
  {
  	int ret;
c6f548d23   Simon Glass   fs: Use filesyste...
189
190
191
  	struct fstype_info *info = fs_get_info(fs_type);
  
  	ret = info->ls(dirname);
045fa1e11   Stephen Warren   fs: add filesyste...
192

e6d524153   Simon Glass   fs: Move ls and r...
193
  	fs_type = FS_TYPE_ANY;
045fa1e11   Stephen Warren   fs: add filesyste...
194
195
196
197
  	fs_close();
  
  	return ret;
  }
6152916a9   Stephen Warren   fs: implement inf...
198
199
200
201
202
203
204
205
206
207
208
209
  int fs_exists(const char *filename)
  {
  	int ret;
  
  	struct fstype_info *info = fs_get_info(fs_type);
  
  	ret = info->exists(filename);
  
  	fs_close();
  
  	return ret;
  }
045fa1e11   Stephen Warren   fs: add filesyste...
210
211
  int fs_read(const char *filename, ulong addr, int offset, int len)
  {
c6f548d23   Simon Glass   fs: Use filesyste...
212
  	struct fstype_info *info = fs_get_info(fs_type);
117e05072   Simon Glass   fs: Use map_sysme...
213
  	void *buf;
045fa1e11   Stephen Warren   fs: add filesyste...
214
  	int ret;
117e05072   Simon Glass   fs: Use map_sysme...
215
216
217
218
219
220
221
  	/*
  	 * We don't actually know how many bytes are being read, since len==0
  	 * means read the whole file.
  	 */
  	buf = map_sysmem(addr, len);
  	ret = info->read(filename, buf, offset, len);
  	unmap_sysmem(buf);
045fa1e11   Stephen Warren   fs: add filesyste...
222

c6f548d23   Simon Glass   fs: Use filesyste...
223
224
225
226
227
228
  	/* If we requested a specific number of bytes, check we got it */
  	if (ret >= 0 && len && ret != len) {
  		printf("** Unable to read file %s **
  ", filename);
  		ret = -1;
  	}
045fa1e11   Stephen Warren   fs: add filesyste...
229
230
231
232
  	fs_close();
  
  	return ret;
  }
a8f6ab522   Simon Glass   fs: Add support f...
233
234
235
236
237
  int fs_write(const char *filename, ulong addr, int offset, int len)
  {
  	struct fstype_info *info = fs_get_info(fs_type);
  	void *buf;
  	int ret;
a8f6ab522   Simon Glass   fs: Add support f...
238
239
240
  	buf = map_sysmem(addr, len);
  	ret = info->write(filename, buf, offset, len);
  	unmap_sysmem(buf);
bd6fb31fa   Stephen Warren   fs: fix generic s...
241
  	if (ret >= 0 && ret != len) {
a8f6ab522   Simon Glass   fs: Add support f...
242
243
244
245
246
247
248
249
  		printf("** Unable to write file %s **
  ", filename);
  		ret = -1;
  	}
  	fs_close();
  
  	return ret;
  }
f9b55e228   Stephen Warren   fs: rename fsload...
250
  int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
b770e88a6   Wolfgang Denk   Fix number base h...
251
  		int fstype)
045fa1e11   Stephen Warren   fs: add filesyste...
252
253
254
255
256
257
258
  {
  	unsigned long addr;
  	const char *addr_str;
  	const char *filename;
  	unsigned long bytes;
  	unsigned long pos;
  	int len_read;
da1fd96ce   Andreas Bießmann   fs/fs.c: do_fsloa...
259
  	unsigned long time;
045fa1e11   Stephen Warren   fs: add filesyste...
260

e9b0f99e8   Stephen Warren   fs: fix do_fsload...
261
262
263
  	if (argc < 2)
  		return CMD_RET_USAGE;
  	if (argc > 7)
045fa1e11   Stephen Warren   fs: add filesyste...
264
  		return CMD_RET_USAGE;
e9b0f99e8   Stephen Warren   fs: fix do_fsload...
265
  	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
045fa1e11   Stephen Warren   fs: add filesyste...
266
267
268
  		return 1;
  
  	if (argc >= 4) {
b770e88a6   Wolfgang Denk   Fix number base h...
269
  		addr = simple_strtoul(argv[3], NULL, 16);
045fa1e11   Stephen Warren   fs: add filesyste...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  	} else {
  		addr_str = getenv("loadaddr");
  		if (addr_str != NULL)
  			addr = simple_strtoul(addr_str, NULL, 16);
  		else
  			addr = CONFIG_SYS_LOAD_ADDR;
  	}
  	if (argc >= 5) {
  		filename = argv[4];
  	} else {
  		filename = getenv("bootfile");
  		if (!filename) {
  			puts("** No boot file defined **
  ");
  			return 1;
  		}
  	}
  	if (argc >= 6)
b770e88a6   Wolfgang Denk   Fix number base h...
288
  		bytes = simple_strtoul(argv[5], NULL, 16);
045fa1e11   Stephen Warren   fs: add filesyste...
289
290
291
  	else
  		bytes = 0;
  	if (argc >= 7)
b770e88a6   Wolfgang Denk   Fix number base h...
292
  		pos = simple_strtoul(argv[6], NULL, 16);
045fa1e11   Stephen Warren   fs: add filesyste...
293
294
  	else
  		pos = 0;
da1fd96ce   Andreas Bießmann   fs/fs.c: do_fsloa...
295
  	time = get_timer(0);
045fa1e11   Stephen Warren   fs: add filesyste...
296
  	len_read = fs_read(filename, addr, pos, bytes);
da1fd96ce   Andreas Bießmann   fs/fs.c: do_fsloa...
297
  	time = get_timer(time);
045fa1e11   Stephen Warren   fs: add filesyste...
298
299
  	if (len_read <= 0)
  		return 1;
da1fd96ce   Andreas Bießmann   fs/fs.c: do_fsloa...
300
301
302
303
304
305
306
307
  	printf("%d bytes read in %lu ms", len_read, time);
  	if (time > 0) {
  		puts(" (");
  		print_size(len_read / time * 1000, "/s");
  		puts(")");
  	}
  	puts("
  ");
045fa1e11   Stephen Warren   fs: add filesyste...
308

49c4f0370   Simon Glass   fs: Use new numer...
309
  	setenv_hex("filesize", len_read);
045fa1e11   Stephen Warren   fs: add filesyste...
310
311
312
313
314
315
316
317
318
  
  	return 0;
  }
  
  int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
  	int fstype)
  {
  	if (argc < 2)
  		return CMD_RET_USAGE;
e9b0f99e8   Stephen Warren   fs: fix do_fsload...
319
320
  	if (argc > 4)
  		return CMD_RET_USAGE;
045fa1e11   Stephen Warren   fs: add filesyste...
321
322
323
  
  	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
  		return 1;
e9b0f99e8   Stephen Warren   fs: fix do_fsload...
324
  	if (fs_ls(argc >= 4 ? argv[3] : "/"))
045fa1e11   Stephen Warren   fs: add filesyste...
325
326
327
328
  		return 1;
  
  	return 0;
  }
a8f6ab522   Simon Glass   fs: Add support f...
329

6152916a9   Stephen Warren   fs: implement inf...
330
331
332
333
334
335
336
337
  int file_exists(const char *dev_type, const char *dev_part, const char *file,
  		int fstype)
  {
  	if (fs_set_blk_dev(dev_type, dev_part, fstype))
  		return 0;
  
  	return fs_exists(file);
  }
a8f6ab522   Simon Glass   fs: Add support f...
338
  int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
b770e88a6   Wolfgang Denk   Fix number base h...
339
  		int fstype)
a8f6ab522   Simon Glass   fs: Add support f...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
  {
  	unsigned long addr;
  	const char *filename;
  	unsigned long bytes;
  	unsigned long pos;
  	int len;
  	unsigned long time;
  
  	if (argc < 6 || argc > 7)
  		return CMD_RET_USAGE;
  
  	if (fs_set_blk_dev(argv[1], argv[2], fstype))
  		return 1;
  
  	filename = argv[3];
b770e88a6   Wolfgang Denk   Fix number base h...
355
356
  	addr = simple_strtoul(argv[4], NULL, 16);
  	bytes = simple_strtoul(argv[5], NULL, 16);
a8f6ab522   Simon Glass   fs: Add support f...
357
  	if (argc >= 7)
b770e88a6   Wolfgang Denk   Fix number base h...
358
  		pos = simple_strtoul(argv[6], NULL, 16);
a8f6ab522   Simon Glass   fs: Add support f...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  	else
  		pos = 0;
  
  	time = get_timer(0);
  	len = fs_write(filename, addr, pos, bytes);
  	time = get_timer(time);
  	if (len <= 0)
  		return 1;
  
  	printf("%d bytes written in %lu ms", len, time);
  	if (time > 0) {
  		puts(" (");
  		print_size(len / time * 1000, "/s");
  		puts(")");
  	}
  	puts("
  ");
  
  	return 0;
  }