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