Blame view

fs/fs.c 9.06 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;
  }
cf6598193   Stephen Warren   fs: implement siz...
45
46
47
48
  static inline int fs_size_unsupported(const char *filename)
  {
  	return -1;
  }
117e05072   Simon Glass   fs: Use map_sysme...
49
  static inline int fs_read_unsupported(const char *filename, void *buf,
045fa1e11   Stephen Warren   fs: add filesyste...
50
51
  				      int offset, int len)
  {
045fa1e11   Stephen Warren   fs: add filesyste...
52
53
  	return -1;
  }
a8f6ab522   Simon Glass   fs: Add support f...
54
55
56
57
58
  static inline int fs_write_unsupported(const char *filename, void *buf,
  				      int offset, int len)
  {
  	return -1;
  }
436e2b731   Simon Glass   fs: Fully populat...
59
60
61
  static inline void fs_close_unsupported(void)
  {
  }
436e2b731   Simon Glass   fs: Fully populat...
62
  struct fstype_info {
045fa1e11   Stephen Warren   fs: add filesyste...
63
  	int fstype;
377202b56   Stephen Warren   fs: don't pass NU...
64
65
66
67
68
69
70
71
72
  	/*
  	 * 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...
73
74
  	int (*probe)(block_dev_desc_t *fs_dev_desc,
  		     disk_partition_t *fs_partition);
436e2b731   Simon Glass   fs: Fully populat...
75
  	int (*ls)(const char *dirname);
6152916a9   Stephen Warren   fs: implement inf...
76
  	int (*exists)(const char *filename);
cf6598193   Stephen Warren   fs: implement siz...
77
  	int (*size)(const char *filename);
117e05072   Simon Glass   fs: Use map_sysme...
78
  	int (*read)(const char *filename, void *buf, int offset, int len);
a8f6ab522   Simon Glass   fs: Add support f...
79
  	int (*write)(const char *filename, void *buf, int offset, int len);
436e2b731   Simon Glass   fs: Fully populat...
80
81
82
83
84
  	void (*close)(void);
  };
  
  static struct fstype_info fstypes[] = {
  #ifdef CONFIG_FS_FAT
045fa1e11   Stephen Warren   fs: add filesyste...
85
86
  	{
  		.fstype = FS_TYPE_FAT,
377202b56   Stephen Warren   fs: don't pass NU...
87
  		.null_dev_desc_ok = false,
e6d524153   Simon Glass   fs: Move ls and r...
88
89
  		.probe = fat_set_blk_dev,
  		.close = fat_close,
436e2b731   Simon Glass   fs: Fully populat...
90
  		.ls = file_fat_ls,
b7b5f3195   Stephen Warren   fat: implement ex...
91
  		.exists = fat_exists,
cf6598193   Stephen Warren   fs: implement siz...
92
  		.size = fat_size,
e6d524153   Simon Glass   fs: Move ls and r...
93
  		.read = fat_read_file,
bd6fb31fa   Stephen Warren   fs: fix generic s...
94
  		.write = fs_write_unsupported,
045fa1e11   Stephen Warren   fs: add filesyste...
95
  	},
436e2b731   Simon Glass   fs: Fully populat...
96
97
  #endif
  #ifdef CONFIG_FS_EXT4
045fa1e11   Stephen Warren   fs: add filesyste...
98
99
  	{
  		.fstype = FS_TYPE_EXT,
377202b56   Stephen Warren   fs: don't pass NU...
100
  		.null_dev_desc_ok = false,
e6d524153   Simon Glass   fs: Move ls and r...
101
102
  		.probe = ext4fs_probe,
  		.close = ext4fs_close,
436e2b731   Simon Glass   fs: Fully populat...
103
  		.ls = ext4fs_ls,
55af5c931   Stephen Warren   ext4: implement e...
104
  		.exists = ext4fs_exists,
cf6598193   Stephen Warren   fs: implement siz...
105
  		.size = ext4fs_size,
e6d524153   Simon Glass   fs: Move ls and r...
106
  		.read = ext4_read_file,
bd6fb31fa   Stephen Warren   fs: fix generic s...
107
  		.write = fs_write_unsupported,
436e2b731   Simon Glass   fs: Fully populat...
108
109
  	},
  #endif
92ccc96bf   Simon Glass   sandbox: Add host...
110
111
112
  #ifdef CONFIG_SANDBOX
  	{
  		.fstype = FS_TYPE_SANDBOX,
377202b56   Stephen Warren   fs: don't pass NU...
113
  		.null_dev_desc_ok = true,
92ccc96bf   Simon Glass   sandbox: Add host...
114
115
116
  		.probe = sandbox_fs_set_blk_dev,
  		.close = sandbox_fs_close,
  		.ls = sandbox_fs_ls,
0a30aa1e7   Stephen Warren   sandbox: implemen...
117
  		.exists = sandbox_fs_exists,
cf6598193   Stephen Warren   fs: implement siz...
118
  		.size = sandbox_fs_size,
92ccc96bf   Simon Glass   sandbox: Add host...
119
  		.read = fs_read_sandbox,
7eb2c8d57   Simon Glass   sandbox: fs: Add ...
120
  		.write = fs_write_sandbox,
92ccc96bf   Simon Glass   sandbox: Add host...
121
122
  	},
  #endif
436e2b731   Simon Glass   fs: Fully populat...
123
124
  	{
  		.fstype = FS_TYPE_ANY,
377202b56   Stephen Warren   fs: don't pass NU...
125
  		.null_dev_desc_ok = true,
436e2b731   Simon Glass   fs: Fully populat...
126
127
128
  		.probe = fs_probe_unsupported,
  		.close = fs_close_unsupported,
  		.ls = fs_ls_unsupported,
6152916a9   Stephen Warren   fs: implement inf...
129
  		.exists = fs_exists_unsupported,
cf6598193   Stephen Warren   fs: implement siz...
130
  		.size = fs_size_unsupported,
436e2b731   Simon Glass   fs: Fully populat...
131
  		.read = fs_read_unsupported,
a8f6ab522   Simon Glass   fs: Add support f...
132
  		.write = fs_write_unsupported,
045fa1e11   Stephen Warren   fs: add filesyste...
133
134
  	},
  };
c6f548d23   Simon Glass   fs: Use filesyste...
135
136
137
138
139
140
141
142
143
144
145
146
147
  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...
148
149
  int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
  {
436e2b731   Simon Glass   fs: Fully populat...
150
  	struct fstype_info *info;
045fa1e11   Stephen Warren   fs: add filesyste...
151
  	int part, i;
a1b231cef   Stephen Warren   fs: handle CONFIG...
152
153
154
155
  #ifdef CONFIG_NEEDS_MANUAL_RELOC
  	static int relocated;
  
  	if (!relocated) {
436e2b731   Simon Glass   fs: Fully populat...
156
157
158
159
160
161
  		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...
162
  			info->write += gd->reloc_off;
436e2b731   Simon Glass   fs: Fully populat...
163
  		}
a1b231cef   Stephen Warren   fs: handle CONFIG...
164
165
166
  		relocated = 1;
  	}
  #endif
045fa1e11   Stephen Warren   fs: add filesyste...
167
168
169
170
171
  
  	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...
172
173
174
  	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...
175
  			continue;
377202b56   Stephen Warren   fs: don't pass NU...
176
177
  		if (!fs_dev_desc && !info->null_dev_desc_ok)
  			continue;
2ded0d471   Simon Glass   fs: Tell probe fu...
178
  		if (!info->probe(fs_dev_desc, &fs_partition)) {
436e2b731   Simon Glass   fs: Fully populat...
179
  			fs_type = info->fstype;
045fa1e11   Stephen Warren   fs: add filesyste...
180
181
182
  			return 0;
  		}
  	}
045fa1e11   Stephen Warren   fs: add filesyste...
183
184
185
186
187
  	return -1;
  }
  
  static void fs_close(void)
  {
c6f548d23   Simon Glass   fs: Use filesyste...
188
  	struct fstype_info *info = fs_get_info(fs_type);
045fa1e11   Stephen Warren   fs: add filesyste...
189

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

045fa1e11   Stephen Warren   fs: add filesyste...
192
193
194
195
196
197
  	fs_type = FS_TYPE_ANY;
  }
  
  int fs_ls(const char *dirname)
  {
  	int ret;
c6f548d23   Simon Glass   fs: Use filesyste...
198
199
200
  	struct fstype_info *info = fs_get_info(fs_type);
  
  	ret = info->ls(dirname);
045fa1e11   Stephen Warren   fs: add filesyste...
201

e6d524153   Simon Glass   fs: Move ls and r...
202
  	fs_type = FS_TYPE_ANY;
045fa1e11   Stephen Warren   fs: add filesyste...
203
204
205
206
  	fs_close();
  
  	return ret;
  }
6152916a9   Stephen Warren   fs: implement inf...
207
208
209
210
211
212
213
214
215
216
217
218
  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;
  }
cf6598193   Stephen Warren   fs: implement siz...
219
220
221
222
223
224
225
226
227
228
229
230
  int fs_size(const char *filename)
  {
  	int ret;
  
  	struct fstype_info *info = fs_get_info(fs_type);
  
  	ret = info->size(filename);
  
  	fs_close();
  
  	return ret;
  }
045fa1e11   Stephen Warren   fs: add filesyste...
231
232
  int fs_read(const char *filename, ulong addr, int offset, int len)
  {
c6f548d23   Simon Glass   fs: Use filesyste...
233
  	struct fstype_info *info = fs_get_info(fs_type);
117e05072   Simon Glass   fs: Use map_sysme...
234
  	void *buf;
045fa1e11   Stephen Warren   fs: add filesyste...
235
  	int ret;
117e05072   Simon Glass   fs: Use map_sysme...
236
237
238
239
240
241
242
  	/*
  	 * 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...
243

c6f548d23   Simon Glass   fs: Use filesyste...
244
245
246
247
248
249
  	/* 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...
250
251
252
253
  	fs_close();
  
  	return ret;
  }
a8f6ab522   Simon Glass   fs: Add support f...
254
255
256
257
258
  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...
259
260
261
  	buf = map_sysmem(addr, len);
  	ret = info->write(filename, buf, offset, len);
  	unmap_sysmem(buf);
bd6fb31fa   Stephen Warren   fs: fix generic s...
262
  	if (ret >= 0 && ret != len) {
a8f6ab522   Simon Glass   fs: Add support f...
263
264
265
266
267
268
269
270
  		printf("** Unable to write file %s **
  ", filename);
  		ret = -1;
  	}
  	fs_close();
  
  	return ret;
  }
cf6598193   Stephen Warren   fs: implement siz...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
  		int fstype)
  {
  	int size;
  
  	if (argc != 4)
  		return CMD_RET_USAGE;
  
  	if (fs_set_blk_dev(argv[1], argv[2], fstype))
  		return 1;
  
  	size = fs_size(argv[3]);
  	if (size < 0)
  		return CMD_RET_FAILURE;
  
  	setenv_hex("filesize", size);
  
  	return 0;
  }
f9b55e228   Stephen Warren   fs: rename fsload...
290
  int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
b770e88a6   Wolfgang Denk   Fix number base h...
291
  		int fstype)
045fa1e11   Stephen Warren   fs: add filesyste...
292
293
294
295
296
297
298
  {
  	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...
299
  	unsigned long time;
949bbd7c8   Pavel Machek   catch wrong load ...
300
  	char *ep;
045fa1e11   Stephen Warren   fs: add filesyste...
301

e9b0f99e8   Stephen Warren   fs: fix do_fsload...
302
303
304
  	if (argc < 2)
  		return CMD_RET_USAGE;
  	if (argc > 7)
045fa1e11   Stephen Warren   fs: add filesyste...
305
  		return CMD_RET_USAGE;
e9b0f99e8   Stephen Warren   fs: fix do_fsload...
306
  	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
045fa1e11   Stephen Warren   fs: add filesyste...
307
308
309
  		return 1;
  
  	if (argc >= 4) {
949bbd7c8   Pavel Machek   catch wrong load ...
310
311
312
  		addr = simple_strtoul(argv[3], &ep, 16);
  		if (ep == argv[3] || *ep != '\0')
  			return CMD_RET_USAGE;
045fa1e11   Stephen Warren   fs: add filesyste...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  	} 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...
331
  		bytes = simple_strtoul(argv[5], NULL, 16);
045fa1e11   Stephen Warren   fs: add filesyste...
332
333
334
  	else
  		bytes = 0;
  	if (argc >= 7)
b770e88a6   Wolfgang Denk   Fix number base h...
335
  		pos = simple_strtoul(argv[6], NULL, 16);
045fa1e11   Stephen Warren   fs: add filesyste...
336
337
  	else
  		pos = 0;
da1fd96ce   Andreas Bießmann   fs/fs.c: do_fsloa...
338
  	time = get_timer(0);
045fa1e11   Stephen Warren   fs: add filesyste...
339
  	len_read = fs_read(filename, addr, pos, bytes);
da1fd96ce   Andreas Bießmann   fs/fs.c: do_fsloa...
340
  	time = get_timer(time);
045fa1e11   Stephen Warren   fs: add filesyste...
341
342
  	if (len_read <= 0)
  		return 1;
da1fd96ce   Andreas Bießmann   fs/fs.c: do_fsloa...
343
344
345
346
347
348
349
350
  	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...
351

49c4f0370   Simon Glass   fs: Use new numer...
352
  	setenv_hex("filesize", len_read);
045fa1e11   Stephen Warren   fs: add filesyste...
353
354
355
356
357
358
359
360
361
  
  	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...
362
363
  	if (argc > 4)
  		return CMD_RET_USAGE;
045fa1e11   Stephen Warren   fs: add filesyste...
364
365
366
  
  	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
  		return 1;
e9b0f99e8   Stephen Warren   fs: fix do_fsload...
367
  	if (fs_ls(argc >= 4 ? argv[3] : "/"))
045fa1e11   Stephen Warren   fs: add filesyste...
368
369
370
371
  		return 1;
  
  	return 0;
  }
a8f6ab522   Simon Glass   fs: Add support f...
372

6152916a9   Stephen Warren   fs: implement inf...
373
374
375
376
377
378
379
380
  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...
381
  int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
b770e88a6   Wolfgang Denk   Fix number base h...
382
  		int fstype)
a8f6ab522   Simon Glass   fs: Add support f...
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  {
  	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...
398
399
  	addr = simple_strtoul(argv[4], NULL, 16);
  	bytes = simple_strtoul(argv[5], NULL, 16);
a8f6ab522   Simon Glass   fs: Add support f...
400
  	if (argc >= 7)
b770e88a6   Wolfgang Denk   Fix number base h...
401
  		pos = simple_strtoul(argv[6], NULL, 16);
a8f6ab522   Simon Glass   fs: Add support f...
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
  	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;
  }