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