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