xref: /rk3399_rockchip-uboot/fs/fs.c (revision b3800056b1e398ab3bede7e927285eeddca7e088)
1 /*
2  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * SPDX-License-Identifier:	GPL-2.0
5  */
6 
7 #include <config.h>
8 #include <errno.h>
9 #include <common.h>
10 #include <mapmem.h>
11 #include <part.h>
12 #include <ext4fs.h>
13 #include <fat.h>
14 #include <fs.h>
15 #include <sandboxfs.h>
16 #include <ubifs_uboot.h>
17 #include <asm/io.h>
18 #include <div64.h>
19 #include <linux/math64.h>
20 
21 DECLARE_GLOBAL_DATA_PTR;
22 
23 static struct blk_desc *fs_dev_desc;
24 static int fs_dev_part;
25 static disk_partition_t fs_partition;
26 static int fs_type = FS_TYPE_ANY;
27 
28 static inline int fs_probe_unsupported(struct blk_desc *fs_dev_desc,
29 				      disk_partition_t *fs_partition)
30 {
31 	printf("** Unrecognized filesystem type **\n");
32 	return -1;
33 }
34 
35 static inline int fs_ls_unsupported(const char *dirname)
36 {
37 	return -1;
38 }
39 
40 static inline int fs_exists_unsupported(const char *filename)
41 {
42 	return 0;
43 }
44 
45 static inline int fs_size_unsupported(const char *filename, loff_t *size)
46 {
47 	return -1;
48 }
49 
50 static inline int fs_read_unsupported(const char *filename, void *buf,
51 				      loff_t offset, loff_t len,
52 				      loff_t *actread)
53 {
54 	return -1;
55 }
56 
57 static inline int fs_write_unsupported(const char *filename, void *buf,
58 				      loff_t offset, loff_t len,
59 				      loff_t *actwrite)
60 {
61 	return -1;
62 }
63 
64 static inline void fs_close_unsupported(void)
65 {
66 }
67 
68 static inline int fs_uuid_unsupported(char *uuid_str)
69 {
70 	return -1;
71 }
72 
73 static inline int fs_opendir_unsupported(const char *filename,
74 					 struct fs_dir_stream **dirs)
75 {
76 	return -EACCES;
77 }
78 
79 struct fstype_info {
80 	int fstype;
81 	char *name;
82 	/*
83 	 * Is it legal to pass NULL as .probe()'s  fs_dev_desc parameter? This
84 	 * should be false in most cases. For "virtual" filesystems which
85 	 * aren't based on a U-Boot block device (e.g. sandbox), this can be
86 	 * set to true. This should also be true for the dumm entry at the end
87 	 * of fstypes[], since that is essentially a "virtual" (non-existent)
88 	 * filesystem.
89 	 */
90 	bool null_dev_desc_ok;
91 	int (*probe)(struct blk_desc *fs_dev_desc,
92 		     disk_partition_t *fs_partition);
93 	int (*ls)(const char *dirname);
94 	int (*exists)(const char *filename);
95 	int (*size)(const char *filename, loff_t *size);
96 	int (*read)(const char *filename, void *buf, loff_t offset,
97 		    loff_t len, loff_t *actread);
98 	int (*write)(const char *filename, void *buf, loff_t offset,
99 		     loff_t len, loff_t *actwrite);
100 	void (*close)(void);
101 	int (*uuid)(char *uuid_str);
102 	/*
103 	 * Open a directory stream.  On success return 0 and directory
104 	 * stream pointer via 'dirsp'.  On error, return -errno.  See
105 	 * fs_opendir().
106 	 */
107 	int (*opendir)(const char *filename, struct fs_dir_stream **dirsp);
108 	/*
109 	 * Read next entry from directory stream.  On success return 0
110 	 * and directory entry pointer via 'dentp'.  On error return
111 	 * -errno.  See fs_readdir().
112 	 */
113 	int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
114 	/* see fs_closedir() */
115 	void (*closedir)(struct fs_dir_stream *dirs);
116 };
117 
118 static struct fstype_info fstypes[] = {
119 #ifdef CONFIG_FS_FAT
120 	{
121 		.fstype = FS_TYPE_FAT,
122 		.name = "fat",
123 		.null_dev_desc_ok = false,
124 		.probe = fat_set_blk_dev,
125 		.close = fat_close,
126 		.ls = file_fat_ls,
127 		.exists = fat_exists,
128 		.size = fat_size,
129 		.read = fat_read_file,
130 #ifdef CONFIG_FAT_WRITE
131 		.write = file_fat_write,
132 #else
133 		.write = fs_write_unsupported,
134 #endif
135 		.uuid = fs_uuid_unsupported,
136 		.opendir = fs_opendir_unsupported,
137 	},
138 #endif
139 #ifdef CONFIG_FS_EXT4
140 	{
141 		.fstype = FS_TYPE_EXT,
142 		.name = "ext4",
143 		.null_dev_desc_ok = false,
144 		.probe = ext4fs_probe,
145 		.close = ext4fs_close,
146 		.ls = ext4fs_ls,
147 		.exists = ext4fs_exists,
148 		.size = ext4fs_size,
149 		.read = ext4_read_file,
150 #ifdef CONFIG_CMD_EXT4_WRITE
151 		.write = ext4_write_file,
152 #else
153 		.write = fs_write_unsupported,
154 #endif
155 		.uuid = ext4fs_uuid,
156 		.opendir = fs_opendir_unsupported,
157 	},
158 #endif
159 #ifdef CONFIG_SANDBOX
160 	{
161 		.fstype = FS_TYPE_SANDBOX,
162 		.name = "sandbox",
163 		.null_dev_desc_ok = true,
164 		.probe = sandbox_fs_set_blk_dev,
165 		.close = sandbox_fs_close,
166 		.ls = sandbox_fs_ls,
167 		.exists = sandbox_fs_exists,
168 		.size = sandbox_fs_size,
169 		.read = fs_read_sandbox,
170 		.write = fs_write_sandbox,
171 		.uuid = fs_uuid_unsupported,
172 		.opendir = fs_opendir_unsupported,
173 	},
174 #endif
175 #ifdef CONFIG_CMD_UBIFS
176 	{
177 		.fstype = FS_TYPE_UBIFS,
178 		.name = "ubifs",
179 		.null_dev_desc_ok = true,
180 		.probe = ubifs_set_blk_dev,
181 		.close = ubifs_close,
182 		.ls = ubifs_ls,
183 		.exists = ubifs_exists,
184 		.size = ubifs_size,
185 		.read = ubifs_read,
186 		.write = fs_write_unsupported,
187 		.uuid = fs_uuid_unsupported,
188 		.opendir = fs_opendir_unsupported,
189 	},
190 #endif
191 	{
192 		.fstype = FS_TYPE_ANY,
193 		.name = "unsupported",
194 		.null_dev_desc_ok = true,
195 		.probe = fs_probe_unsupported,
196 		.close = fs_close_unsupported,
197 		.ls = fs_ls_unsupported,
198 		.exists = fs_exists_unsupported,
199 		.size = fs_size_unsupported,
200 		.read = fs_read_unsupported,
201 		.write = fs_write_unsupported,
202 		.uuid = fs_uuid_unsupported,
203 		.opendir = fs_opendir_unsupported,
204 	},
205 };
206 
207 static struct fstype_info *fs_get_info(int fstype)
208 {
209 	struct fstype_info *info;
210 	int i;
211 
212 	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) {
213 		if (fstype == info->fstype)
214 			return info;
215 	}
216 
217 	/* Return the 'unsupported' sentinel */
218 	return info;
219 }
220 
221 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
222 {
223 	struct fstype_info *info;
224 	int part, i;
225 #ifdef CONFIG_NEEDS_MANUAL_RELOC
226 	static int relocated;
227 
228 	if (!relocated) {
229 		for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes);
230 				i++, info++) {
231 			info->name += gd->reloc_off;
232 			info->probe += gd->reloc_off;
233 			info->close += gd->reloc_off;
234 			info->ls += gd->reloc_off;
235 			info->read += gd->reloc_off;
236 			info->write += gd->reloc_off;
237 		}
238 		relocated = 1;
239 	}
240 #endif
241 
242 	part = blk_get_device_part_str(ifname, dev_part_str, &fs_dev_desc,
243 					&fs_partition, 1);
244 	if (part < 0)
245 		return -1;
246 
247 	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
248 		if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY &&
249 				fstype != info->fstype)
250 			continue;
251 
252 		if (!fs_dev_desc && !info->null_dev_desc_ok)
253 			continue;
254 
255 		if (!info->probe(fs_dev_desc, &fs_partition)) {
256 			fs_type = info->fstype;
257 			fs_dev_part = part;
258 			return 0;
259 		}
260 	}
261 
262 	return -1;
263 }
264 
265 /* set current blk device w/ blk_desc + partition # */
266 int fs_set_blk_dev_with_part(struct blk_desc *desc, int part)
267 {
268 	struct fstype_info *info;
269 	int ret, i;
270 
271 	if (part >= 1)
272 		ret = part_get_info(desc, part, &fs_partition);
273 	else
274 		ret = part_get_info_whole_disk(desc, &fs_partition);
275 	if (ret)
276 		return ret;
277 	fs_dev_desc = desc;
278 
279 	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
280 		if (!info->probe(fs_dev_desc, &fs_partition)) {
281 			fs_type = info->fstype;
282 			return 0;
283 		}
284 	}
285 
286 	return -1;
287 }
288 
289 static void fs_close(void)
290 {
291 	struct fstype_info *info = fs_get_info(fs_type);
292 
293 	info->close();
294 
295 	fs_type = FS_TYPE_ANY;
296 }
297 
298 int fs_uuid(char *uuid_str)
299 {
300 	struct fstype_info *info = fs_get_info(fs_type);
301 
302 	return info->uuid(uuid_str);
303 }
304 
305 int fs_ls(const char *dirname)
306 {
307 	int ret;
308 
309 	struct fstype_info *info = fs_get_info(fs_type);
310 
311 	ret = info->ls(dirname);
312 
313 	fs_type = FS_TYPE_ANY;
314 	fs_close();
315 
316 	return ret;
317 }
318 
319 int fs_exists(const char *filename)
320 {
321 	int ret;
322 
323 	struct fstype_info *info = fs_get_info(fs_type);
324 
325 	ret = info->exists(filename);
326 
327 	fs_close();
328 
329 	return ret;
330 }
331 
332 int fs_size(const char *filename, loff_t *size)
333 {
334 	int ret;
335 
336 	struct fstype_info *info = fs_get_info(fs_type);
337 
338 	ret = info->size(filename, size);
339 
340 	fs_close();
341 
342 	return ret;
343 }
344 
345 int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len,
346 	    loff_t *actread)
347 {
348 	struct fstype_info *info = fs_get_info(fs_type);
349 	void *buf;
350 	int ret;
351 
352 	/*
353 	 * We don't actually know how many bytes are being read, since len==0
354 	 * means read the whole file.
355 	 */
356 	buf = map_sysmem(addr, len);
357 	ret = info->read(filename, buf, offset, len, actread);
358 	unmap_sysmem(buf);
359 
360 	/* If we requested a specific number of bytes, check we got it */
361 	if (ret == 0 && len && *actread != len)
362 		printf("** %s shorter than offset + len **\n", filename);
363 	fs_close();
364 
365 	return ret;
366 }
367 
368 int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
369 	     loff_t *actwrite)
370 {
371 	struct fstype_info *info = fs_get_info(fs_type);
372 	void *buf;
373 	int ret;
374 
375 	buf = map_sysmem(addr, len);
376 	ret = info->write(filename, buf, offset, len, actwrite);
377 	unmap_sysmem(buf);
378 
379 	if (ret < 0 && len != *actwrite) {
380 		printf("** Unable to write file %s **\n", filename);
381 		ret = -1;
382 	}
383 	fs_close();
384 
385 	return ret;
386 }
387 
388 struct fs_dir_stream *fs_opendir(const char *filename)
389 {
390 	struct fstype_info *info = fs_get_info(fs_type);
391 	struct fs_dir_stream *dirs = NULL;
392 	int ret;
393 
394 	ret = info->opendir(filename, &dirs);
395 	fs_close();
396 	if (ret) {
397 		errno = -ret;
398 		return NULL;
399 	}
400 
401 	dirs->desc = fs_dev_desc;
402 	dirs->part = fs_dev_part;
403 
404 	return dirs;
405 }
406 
407 struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs)
408 {
409 	struct fstype_info *info;
410 	struct fs_dirent *dirent;
411 	int ret;
412 
413 	fs_set_blk_dev_with_part(dirs->desc, dirs->part);
414 	info = fs_get_info(fs_type);
415 
416 	ret = info->readdir(dirs, &dirent);
417 	fs_close();
418 	if (ret) {
419 		errno = -ret;
420 		return NULL;
421 	}
422 
423 	return dirent;
424 }
425 
426 void fs_closedir(struct fs_dir_stream *dirs)
427 {
428 	struct fstype_info *info;
429 
430 	if (!dirs)
431 		return;
432 
433 	fs_set_blk_dev_with_part(dirs->desc, dirs->part);
434 	info = fs_get_info(fs_type);
435 
436 	info->closedir(dirs);
437 	fs_close();
438 }
439 
440 
441 int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
442 		int fstype)
443 {
444 	loff_t size;
445 
446 	if (argc != 4)
447 		return CMD_RET_USAGE;
448 
449 	if (fs_set_blk_dev(argv[1], argv[2], fstype))
450 		return 1;
451 
452 	if (fs_size(argv[3], &size) < 0)
453 		return CMD_RET_FAILURE;
454 
455 	env_set_hex("filesize", size);
456 
457 	return 0;
458 }
459 
460 int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
461 		int fstype)
462 {
463 	unsigned long addr;
464 	const char *addr_str;
465 	const char *filename;
466 	loff_t bytes;
467 	loff_t pos;
468 	loff_t len_read;
469 	int ret;
470 	unsigned long time;
471 	char *ep;
472 
473 	if (argc < 2)
474 		return CMD_RET_USAGE;
475 	if (argc > 7)
476 		return CMD_RET_USAGE;
477 
478 	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
479 		return 1;
480 
481 	if (argc >= 4) {
482 		addr = simple_strtoul(argv[3], &ep, 16);
483 		if (ep == argv[3] || *ep != '\0')
484 			return CMD_RET_USAGE;
485 	} else {
486 		addr_str = env_get("loadaddr");
487 		if (addr_str != NULL)
488 			addr = simple_strtoul(addr_str, NULL, 16);
489 		else
490 			addr = CONFIG_SYS_LOAD_ADDR;
491 	}
492 	if (argc >= 5) {
493 		filename = argv[4];
494 	} else {
495 		filename = env_get("bootfile");
496 		if (!filename) {
497 			puts("** No boot file defined **\n");
498 			return 1;
499 		}
500 	}
501 	if (argc >= 6)
502 		bytes = simple_strtoul(argv[5], NULL, 16);
503 	else
504 		bytes = 0;
505 	if (argc >= 7)
506 		pos = simple_strtoul(argv[6], NULL, 16);
507 	else
508 		pos = 0;
509 
510 	time = get_timer(0);
511 	ret = fs_read(filename, addr, pos, bytes, &len_read);
512 	time = get_timer(time);
513 	if (ret < 0)
514 		return 1;
515 
516 	printf("%llu bytes read in %lu ms", len_read, time);
517 	if (time > 0) {
518 		puts(" (");
519 		print_size(div_u64(len_read, time) * 1000, "/s");
520 		puts(")");
521 	}
522 	puts("\n");
523 
524 	env_set_hex("fileaddr", addr);
525 	env_set_hex("filesize", len_read);
526 
527 	return 0;
528 }
529 
530 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
531 	int fstype)
532 {
533 	if (argc < 2)
534 		return CMD_RET_USAGE;
535 	if (argc > 4)
536 		return CMD_RET_USAGE;
537 
538 	if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
539 		return 1;
540 
541 	if (fs_ls(argc >= 4 ? argv[3] : "/"))
542 		return 1;
543 
544 	return 0;
545 }
546 
547 int file_exists(const char *dev_type, const char *dev_part, const char *file,
548 		int fstype)
549 {
550 	if (fs_set_blk_dev(dev_type, dev_part, fstype))
551 		return 0;
552 
553 	return fs_exists(file);
554 }
555 
556 int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
557 		int fstype)
558 {
559 	unsigned long addr;
560 	const char *filename;
561 	loff_t bytes;
562 	loff_t pos;
563 	loff_t len;
564 	int ret;
565 	unsigned long time;
566 
567 	if (argc < 6 || argc > 7)
568 		return CMD_RET_USAGE;
569 
570 	if (fs_set_blk_dev(argv[1], argv[2], fstype))
571 		return 1;
572 
573 	addr = simple_strtoul(argv[3], NULL, 16);
574 	filename = argv[4];
575 	bytes = simple_strtoul(argv[5], NULL, 16);
576 	if (argc >= 7)
577 		pos = simple_strtoul(argv[6], NULL, 16);
578 	else
579 		pos = 0;
580 
581 	time = get_timer(0);
582 	ret = fs_write(filename, addr, pos, bytes, &len);
583 	time = get_timer(time);
584 	if (ret < 0)
585 		return 1;
586 
587 	printf("%llu bytes written in %lu ms", len, time);
588 	if (time > 0) {
589 		puts(" (");
590 		print_size(div_u64(len, time) * 1000, "/s");
591 		puts(")");
592 	}
593 	puts("\n");
594 
595 	return 0;
596 }
597 
598 int do_fs_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
599 		int fstype)
600 {
601 	int ret;
602 	char uuid[37];
603 	memset(uuid, 0, sizeof(uuid));
604 
605 	if (argc < 3 || argc > 4)
606 		return CMD_RET_USAGE;
607 
608 	if (fs_set_blk_dev(argv[1], argv[2], fstype))
609 		return 1;
610 
611 	ret = fs_uuid(uuid);
612 	if (ret)
613 		return CMD_RET_FAILURE;
614 
615 	if (argc == 4)
616 		env_set(argv[3], uuid);
617 	else
618 		printf("%s\n", uuid);
619 
620 	return CMD_RET_SUCCESS;
621 }
622 
623 int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
624 {
625 	struct fstype_info *info;
626 
627 	if (argc < 3 || argc > 4)
628 		return CMD_RET_USAGE;
629 
630 	if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
631 		return 1;
632 
633 	info = fs_get_info(fs_type);
634 
635 	if (argc == 4)
636 		env_set(argv[3], info->name);
637 	else
638 		printf("%s\n", info->name);
639 
640 	return CMD_RET_SUCCESS;
641 }
642 
643