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