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