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 char *ep; 280 281 if (argc < 2) 282 return CMD_RET_USAGE; 283 if (argc > 7) 284 return CMD_RET_USAGE; 285 286 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype)) 287 return 1; 288 289 if (argc >= 4) { 290 addr = simple_strtoul(argv[3], &ep, 16); 291 if (ep == argv[3] || *ep != '\0') 292 return CMD_RET_USAGE; 293 } else { 294 addr_str = getenv("loadaddr"); 295 if (addr_str != NULL) 296 addr = simple_strtoul(addr_str, NULL, 16); 297 else 298 addr = CONFIG_SYS_LOAD_ADDR; 299 } 300 if (argc >= 5) { 301 filename = argv[4]; 302 } else { 303 filename = getenv("bootfile"); 304 if (!filename) { 305 puts("** No boot file defined **\n"); 306 return 1; 307 } 308 } 309 if (argc >= 6) 310 bytes = simple_strtoul(argv[5], NULL, 16); 311 else 312 bytes = 0; 313 if (argc >= 7) 314 pos = simple_strtoul(argv[6], NULL, 16); 315 else 316 pos = 0; 317 318 time = get_timer(0); 319 len_read = fs_read(filename, addr, pos, bytes); 320 time = get_timer(time); 321 if (len_read <= 0) 322 return 1; 323 324 printf("%d bytes read in %lu ms", len_read, time); 325 if (time > 0) { 326 puts(" ("); 327 print_size(len_read / time * 1000, "/s"); 328 puts(")"); 329 } 330 puts("\n"); 331 332 setenv_hex("filesize", len_read); 333 334 return 0; 335 } 336 337 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 338 int fstype) 339 { 340 if (argc < 2) 341 return CMD_RET_USAGE; 342 if (argc > 4) 343 return CMD_RET_USAGE; 344 345 if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype)) 346 return 1; 347 348 if (fs_ls(argc >= 4 ? argv[3] : "/")) 349 return 1; 350 351 return 0; 352 } 353 354 int file_exists(const char *dev_type, const char *dev_part, const char *file, 355 int fstype) 356 { 357 if (fs_set_blk_dev(dev_type, dev_part, fstype)) 358 return 0; 359 360 return fs_exists(file); 361 } 362 363 int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], 364 int fstype) 365 { 366 unsigned long addr; 367 const char *filename; 368 unsigned long bytes; 369 unsigned long pos; 370 int len; 371 unsigned long time; 372 373 if (argc < 6 || argc > 7) 374 return CMD_RET_USAGE; 375 376 if (fs_set_blk_dev(argv[1], argv[2], fstype)) 377 return 1; 378 379 filename = argv[3]; 380 addr = simple_strtoul(argv[4], NULL, 16); 381 bytes = simple_strtoul(argv[5], NULL, 16); 382 if (argc >= 7) 383 pos = simple_strtoul(argv[6], NULL, 16); 384 else 385 pos = 0; 386 387 time = get_timer(0); 388 len = fs_write(filename, addr, pos, bytes); 389 time = get_timer(time); 390 if (len <= 0) 391 return 1; 392 393 printf("%d bytes written in %lu ms", len, time); 394 if (time > 0) { 395 puts(" ("); 396 print_size(len / time * 1000, "/s"); 397 puts(")"); 398 } 399 puts("\n"); 400 401 return 0; 402 } 403