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