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