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 <errno.h> 19 #include <common.h> 20 #include <part.h> 21 #include <ext4fs.h> 22 #include <fat.h> 23 #include <fs.h> 24 #include <sandboxfs.h> 25 #include <asm/io.h> 26 27 DECLARE_GLOBAL_DATA_PTR; 28 29 static block_dev_desc_t *fs_dev_desc; 30 static disk_partition_t fs_partition; 31 static int fs_type = FS_TYPE_ANY; 32 33 static inline int fs_probe_unsupported(block_dev_desc_t *fs_dev_desc, 34 disk_partition_t *fs_partition) 35 { 36 printf("** Unrecognized filesystem type **\n"); 37 return -1; 38 } 39 40 static inline int fs_ls_unsupported(const char *dirname) 41 { 42 return -1; 43 } 44 45 static inline int fs_exists_unsupported(const char *filename) 46 { 47 return 0; 48 } 49 50 static inline int fs_size_unsupported(const char *filename, loff_t *size) 51 { 52 return -1; 53 } 54 55 static inline int fs_read_unsupported(const char *filename, void *buf, 56 loff_t offset, loff_t len, 57 loff_t *actread) 58 { 59 return -1; 60 } 61 62 static inline int fs_write_unsupported(const char *filename, void *buf, 63 loff_t offset, loff_t len, 64 loff_t *actwrite) 65 { 66 return -1; 67 } 68 69 static inline void fs_close_unsupported(void) 70 { 71 } 72 73 static inline int fs_uuid_unsupported(char *uuid_str) 74 { 75 return -1; 76 } 77 78 struct fstype_info { 79 int fstype; 80 /* 81 * Is it legal to pass NULL as .probe()'s fs_dev_desc parameter? This 82 * should be false in most cases. For "virtual" filesystems which 83 * aren't based on a U-Boot block device (e.g. sandbox), this can be 84 * set to true. This should also be true for the dumm entry at the end 85 * of fstypes[], since that is essentially a "virtual" (non-existent) 86 * filesystem. 87 */ 88 bool null_dev_desc_ok; 89 int (*probe)(block_dev_desc_t *fs_dev_desc, 90 disk_partition_t *fs_partition); 91 int (*ls)(const char *dirname); 92 int (*exists)(const char *filename); 93 int (*size)(const char *filename, loff_t *size); 94 int (*read)(const char *filename, void *buf, loff_t offset, 95 loff_t len, loff_t *actread); 96 int (*write)(const char *filename, void *buf, loff_t offset, 97 loff_t len, loff_t *actwrite); 98 void (*close)(void); 99 int (*uuid)(char *uuid_str); 100 }; 101 102 static struct fstype_info fstypes[] = { 103 #ifdef CONFIG_FS_FAT 104 { 105 .fstype = FS_TYPE_FAT, 106 .null_dev_desc_ok = false, 107 .probe = fat_set_blk_dev, 108 .close = fat_close, 109 .ls = file_fat_ls, 110 .exists = fat_exists, 111 .size = fat_size, 112 .read = fat_read_file, 113 #ifdef CONFIG_FAT_WRITE 114 .write = file_fat_write, 115 #else 116 .write = fs_write_unsupported, 117 #endif 118 .uuid = fs_uuid_unsupported, 119 }, 120 #endif 121 #ifdef CONFIG_FS_EXT4 122 { 123 .fstype = FS_TYPE_EXT, 124 .null_dev_desc_ok = false, 125 .probe = ext4fs_probe, 126 .close = ext4fs_close, 127 .ls = ext4fs_ls, 128 .exists = ext4fs_exists, 129 .size = ext4fs_size, 130 .read = ext4_read_file, 131 #ifdef CONFIG_CMD_EXT4_WRITE 132 .write = ext4_write_file, 133 #else 134 .write = fs_write_unsupported, 135 #endif 136 .uuid = ext4fs_uuid, 137 }, 138 #endif 139 #ifdef CONFIG_SANDBOX 140 { 141 .fstype = FS_TYPE_SANDBOX, 142 .null_dev_desc_ok = true, 143 .probe = sandbox_fs_set_blk_dev, 144 .close = sandbox_fs_close, 145 .ls = sandbox_fs_ls, 146 .exists = sandbox_fs_exists, 147 .size = sandbox_fs_size, 148 .read = fs_read_sandbox, 149 .write = fs_write_sandbox, 150 .uuid = fs_uuid_unsupported, 151 }, 152 #endif 153 { 154 .fstype = FS_TYPE_ANY, 155 .null_dev_desc_ok = true, 156 .probe = fs_probe_unsupported, 157 .close = fs_close_unsupported, 158 .ls = fs_ls_unsupported, 159 .exists = fs_exists_unsupported, 160 .size = fs_size_unsupported, 161 .read = fs_read_unsupported, 162 .write = fs_write_unsupported, 163 .uuid = fs_uuid_unsupported, 164 }, 165 }; 166 167 static struct fstype_info *fs_get_info(int fstype) 168 { 169 struct fstype_info *info; 170 int i; 171 172 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes) - 1; i++, info++) { 173 if (fstype == info->fstype) 174 return info; 175 } 176 177 /* Return the 'unsupported' sentinel */ 178 return info; 179 } 180 181 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype) 182 { 183 struct fstype_info *info; 184 int part, i; 185 #ifdef CONFIG_NEEDS_MANUAL_RELOC 186 static int relocated; 187 188 if (!relocated) { 189 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); 190 i++, info++) { 191 info->probe += gd->reloc_off; 192 info->close += gd->reloc_off; 193 info->ls += gd->reloc_off; 194 info->read += gd->reloc_off; 195 info->write += gd->reloc_off; 196 } 197 relocated = 1; 198 } 199 #endif 200 201 part = get_device_and_partition(ifname, dev_part_str, &fs_dev_desc, 202 &fs_partition, 1); 203 if (part < 0) 204 return -1; 205 206 for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) { 207 if (fstype != FS_TYPE_ANY && info->fstype != FS_TYPE_ANY && 208 fstype != info->fstype) 209 continue; 210 211 if (!fs_dev_desc && !info->null_dev_desc_ok) 212 continue; 213 214 if (!info->probe(fs_dev_desc, &fs_partition)) { 215 fs_type = info->fstype; 216 return 0; 217 } 218 } 219 220 return -1; 221 } 222 223 static void fs_close(void) 224 { 225 struct fstype_info *info = fs_get_info(fs_type); 226 227 info->close(); 228 229 fs_type = FS_TYPE_ANY; 230 } 231 232 int fs_uuid(char *uuid_str) 233 { 234 struct fstype_info *info = fs_get_info(fs_type); 235 236 return info->uuid(uuid_str); 237 } 238 239 int fs_ls(const char *dirname) 240 { 241 int ret; 242 243 struct fstype_info *info = fs_get_info(fs_type); 244 245 ret = info->ls(dirname); 246 247 fs_type = FS_TYPE_ANY; 248 fs_close(); 249 250 return ret; 251 } 252 253 int fs_exists(const char *filename) 254 { 255 int ret; 256 257 struct fstype_info *info = fs_get_info(fs_type); 258 259 ret = info->exists(filename); 260 261 fs_close(); 262 263 return ret; 264 } 265 266 int fs_size(const char *filename, loff_t *size) 267 { 268 int ret; 269 270 struct fstype_info *info = fs_get_info(fs_type); 271 272 ret = info->size(filename, size); 273 274 fs_close(); 275 276 return ret; 277 } 278 279 int fs_read(const char *filename, ulong addr, loff_t offset, loff_t len, 280 loff_t *actread) 281 { 282 struct fstype_info *info = fs_get_info(fs_type); 283 void *buf; 284 int ret; 285 286 /* 287 * We don't actually know how many bytes are being read, since len==0 288 * means read the whole file. 289 */ 290 buf = map_sysmem(addr, len); 291 ret = info->read(filename, buf, offset, len, actread); 292 unmap_sysmem(buf); 293 294 /* If we requested a specific number of bytes, check we got it */ 295 if (ret == 0 && len && *actread != len) { 296 printf("** Unable to read file %s **\n", filename); 297 ret = -1; 298 } 299 fs_close(); 300 301 return ret; 302 } 303 304 int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len, 305 loff_t *actwrite) 306 { 307 struct fstype_info *info = fs_get_info(fs_type); 308 void *buf; 309 int ret; 310 311 buf = map_sysmem(addr, len); 312 ret = info->write(filename, buf, offset, len, actwrite); 313 unmap_sysmem(buf); 314 315 if (ret < 0 && len != *actwrite) { 316 printf("** Unable to write file %s **\n", filename); 317 ret = -1; 318 } 319 fs_close(); 320 321 return ret; 322 } 323 324 int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 325 int fstype) 326 { 327 loff_t size; 328 329 if (argc != 4) 330 return CMD_RET_USAGE; 331 332 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 333 return 1; 334 335 if (fs_size(argv[3], &size) < 0) 336 return CMD_RET_FAILURE; 337 338 setenv_hex("filesize", size); 339 340 return 0; 341 } 342 343 int do_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 344 int fstype) 345 { 346 unsigned long addr; 347 const char *addr_str; 348 const char *filename; 349 loff_t bytes; 350 loff_t pos; 351 loff_t len_read; 352 int ret; 353 unsigned long time; 354 char *ep; 355 356 if (argc < 2) 357 return CMD_RET_USAGE; 358 if (argc > 7) 359 return CMD_RET_USAGE; 360 361 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype)) 362 return 1; 363 364 if (argc >= 4) { 365 addr = simple_strtoul(argv[3], &ep, 16); 366 if (ep == argv[3] || *ep != '\0') 367 return CMD_RET_USAGE; 368 } else { 369 addr_str = getenv("loadaddr"); 370 if (addr_str != NULL) 371 addr = simple_strtoul(addr_str, NULL, 16); 372 else 373 addr = CONFIG_SYS_LOAD_ADDR; 374 } 375 if (argc >= 5) { 376 filename = argv[4]; 377 } else { 378 filename = getenv("bootfile"); 379 if (!filename) { 380 puts("** No boot file defined **\n"); 381 return 1; 382 } 383 } 384 if (argc >= 6) 385 bytes = simple_strtoul(argv[5], NULL, 16); 386 else 387 bytes = 0; 388 if (argc >= 7) 389 pos = simple_strtoul(argv[6], NULL, 16); 390 else 391 pos = 0; 392 393 time = get_timer(0); 394 ret = fs_read(filename, addr, pos, bytes, &len_read); 395 time = get_timer(time); 396 if (ret < 0) 397 return 1; 398 399 printf("%llu bytes read in %lu ms", len_read, time); 400 if (time > 0) { 401 puts(" ("); 402 print_size(len_read / time * 1000, "/s"); 403 puts(")"); 404 } 405 puts("\n"); 406 407 setenv_hex("filesize", len_read); 408 409 return 0; 410 } 411 412 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 413 int fstype) 414 { 415 if (argc < 2) 416 return CMD_RET_USAGE; 417 if (argc > 4) 418 return CMD_RET_USAGE; 419 420 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype)) 421 return 1; 422 423 if (fs_ls(argc >= 4 ? argv[3] : "/")) 424 return 1; 425 426 return 0; 427 } 428 429 int file_exists(const char *dev_type, const char *dev_part, const char *file, 430 int fstype) 431 { 432 if (fs_set_blk_dev(dev_type, dev_part, fstype)) 433 return 0; 434 435 return fs_exists(file); 436 } 437 438 int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 439 int fstype) 440 { 441 unsigned long addr; 442 const char *filename; 443 loff_t bytes; 444 loff_t pos; 445 loff_t len; 446 int ret; 447 unsigned long time; 448 449 if (argc < 6 || argc > 7) 450 return CMD_RET_USAGE; 451 452 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 453 return 1; 454 455 addr = simple_strtoul(argv[3], NULL, 16); 456 filename = argv[4]; 457 bytes = simple_strtoul(argv[5], NULL, 16); 458 if (argc >= 7) 459 pos = simple_strtoul(argv[6], NULL, 16); 460 else 461 pos = 0; 462 463 time = get_timer(0); 464 ret = fs_write(filename, addr, pos, bytes, &len); 465 time = get_timer(time); 466 if (ret < 0) 467 return 1; 468 469 printf("%llu bytes written in %lu ms", len, time); 470 if (time > 0) { 471 puts(" ("); 472 print_size(len / time * 1000, "/s"); 473 puts(")"); 474 } 475 puts("\n"); 476 477 return 0; 478 } 479 480 int do_fs_uuid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 481 int fstype) 482 { 483 int ret; 484 char uuid[37]; 485 memset(uuid, 0, sizeof(uuid)); 486 487 if (argc < 3 || argc > 4) 488 return CMD_RET_USAGE; 489 490 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 491 return 1; 492 493 ret = fs_uuid(uuid); 494 if (ret) 495 return CMD_RET_FAILURE; 496 497 if (argc == 4) 498 setenv(argv[3], uuid); 499 else 500 printf("%s\n", uuid); 501 502 return CMD_RET_SUCCESS; 503 } 504