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