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