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