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