u-boot 2011.12: switch beagleboard to ext4 to match beaglebone
[glsdk/meta-ti-glsdk.git] / recipes-bsp / u-boot / u-boot / 2011.12 / 0012-ext4fs-ls-load-support.patch
1 From 04a6b1d60a4fec316992b11837d6347117cbb670 Mon Sep 17 00:00:00 2001
2 From: "uma.shankar" <uma.shankar@samsung.com>
3 Date: Mon, 9 Jan 2012 07:54:50 +0000
4 Subject: [PATCH 12/13] ext4fs ls load support
6 Signed-off-by: Uma Shankar <uma.shankar@samsung.com>
7 Signed-off-by: Manjunatha C Achar <a.manjunatha@samsung.com>
8 Signed-off-by: Iqbal Shareef <iqbal.ams@samsung.com>
9 Signed-off-by: Hakgoo Lee <goodguy.lee@samsung.com>
10 ---
11  Makefile              |    2 +-
12  common/Makefile       |    1 +
13  common/cmd_ext4.c     |  266 +++++++++++++++
14  fs/Makefile           |    1 +
15  fs/ext2/dev.c         |    1 +
16  fs/ext2/ext2fs.c      |  181 ++--------
17  fs/ext4/Makefile      |   51 +++
18  fs/ext4/dev.c         |  145 ++++++++
19  fs/ext4/ext4_common.c |  875 +++++++++++++++++++++++++++++++++++++++++++++++++
20  fs/ext4/ext4_common.h |   63 ++++
21  fs/ext4/ext4fs.c      |  228 +++++++++++++
22  include/ext4fs.h      |  132 ++++++++
23  include/ext_common.h  |  188 +++++++++++
24  13 files changed, 1977 insertions(+), 157 deletions(-)
25  create mode 100644 common/cmd_ext4.c
26  create mode 100644 fs/ext4/Makefile
27  create mode 100644 fs/ext4/dev.c
28  create mode 100644 fs/ext4/ext4_common.c
29  create mode 100644 fs/ext4/ext4_common.h
30  create mode 100644 fs/ext4/ext4fs.c
31  create mode 100644 include/ext4fs.h
32  create mode 100644 include/ext_common.h
34 diff --git a/Makefile b/Makefile
35 index 0438f1e..51cc8c8 100644
36 --- a/Makefile
37 +++ b/Makefile
38 @@ -235,7 +235,7 @@ LIBS += dts/libdts.o
39  endif
40  LIBS += arch/$(ARCH)/lib/lib$(ARCH).o
41  LIBS += fs/cramfs/libcramfs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o \
42 -       fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/yaffs2/libyaffs2.o \
43 +       fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/ext4/libext4fs.o fs/yaffs2/libyaffs2.o \
44         fs/ubifs/libubifs.o
45  LIBS += net/libnet.o
46  LIBS += disk/libdisk.o
47 diff --git a/common/Makefile b/common/Makefile
48 index 2d9ae8c..f5243f6 100644
49 --- a/common/Makefile
50 +++ b/common/Makefile
51 @@ -86,6 +86,7 @@ COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += cmd_eeprom.o
52  COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o
53  COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o
54  COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o
55 +COBJS-$(CONFIG_CMD_EXT4) += cmd_ext4.o
56  COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o
57  COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o
58  COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o
59 diff --git a/common/cmd_ext4.c b/common/cmd_ext4.c
60 new file mode 100644
61 index 0000000..2c53d2c
62 --- /dev/null
63 +++ b/common/cmd_ext4.c
64 @@ -0,0 +1,266 @@
65 +/*
66 + * (C) Copyright 2011 - 2012 Samsung Electronics
67 + * EXT4 filesystem implementation in Uboot by
68 + * Uma Shankar <uma.shankar@samsung.com>
69 + * Manjunatha C Achar <a.manjunatha@samsung.com>
70 + *
71 + * Ext4fs support
72 + * made from existing cmd_ext2.c file of Uboot
73 + *
74 + * (C) Copyright 2004
75 + * esd gmbh <www.esd-electronics.com>
76 + * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
77 + *
78 + * made from cmd_reiserfs by
79 + *
80 + * (C) Copyright 2003 - 2004
81 + * Sysgo Real-Time Solutions, AG <www.elinos.com>
82 + * Pavel Bartusek <pba@sysgo.com>
83 + *
84 + * This program is free software; you can redistribute it and/or
85 + * modify it under the terms of the GNU General Public License as
86 + * published by the Free Software Foundation; either version 2 of
87 + * the License, or (at your option) any later version.
88 + *
89 + * This program is distributed in the hope that it will be useful,
90 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
91 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
92 + * GNU General Public License for more details.
93 + *
94 + * You should have received a copy of the GNU General Public License
95 + * along with this program; if not, write to the Free Software
96 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
97 + * MA 02111-1307 USA
98 + *
99 + */
101 +/*
102 + * Changelog:
103 + *     0.1 - Newly created file for ext4fs support. Taken from cmd_ext2.c
104 + *             file in uboot. Added ext4fs ls and load support.
105 + */
107 +#include <common.h>
108 +#include <part.h>
109 +#include <config.h>
110 +#include <command.h>
111 +#include <image.h>
112 +#include <linux/ctype.h>
113 +#include <asm/byteorder.h>
114 +#include <ext_common.h>
115 +#include <ext4fs.h>
116 +#include <linux/stat.h>
117 +#include <malloc.h>
119 +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
120 +#include <usb.h>
121 +#endif
123 +#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION)
124 +#error DOS or EFI partition support must be selected
125 +#endif
127 +uint64_t total_sector;
128 +uint64_t part_offset;
130 +#define DOS_PART_MAGIC_OFFSET  0x1fe
131 +#define DOS_FS_TYPE_OFFSET     0x36
132 +#define DOS_FS32_TYPE_OFFSET   0x52
134 +static int do_ext4_load(cmd_tbl_t *cmdtp, int flag, int argc,
135 +                                               char *const argv[])
136 +{
137 +       char *filename = NULL;
138 +       char *ep;
139 +       int dev;
140 +       unsigned long part = 1;
141 +       ulong addr = 0;
142 +       ulong part_length;
143 +       int filelen;
144 +       disk_partition_t info;
145 +       struct ext_filesystem *fs;
146 +       char buf[12];
147 +       unsigned long count;
148 +       const char *addr_str;
150 +       count = 0;
151 +       addr = simple_strtoul(argv[3], NULL, 16);
152 +       filename = getenv("bootfile");
153 +       switch (argc) {
154 +       case 3:
155 +               addr_str = getenv("loadaddr");
156 +               if (addr_str != NULL)
157 +                       addr = simple_strtoul(addr_str, NULL, 16);
158 +               else
159 +                       addr = CONFIG_SYS_LOAD_ADDR;
161 +               break;
162 +       case 4:
163 +               break;
164 +       case 5:
165 +               filename = argv[4];
166 +               break;
167 +       case 6:
168 +               filename = argv[4];
169 +               count = simple_strtoul(argv[5], NULL, 16);
170 +               break;
172 +       default:
173 +               return cmd_usage(cmdtp);
174 +       }
176 +       if (!filename) {
177 +               puts("** No boot file defined **\n");
178 +               return 1;
179 +       }
181 +       dev = (int)simple_strtoul(argv[2], &ep, 16);
182 +       ext4_dev_desc = get_dev(argv[1], dev);
183 +       if (ext4_dev_desc == NULL) {
184 +               printf("** Block device %s %d not supported\n", argv[1], dev);
185 +               return 1;
186 +       }
187 +       if (init_fs(ext4_dev_desc))
188 +               return 1;
190 +       fs = get_fs();
191 +       if (*ep) {
192 +               if (*ep != ':') {
193 +                       puts("** Invalid boot device, use `dev[:part]' **\n");
194 +                       return 1;
195 +               }
196 +               part = simple_strtoul(++ep, NULL, 16);
197 +       }
199 +       if (part != 0) {
200 +               if (get_partition_info(fs->dev_desc, part, &info)) {
201 +                       printf("** Bad partition %lu **\n", part);
202 +                       return 1;
203 +               }
205 +               if (strncmp((char *)info.type, BOOT_PART_TYPE,
206 +                           strlen(BOOT_PART_TYPE)) != 0) {
207 +                       printf("** Invalid partition type \"%s\""
208 +                              " (expect \"" BOOT_PART_TYPE "\")\n", info.type);
209 +                       return 1;
210 +               }
211 +               printf("Loading file \"%s\" "
212 +                      "from %s device %d:%lu %s\n",
213 +                      filename, argv[1], dev, part, info.name);
214 +       } else {
215 +               printf("Loading file \"%s\" from %s device %d\n",
216 +                      filename, argv[1], dev);
217 +       }
219 +       part_length = ext4fs_set_blk_dev(fs->dev_desc, part);
220 +       if (part_length == 0) {
221 +               printf("**Bad partition - %s %d:%lu **\n", argv[1], dev, part);
222 +               ext4fs_close();
223 +               return 1;
224 +       }
226 +       if (!ext4fs_mount(part_length)) {
227 +               printf("** Bad ext2 partition or disk - %s %d:%lu **\n",
228 +                      argv[1], dev, part);
229 +               ext4fs_close();
230 +               return 1;
231 +       }
233 +       filelen = ext4fs_open(filename);
234 +       if (filelen < 0) {
235 +               printf("** File not found %s\n", filename);
236 +               ext4fs_close();
237 +               return 1;
238 +       }
239 +       if ((count < filelen) && (count != 0))
240 +               filelen = count;
242 +       if (ext4fs_read((char *)addr, filelen) != filelen) {
243 +               printf("** Unable to read \"%s\" from %s %d:%lu **\n",
244 +                      filename, argv[1], dev, part);
245 +               ext4fs_close();
246 +               return 1;
247 +       }
249 +       ext4fs_close();
250 +       deinit_fs(fs->dev_desc);
251 +       /* Loading ok, update default load address */
252 +       load_addr = addr;
254 +       printf("%d bytes read\n", filelen);
255 +       sprintf(buf, "%X", filelen);
256 +       setenv("filesize", buf);
258 +       return 0;
259 +}
261 +static int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
262 +{
263 +       const char *filename = "/";
264 +       int dev;
265 +       unsigned long part = 1;
266 +       char *ep;
267 +       struct ext_filesystem *fs;
268 +       int part_length;
270 +       if (argc < 3)
271 +               return cmd_usage(cmdtp);
273 +       dev = (int)simple_strtoul(argv[2], &ep, 16);
274 +       ext4_dev_desc = get_dev(argv[1], dev);
276 +       if (ext4_dev_desc == NULL) {
277 +               printf("\n** Block device %s %d not supported\n", argv[1], dev);
278 +               return 1;
279 +       }
281 +       if (init_fs(ext4_dev_desc))
282 +               return 1;
284 +       fs = get_fs();
285 +       if (*ep) {
286 +               if (*ep != ':') {
287 +                       puts("\n** Invalid boot device, use `dev[:part]' **\n");
288 +                       return 1;
289 +               }
290 +               part = simple_strtoul(++ep, NULL, 16);
291 +       }
293 +       if (argc == 4)
294 +               filename = argv[3];
296 +       part_length = ext4fs_set_blk_dev(fs->dev_desc, part);
297 +       if (part_length == 0) {
298 +               printf("** Bad partition - %s %d:%lu **\n", argv[1], dev, part);
299 +               ext4fs_close();
300 +               return 1;
301 +       }
303 +       if (!ext4fs_mount(part_length)) {
304 +               printf("** Bad ext2 partition or disk - %s %d:%lu **\n",
305 +                      argv[1], dev, part);
306 +               ext4fs_close();
307 +               return 1;
308 +       }
309 +       if (ext4fs_ls(filename)) {
310 +               printf("** Error ext2fs_ls() **\n");
311 +               ext4fs_close();
312 +               return 1;
313 +       };
315 +       ext4fs_close();
316 +       deinit_fs(fs->dev_desc);
318 +       return 0;
319 +}
321 +U_BOOT_CMD(ext4ls, 4, 1, do_ext4_ls,
322 +          "list files in a directory (default /)",
323 +          "<interface> <dev[:part]> [directory]\n"
324 +          "      - list files from 'dev' on 'interface' in a 'directory'");
326 +U_BOOT_CMD(ext4load, 6, 0, do_ext4_load,
327 +          "load binary file from a Ext2 filesystem",
328 +          "<interface> <dev[:part]> [addr] [filename] [bytes]\n"
329 +          "      - load binary file 'filename' from 'dev' on 'interface'\n"
330 +          "             to address 'addr' from ext2 filesystem");
331 diff --git a/fs/Makefile b/fs/Makefile
332 index 22aad12..00a8f37 100644
333 --- a/fs/Makefile
334 +++ b/fs/Makefile
335 @@ -23,6 +23,7 @@
336  #
337  
338  subdirs-$(CONFIG_CMD_CRAMFS) := cramfs
339 +subdirs-$(CONFIG_CMD_EXT4) += ext4
340  subdirs-$(CONFIG_CMD_EXT2) += ext2
341  subdirs-$(CONFIG_CMD_FAT) += fat
342  subdirs-$(CONFIG_CMD_FDOS) += fdos
343 diff --git a/fs/ext2/dev.c b/fs/ext2/dev.c
344 index 874e211..315ff53 100644
345 --- a/fs/ext2/dev.c
346 +++ b/fs/ext2/dev.c
347 @@ -27,6 +27,7 @@
348  #include <common.h>
349  #include <config.h>
350  #include <ext2fs.h>
351 +#include <ext_common.h>
352  
353  static block_dev_desc_t *ext2fs_block_dev_desc;
354  static disk_partition_t part_info;
355 diff --git a/fs/ext2/ext2fs.c b/fs/ext2/ext2fs.c
356 index 8531db5..ea3d98c 100644
357 --- a/fs/ext2/ext2fs.c
358 +++ b/fs/ext2/ext2fs.c
359 @@ -25,152 +25,16 @@
360  
361  #include <common.h>
362  #include <ext2fs.h>
363 +#include <ext_common.h>
364  #include <malloc.h>
365  #include <asm/byteorder.h>
366  
367  extern int ext2fs_devread (int sector, int byte_offset, int byte_len,
368                            char *buf);
369  
370 -/* Magic value used to identify an ext2 filesystem.  */
371 -#define        EXT2_MAGIC              0xEF53
372 -/* Amount of indirect blocks in an inode.  */
373 -#define INDIRECT_BLOCKS                12
374 -/* Maximum lenght of a pathname.  */
375 -#define EXT2_PATH_MAX          4096
376 -/* Maximum nesting of symlinks, used to prevent a loop.  */
377 -#define        EXT2_MAX_SYMLINKCNT     8
379 -/* Filetype used in directory entry.  */
380 -#define        FILETYPE_UNKNOWN        0
381 -#define        FILETYPE_REG            1
382 -#define        FILETYPE_DIRECTORY      2
383 -#define        FILETYPE_SYMLINK        7
385 -/* Filetype information as used in inodes.  */
386 -#define FILETYPE_INO_MASK      0170000
387 -#define FILETYPE_INO_REG       0100000
388 -#define FILETYPE_INO_DIRECTORY 0040000
389 -#define FILETYPE_INO_SYMLINK   0120000
391 -/* Bits used as offset in sector */
392 -#define DISK_SECTOR_BITS        9
394 -/* Log2 size of ext2 block in 512 blocks.  */
395 -#define LOG2_EXT2_BLOCK_SIZE(data) (__le32_to_cpu (data->sblock.log2_block_size) + 1)
397 -/* Log2 size of ext2 block in bytes.  */
398 -#define LOG2_BLOCK_SIZE(data)     (__le32_to_cpu (data->sblock.log2_block_size) + 10)
400 -/* The size of an ext2 block in bytes.  */
401 -#define EXT2_BLOCK_SIZE(data)     (1 << LOG2_BLOCK_SIZE(data))
403 -/* The ext2 superblock.  */
404 -struct ext2_sblock {
405 -       uint32_t total_inodes;
406 -       uint32_t total_blocks;
407 -       uint32_t reserved_blocks;
408 -       uint32_t free_blocks;
409 -       uint32_t free_inodes;
410 -       uint32_t first_data_block;
411 -       uint32_t log2_block_size;
412 -       uint32_t log2_fragment_size;
413 -       uint32_t blocks_per_group;
414 -       uint32_t fragments_per_group;
415 -       uint32_t inodes_per_group;
416 -       uint32_t mtime;
417 -       uint32_t utime;
418 -       uint16_t mnt_count;
419 -       uint16_t max_mnt_count;
420 -       uint16_t magic;
421 -       uint16_t fs_state;
422 -       uint16_t error_handling;
423 -       uint16_t minor_revision_level;
424 -       uint32_t lastcheck;
425 -       uint32_t checkinterval;
426 -       uint32_t creator_os;
427 -       uint32_t revision_level;
428 -       uint16_t uid_reserved;
429 -       uint16_t gid_reserved;
430 -       uint32_t first_inode;
431 -       uint16_t inode_size;
432 -       uint16_t block_group_number;
433 -       uint32_t feature_compatibility;
434 -       uint32_t feature_incompat;
435 -       uint32_t feature_ro_compat;
436 -       uint32_t unique_id[4];
437 -       char volume_name[16];
438 -       char last_mounted_on[64];
439 -       uint32_t compression_info;
440 -};
442 -/* The ext2 blockgroup.  */
443 -struct ext2_block_group {
444 -       uint32_t block_id;
445 -       uint32_t inode_id;
446 -       uint32_t inode_table_id;
447 -       uint16_t free_blocks;
448 -       uint16_t free_inodes;
449 -       uint16_t used_dir_cnt;
450 -       uint32_t reserved[3];
451 -};
453 -/* The ext2 inode.  */
454 -struct ext2_inode {
455 -       uint16_t mode;
456 -       uint16_t uid;
457 -       uint32_t size;
458 -       uint32_t atime;
459 -       uint32_t ctime;
460 -       uint32_t mtime;
461 -       uint32_t dtime;
462 -       uint16_t gid;
463 -       uint16_t nlinks;
464 -       uint32_t blockcnt;      /* Blocks of 512 bytes!! */
465 -       uint32_t flags;
466 -       uint32_t osd1;
467 -       union {
468 -               struct datablocks {
469 -                       uint32_t dir_blocks[INDIRECT_BLOCKS];
470 -                       uint32_t indir_block;
471 -                       uint32_t double_indir_block;
472 -                       uint32_t tripple_indir_block;
473 -               } blocks;
474 -               char symlink[60];
475 -       } b;
476 -       uint32_t version;
477 -       uint32_t acl;
478 -       uint32_t dir_acl;
479 -       uint32_t fragment_addr;
480 -       uint32_t osd2[3];
481 -};
483 -/* The header of an ext2 directory entry.  */
484 -struct ext2_dirent {
485 -       uint32_t inode;
486 -       uint16_t direntlen;
487 -       uint8_t namelen;
488 -       uint8_t filetype;
489 -};
491 -struct ext2fs_node {
492 -       struct ext2_data *data;
493 -       struct ext2_inode inode;
494 -       int ino;
495 -       int inode_read;
496 -};
498 -/* Information about a "mounted" ext2 filesystem.  */
499 -struct ext2_data {
500 -       struct ext2_sblock sblock;
501 -       struct ext2_inode *inode;
502 -       struct ext2fs_node diropen;
503 -};
506 -typedef struct ext2fs_node *ext2fs_node_t;
507  
508  struct ext2_data *ext2fs_root = NULL;
509 -ext2fs_node_t ext2fs_file = NULL;
510 +struct ext2fs_node *ext2fs_file;
511  int symlinknest = 0;
512  uint32_t *indir1_block = NULL;
513  int indir1_size = 0;
514 @@ -243,14 +107,16 @@ static int ext2fs_read_inode
515  }
516  
517  
518 -void ext2fs_free_node (ext2fs_node_t node, ext2fs_node_t currroot) {
519 +void ext2fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
520 +{
521         if ((node != &ext2fs_root->diropen) && (node != currroot)) {
522                 free (node);
523         }
524  }
525  
526  
527 -static int ext2fs_read_block (ext2fs_node_t node, int fileblock) {
528 +static int ext2fs_read_block(struct ext2fs_node *node, int fileblock)
529 +{
530         struct ext2_data *data = node->data;
531         struct ext2_inode *inode = &node->inode;
532         int blknr;
533 @@ -390,7 +256,8 @@ static int ext2fs_read_block (ext2fs_node_t node, int fileblock) {
534  
535  
536  int ext2fs_read_file
537 -       (ext2fs_node_t node, int pos, unsigned int len, char *buf) {
538 +       (struct ext2fs_node *node, int pos, unsigned int len, char *buf)
539 +{
540         int i;
541         int blockcnt;
542         int log2blocksize = LOG2_EXT2_BLOCK_SIZE (node->data);
543 @@ -471,8 +338,8 @@ int ext2fs_read_file
544         return (len);
545  }
546  
548 -static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fnode, int *ftype)
549 +int ext2fs_iterate_dir(struct ext2fs_node *dir, char *name,
550 +                                       struct ext2fs_node **fnode, int *ftype)
551  {
552         unsigned int fpos = 0;
553         int status;
554 @@ -501,7 +368,7 @@ static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fn
555                 }
556                 if (dirent.namelen != 0) {
557                         char filename[dirent.namelen + 1];
558 -                       ext2fs_node_t fdiro;
559 +                       struct ext2fs_node *fdiro;
560                         int type = FILETYPE_UNKNOWN;
561  
562                         status = ext2fs_read_file (diro,
563 @@ -603,8 +470,8 @@ static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fn
564         return (0);
565  }
566  
568 -static char *ext2fs_read_symlink (ext2fs_node_t node) {
569 +static char *ext2fs_read_symlink(struct ext2fs_node *node)
570 +{
571         char *symlink;
572         struct ext2fs_node *diro = node;
573         int status;
574 @@ -641,15 +508,16 @@ static char *ext2fs_read_symlink (ext2fs_node_t node) {
575  
576  
577  int ext2fs_find_file1
578 -       (const char *currpath,
579 -        ext2fs_node_t currroot, ext2fs_node_t * currfound, int *foundtype) {
580 +       (const char *currpath, struct ext2fs_node *currroot,
581 +               struct ext2fs_node **currfound, int *foundtype)
582 +{
583         char fpath[strlen (currpath) + 1];
584         char *name = fpath;
585         char *next;
586         int status;
587         int type = FILETYPE_DIRECTORY;
588 -       ext2fs_node_t currnode = currroot;
589 -       ext2fs_node_t oldnode = currroot;
590 +       struct ext2fs_node *currnode = currroot;
591 +       struct ext2fs_node *oldnode = currroot;
592  
593         strncpy (fpath, currpath, strlen (currpath) + 1);
594  
595 @@ -745,8 +613,9 @@ int ext2fs_find_file1
596  
597  
598  int ext2fs_find_file
599 -       (const char *path,
600 -        ext2fs_node_t rootnode, ext2fs_node_t * foundnode, int expecttype) {
601 +       (const char *path, struct ext2fs_node *rootnode,
602 +       struct ext2fs_node **foundnode, int expecttype)
603 +{
604         int status;
605         int foundtype = FILETYPE_DIRECTORY;
606  
607 @@ -772,7 +641,7 @@ int ext2fs_find_file
608  
609  
610  int ext2fs_ls (const char *dirname) {
611 -       ext2fs_node_t dirnode;
612 +       struct ext2fs_node *dirnode;
613         int status;
614  
615         if (ext2fs_root == NULL) {
616 @@ -792,7 +661,7 @@ int ext2fs_ls (const char *dirname) {
617  
618  
619  int ext2fs_open (const char *filename) {
620 -       ext2fs_node_t fdiro = NULL;
621 +       struct ext2fs_node *fdiro = NULL;
622         int status;
623         int len;
624  
625 @@ -822,8 +691,8 @@ fail:
626  }
627  
628  
629 -int ext2fs_close (void
630 -       ) {
631 +int ext2fs_close(void)
632 +{
633         if ((ext2fs_file != NULL) && (ext2fs_root != NULL)) {
634                 ext2fs_free_node (ext2fs_file, &ext2fs_root->diropen);
635                 ext2fs_file = NULL;
636 diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
637 new file mode 100644
638 index 0000000..7add4ab
639 --- /dev/null
640 +++ b/fs/ext4/Makefile
641 @@ -0,0 +1,51 @@
642 +#
643 +# (C) Copyright 2006
644 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
645 +#
646 +# (C) Copyright 2003
647 +# Pavel Bartusek, Sysgo Real-Time Solutions AG, pba@sysgo.de
648 +#
649 +#
650 +# See file CREDITS for list of people who contributed to this
651 +# project.
652 +#
653 +# This program is free software; you can redistribute it and/or
654 +# modify it under the terms of the GNU General Public License as
655 +# published by the Free Software Foundation; either version 2 of
656 +# the License, or (at your option) any later version.
657 +#
658 +# This program is distributed in the hope that it will be useful,
659 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
660 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
661 +# GNU General Public License for more details.
662 +#
663 +# You should have received a copy of the GNU General Public License
664 +# along with this program; if not, write to the Free Software
665 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
666 +# MA 02111-1307 USA
667 +#
669 +include $(TOPDIR)/config.mk
671 +LIB    = $(obj)libext4fs.o
673 +AOBJS  =
674 +COBJS-$(CONFIG_CMD_EXT4) := ext4fs.o ext4_common.o dev.o
676 +SRCS   := $(AOBJS:.o=.S) $(COBJS-y:.o=.c)
677 +OBJS   := $(addprefix $(obj),$(AOBJS) $(COBJS-y))
680 +all:   $(LIB) $(AOBJS)
682 +$(LIB):        $(obj).depend $(OBJS)
683 +       $(call cmd_link_o_target, $(OBJS))
685 +#########################################################################
687 +# defines $(obj).depend target
688 +include $(SRCTREE)/rules.mk
690 +sinclude $(obj).depend
692 +#########################################################################
693 diff --git a/fs/ext4/dev.c b/fs/ext4/dev.c
694 new file mode 100644
695 index 0000000..2054be3
696 --- /dev/null
697 +++ b/fs/ext4/dev.c
698 @@ -0,0 +1,145 @@
699 +/*
700 + * (C) Copyright 2011 - 2012 Samsung Electronics
701 + * EXT4 filesystem implementation in Uboot by
702 + * Uma Shankar <uma.shankar@samsung.com>
703 + * Manjunatha C Achar <a.manjunatha@samsung.com>
704 + *
705 + * made from existing ext2/dev.c file of Uboot
706 + * (C) Copyright 2004
707 + * esd gmbh <www.esd-electronics.com>
708 + * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
709 + *
710 + * based on code of fs/reiserfs/dev.c by
711 + *
712 + * (C) Copyright 2003 - 2004
713 + * Sysgo AG, <www.elinos.com>, Pavel Bartusek <pba@sysgo.com>
714 + *
715 + * This program is free software; you can redistribute it and/or modify
716 + * it under the terms of the GNU General Public License as published by
717 + * the Free Software Foundation; either version 2 of the License, or
718 + * (at your option) any later version.
719 + *
720 + * This program is distributed in the hope that it will be useful,
721 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
722 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
723 + * GNU General Public License for more details.
724 + *
725 + * You should have received a copy of the GNU General Public License
726 + * along with this program; if not, write to the Free Software
727 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
728 + *
729 + */
731 +/*
732 + * Changelog:
733 + *     0.1 - Newly created file for ext4fs support. Taken from
734 + *             fs/ext2/dev.c file in uboot.
735 + */
737 +#include <common.h>
738 +#include <config.h>
739 +#include <ext_common.h>
741 +static block_dev_desc_t *ext4fs_block_dev_desc;
742 +static disk_partition_t part_info;
744 +int ext4fs_set_blk_dev(block_dev_desc_t *rbdd, int part)
745 +{
746 +       ext4fs_block_dev_desc = rbdd;
748 +       if (part == 0) {
749 +               /* disk doesn't use partition table */
750 +               part_info.start = 0;
751 +               part_info.size = rbdd->lba;
752 +               part_info.blksz = rbdd->blksz;
753 +       } else {
754 +               if (get_partition_info(ext4fs_block_dev_desc,
755 +                                       part, &part_info))
756 +                       return 0;
757 +       }
758 +       return part_info.size;
759 +}
761 +int ext4fs_devread(int sector, int byte_offset, int byte_len, char *buf)
762 +{
763 +       char sec_buf[SECTOR_SIZE];
764 +       unsigned block_len;
766 +       /* Check partition boundaries */
767 +       if ((sector < 0)
768 +           || ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS)) >=
769 +               part_info.size)) {
770 +               printf("%s read outside partition %d\n", __func__, sector);
771 +               return 0;
772 +       }
774 +       /* Get the read to the beginning of a partition */
775 +       sector += byte_offset >> SECTOR_BITS;
776 +       byte_offset &= SECTOR_SIZE - 1;
778 +       debug(" <%d, %d, %d>\n", sector, byte_offset, byte_len);
780 +       if (ext4fs_block_dev_desc == NULL) {
781 +               printf("** Invalid Block Device Descriptor (NULL)\n");
782 +               return 0;
783 +       }
785 +       if (byte_offset != 0) {
786 +               /* read first part which isn't aligned with start of sector */
787 +               if (ext4fs_block_dev_desc->
788 +                   block_read(ext4fs_block_dev_desc->dev,
789 +                               part_info.start + sector, 1,
790 +                               (unsigned long *) sec_buf) != 1) {
791 +                       printf(" ** ext2fs_devread() read error **\n");
792 +                       return 0;
793 +               }
794 +               memcpy(buf, sec_buf + byte_offset,
795 +                       min(SECTOR_SIZE - byte_offset, byte_len));
796 +               buf += min(SECTOR_SIZE - byte_offset, byte_len);
797 +               byte_len -= min(SECTOR_SIZE - byte_offset, byte_len);
798 +               sector++;
799 +       }
801 +       if (byte_len == 0)
802 +               return 1;
804 +       /* read sector aligned part */
805 +       block_len = byte_len & ~(SECTOR_SIZE - 1);
807 +       if (block_len == 0) {
808 +               u8 p[SECTOR_SIZE];
810 +               block_len = SECTOR_SIZE;
811 +               ext4fs_block_dev_desc->block_read(ext4fs_block_dev_desc->dev,
812 +                                                 part_info.start + sector,
813 +                                                 1, (unsigned long *)p);
814 +               memcpy(buf, p, byte_len);
815 +               return 1;
816 +       }
818 +       if (ext4fs_block_dev_desc->block_read(ext4fs_block_dev_desc->dev,
819 +                                       part_info.start + sector,
820 +                                       block_len / SECTOR_SIZE,
821 +                                       (unsigned long *) buf) !=
822 +                                       block_len / SECTOR_SIZE) {
823 +               printf(" ** %s read error - block\n", __func__);
824 +               return 0;
825 +       }
826 +       block_len = byte_len & ~(SECTOR_SIZE - 1);
827 +       buf += block_len;
828 +       byte_len -= block_len;
829 +       sector += block_len / SECTOR_SIZE;
831 +       if (byte_len != 0) {
832 +               /* read rest of data which are not in whole sector */
833 +               if (ext4fs_block_dev_desc->
834 +                   block_read(ext4fs_block_dev_desc->dev,
835 +                               part_info.start + sector, 1,
836 +                               (unsigned long *) sec_buf) != 1) {
837 +                       printf("* %s read error - last part\n", __func__);
838 +                       return 0;
839 +               }
840 +               memcpy(buf, sec_buf, byte_len);
841 +       }
842 +       return 1;
843 +}
844 diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
845 new file mode 100644
846 index 0000000..d9deefe
847 --- /dev/null
848 +++ b/fs/ext4/ext4_common.c
849 @@ -0,0 +1,875 @@
850 +/*
851 + * (C) Copyright 2011 - 2012 Samsung Electronics
852 + * EXT4 filesystem implementation in Uboot by
853 + * Uma Shankar <uma.shankar@samsung.com>
854 + * Manjunatha C Achar <a.manjunatha@samsung.com>
855 + *
856 + * ext4ls and ext4load : Based on ext2 ls load support in Uboot.
857 + *
858 + * (C) Copyright 2004
859 + * esd gmbh <www.esd-electronics.com>
860 + * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
861 + *
862 + * based on code from grub2 fs/ext2.c and fs/fshelp.c by
863 + * GRUB  --  GRand Unified Bootloader
864 + * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
865 + *
866 + * This program is free software; you can redistribute it and/or modify
867 + * it under the terms of the GNU General Public License as published by
868 + * the Free Software Foundation; either version 2 of the License, or
869 + * (at your option) any later version.
870 + *
871 + * This program is distributed in the hope that it will be useful,
872 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
873 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
874 + * GNU General Public License for more details.
875 + *
876 + * You should have received a copy of the GNU General Public License
877 + * along with this program; if not, write to the Free Software
878 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
879 + */
881 +#include <common.h>
882 +#include <ext_common.h>
883 +#include <ext4fs.h>
884 +#include <malloc.h>
885 +#include <stddef.h>
886 +#include <linux/stat.h>
887 +#include <linux/time.h>
888 +#include <asm/byteorder.h>
889 +#include "ext4_common.h"
891 +struct ext2_data *ext4fs_root;
892 +struct ext2fs_node *ext4fs_file;
893 +uint32_t *ext4fs_indir1_block;
894 +int ext4fs_indir1_size;
895 +int ext4fs_indir1_blkno = -1;
896 +uint32_t *ext4fs_indir2_block;
897 +int ext4fs_indir2_size;
898 +int ext4fs_indir2_blkno = -1;
900 +uint32_t *ext4fs_indir3_block;
901 +int ext4fs_indir3_size;
902 +int ext4fs_indir3_blkno = -1;
903 +struct ext2_inode *g_parent_inode;
904 +static int symlinknest;
906 +static struct ext4_extent_header *ext4fs_get_extent_block
907 +       (struct ext2_data *data, char *buf,
908 +               struct ext4_extent_header *ext_block,
909 +               uint32_t fileblock, int log2_blksz)
910 +{
911 +       struct ext4_extent_idx *index;
912 +       unsigned long long block;
913 +       struct ext_filesystem *fs = get_fs();
914 +       int i;
916 +       while (1) {
917 +               index = (struct ext4_extent_idx *)(ext_block + 1);
919 +               if (le32_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC)
920 +                       return 0;
922 +               if (ext_block->eh_depth == 0)
923 +                       return ext_block;
924 +               i = -1;
925 +               do {
926 +                       i++;
927 +                       if (i >= le32_to_cpu(ext_block->eh_entries))
928 +                               break;
929 +               } while (fileblock > le32_to_cpu(index[i].ei_block));
931 +               if (--i < 0)
932 +                       return 0;
934 +               block = le32_to_cpu(index[i].ei_leaf_hi);
935 +               block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo);
937 +               if (ext4fs_devread(block << log2_blksz, 0, fs->blksz, buf))
938 +                       ext_block = (struct ext4_extent_header *)buf;
939 +               else
940 +                       return 0;
941 +       }
942 +}
944 +static int ext4fs_blockgroup
945 +       (struct ext2_data *data, int group, struct ext2_block_group *blkgrp)
946 +{
947 +       long int blkno;
948 +       unsigned int blkoff, desc_per_blk;
950 +       desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group);
952 +       blkno = __le32_to_cpu(data->sblock.first_data_block) + 1 +
953 +           group / desc_per_blk;
954 +       blkoff = (group % desc_per_blk) * sizeof(struct ext2_block_group);
956 +       debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n",
957 +             group, blkno, blkoff);
959 +       return ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data),
960 +                             blkoff, sizeof(struct ext2_block_group),
961 +                             (char *)blkgrp);
962 +}
964 +int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
965 +{
966 +       struct ext2_block_group blkgrp;
967 +       struct ext2_sblock *sblock = &data->sblock;
968 +       struct ext_filesystem *fs = get_fs();
969 +       int inodes_per_block, status;
970 +       long int blkno;
971 +       unsigned int blkoff;
973 +       /* It is easier to calculate if the first inode is 0. */
974 +       ino--;
975 +       status = ext4fs_blockgroup(data, ino / __le32_to_cpu
976 +                                  (sblock->inodes_per_group), &blkgrp);
977 +       if (status == 0)
978 +               return 0;
980 +       inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz;
981 +       blkno = __le32_to_cpu(blkgrp.inode_table_id) +
982 +           (ino % __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
983 +       blkoff = (ino % inodes_per_block) * fs->inodesz;
984 +       /* Read the inode. */
985 +       status = ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data), blkoff,
986 +                               sizeof(struct ext2_inode), (char *)inode);
987 +       if (status == 0)
988 +               return 0;
990 +       return 1;
991 +}
993 +long int read_allocated_block(struct ext2_inode *inode, int fileblock)
994 +{
995 +       long int blknr;
996 +       int blksz;
997 +       int log2_blksz;
998 +       int status;
999 +       long int rblock;
1000 +       long int perblock_parent;
1001 +       long int perblock_child;
1002 +       unsigned long long start;
1003 +       /* get the blocksize of the filesystem */
1004 +       blksz = EXT2_BLOCK_SIZE(ext4fs_root);
1005 +       log2_blksz = LOG2_EXT2_BLOCK_SIZE(ext4fs_root);
1006 +       if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) {
1007 +               char *buf = zalloc(blksz);
1008 +               if (!buf)
1009 +                       return -ENOMEM;
1010 +               struct ext4_extent_header *ext_block;
1011 +               struct ext4_extent *extent;
1012 +               int i = -1;
1013 +               ext_block = ext4fs_get_extent_block(ext4fs_root, buf,
1014 +                                                   (struct ext4_extent_header
1015 +                                                    *)inode->b.
1016 +                                                   blocks.dir_blocks,
1017 +                                                   fileblock, log2_blksz);
1018 +               if (!ext_block) {
1019 +                       printf("invalid extent block\n");
1020 +                       free(buf);
1021 +                       return -EINVAL;
1022 +               }
1024 +               extent = (struct ext4_extent *)(ext_block + 1);
1026 +               do {
1027 +                       i++;
1028 +                       if (i >= le32_to_cpu(ext_block->eh_entries))
1029 +                               break;
1030 +               } while (fileblock >= le32_to_cpu(extent[i].ee_block));
1031 +               if (--i >= 0) {
1032 +                       fileblock -= le32_to_cpu(extent[i].ee_block);
1033 +                       if (fileblock >= le32_to_cpu(extent[i].ee_len)) {
1034 +                               free(buf);
1035 +                               return 0;
1036 +                       }
1038 +                       start = le32_to_cpu(extent[i].ee_start_hi);
1039 +                       start = (start << 32) +
1040 +                           le32_to_cpu(extent[i].ee_start_lo);
1041 +                       free(buf);
1042 +                       return fileblock + start;
1043 +               }
1045 +               printf("Extent Error\n");
1046 +               free(buf);
1047 +               return -1;
1048 +       }
1050 +       /* Direct blocks. */
1051 +       if (fileblock < INDIRECT_BLOCKS)
1052 +               blknr = __le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]);
1054 +       /* Indirect. */
1055 +       else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
1056 +               if (ext4fs_indir1_block == NULL) {
1057 +                       ext4fs_indir1_block = zalloc(blksz);
1058 +                       if (ext4fs_indir1_block == NULL) {
1059 +                               printf("** SI ext2fs read block (indir 1)"
1060 +                                      "malloc failed. **\n");
1061 +                               return -1;
1062 +                       }
1063 +                       ext4fs_indir1_size = blksz;
1064 +                       ext4fs_indir1_blkno = -1;
1065 +               }
1066 +               if (blksz != ext4fs_indir1_size) {
1067 +                       free(ext4fs_indir1_block);
1068 +                       ext4fs_indir1_block = NULL;
1069 +                       ext4fs_indir1_size = 0;
1070 +                       ext4fs_indir1_blkno = -1;
1071 +                       ext4fs_indir1_block = zalloc(blksz);
1072 +                       if (ext4fs_indir1_block == NULL) {
1073 +                               printf("** SI ext2fs read block (indir 1):"
1074 +                                      "malloc failed. **\n");
1075 +                               return -1;
1076 +                       }
1077 +                       ext4fs_indir1_size = blksz;
1078 +               }
1079 +               if ((__le32_to_cpu(inode->b.blocks.indir_block) <<
1080 +                    log2_blksz) != ext4fs_indir1_blkno) {
1081 +                       status =
1082 +                           ext4fs_devread(__le32_to_cpu
1083 +                                          (inode->b.blocks.
1084 +                                           indir_block) << log2_blksz, 0,
1085 +                                          blksz, (char *)ext4fs_indir1_block);
1086 +                       if (status == 0) {
1087 +                               printf("** SI ext2fs read block (indir 1)"
1088 +                                      "failed. **\n");
1089 +                               return 0;
1090 +                       }
1091 +                       ext4fs_indir1_blkno =
1092 +                           __le32_to_cpu(inode->b.blocks.
1093 +                                         indir_block) << log2_blksz;
1094 +               }
1095 +               blknr = __le32_to_cpu(ext4fs_indir1_block
1096 +                                     [fileblock - INDIRECT_BLOCKS]);
1097 +       }
1098 +       /* Double indirect. */
1099 +       else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4 *
1100 +                                       (blksz / 4 + 1)))) {
1102 +               long int perblock = blksz / 4;
1103 +               long int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4);
1105 +               if (ext4fs_indir1_block == NULL) {
1106 +                       ext4fs_indir1_block = zalloc(blksz);
1107 +                       if (ext4fs_indir1_block == NULL) {
1108 +                               printf("** DI ext2fs read block (indir 2 1)"
1109 +                                      "malloc failed. **\n");
1110 +                               return -1;
1111 +                       }
1112 +                       ext4fs_indir1_size = blksz;
1113 +                       ext4fs_indir1_blkno = -1;
1114 +               }
1115 +               if (blksz != ext4fs_indir1_size) {
1116 +                       free(ext4fs_indir1_block);
1117 +                       ext4fs_indir1_block = NULL;
1118 +                       ext4fs_indir1_size = 0;
1119 +                       ext4fs_indir1_blkno = -1;
1120 +                       ext4fs_indir1_block = zalloc(blksz);
1121 +                       if (ext4fs_indir1_block == NULL) {
1122 +                               printf("** DI ext2fs read block (indir 2 1)"
1123 +                                      "malloc failed. **\n");
1124 +                               return -1;
1125 +                       }
1126 +                       ext4fs_indir1_size = blksz;
1127 +               }
1128 +               if ((__le32_to_cpu(inode->b.blocks.double_indir_block) <<
1129 +                    log2_blksz) != ext4fs_indir1_blkno) {
1130 +                       status =
1131 +                           ext4fs_devread(__le32_to_cpu
1132 +                                          (inode->b.blocks.
1133 +                                           double_indir_block) << log2_blksz,
1134 +                                          0, blksz,
1135 +                                          (char *)ext4fs_indir1_block);
1136 +                       if (status == 0) {
1137 +                               printf("** DI ext2fs read block (indir 2 1)"
1138 +                                      "failed. **\n");
1139 +                               return -1;
1140 +                       }
1141 +                       ext4fs_indir1_blkno =
1142 +                           __le32_to_cpu(inode->b.blocks.double_indir_block) <<
1143 +                           log2_blksz;
1144 +               }
1146 +               if (ext4fs_indir2_block == NULL) {
1147 +                       ext4fs_indir2_block = zalloc(blksz);
1148 +                       if (ext4fs_indir2_block == NULL) {
1149 +                               printf("** DI ext2fs read block (indir 2 2)"
1150 +                                      "malloc failed. **\n");
1151 +                               return -1;
1152 +                       }
1153 +                       ext4fs_indir2_size = blksz;
1154 +                       ext4fs_indir2_blkno = -1;
1155 +               }
1156 +               if (blksz != ext4fs_indir2_size) {
1157 +                       free(ext4fs_indir2_block);
1158 +                       ext4fs_indir2_block = NULL;
1159 +                       ext4fs_indir2_size = 0;
1160 +                       ext4fs_indir2_blkno = -1;
1161 +                       ext4fs_indir2_block = zalloc(blksz);
1162 +                       if (ext4fs_indir2_block == NULL) {
1163 +                               printf("** DI ext2fs read block (indir 2 2)"
1164 +                                      "malloc failed. **\n");
1165 +                               return -1;
1166 +                       }
1167 +                       ext4fs_indir2_size = blksz;
1168 +               }
1169 +               if ((__le32_to_cpu(ext4fs_indir1_block[rblock / perblock]) <<
1170 +                    log2_blksz) != ext4fs_indir2_blkno) {
1171 +                       status = ext4fs_devread(__le32_to_cpu
1172 +                                               (ext4fs_indir1_block
1173 +                                                [rblock /
1174 +                                                 perblock]) << log2_blksz, 0,
1175 +                                               blksz,
1176 +                                               (char *)ext4fs_indir2_block);
1177 +                       if (status == 0) {
1178 +                               printf("** DI ext2fs read block (indir 2 2)"
1179 +                                      "failed. **\n");
1180 +                               return -1;
1181 +                       }
1182 +                       ext4fs_indir2_blkno =
1183 +                           __le32_to_cpu(ext4fs_indir1_block[rblock
1184 +                                                             /
1185 +                                                             perblock]) <<
1186 +                           log2_blksz;
1187 +               }
1188 +               blknr = __le32_to_cpu(ext4fs_indir2_block[rblock % perblock]);
1189 +       }
1190 +       /* Tripple indirect. */
1191 +       else {
1192 +               rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 +
1193 +                                     (blksz / 4 * blksz / 4));
1194 +               perblock_child = blksz / 4;
1195 +               perblock_parent = ((blksz / 4) * (blksz / 4));
1197 +               if (ext4fs_indir1_block == NULL) {
1198 +                       ext4fs_indir1_block = zalloc(blksz);
1199 +                       if (ext4fs_indir1_block == NULL) {
1200 +                               printf("** TI ext2fs read block (indir 2 1)"
1201 +                                      "malloc failed. **\n");
1202 +                               return -1;
1203 +                       }
1204 +                       ext4fs_indir1_size = blksz;
1205 +                       ext4fs_indir1_blkno = -1;
1206 +               }
1207 +               if (blksz != ext4fs_indir1_size) {
1208 +                       free(ext4fs_indir1_block);
1209 +                       ext4fs_indir1_block = NULL;
1210 +                       ext4fs_indir1_size = 0;
1211 +                       ext4fs_indir1_blkno = -1;
1212 +                       ext4fs_indir1_block = zalloc(blksz);
1213 +                       if (ext4fs_indir1_block == NULL) {
1214 +                               printf("** TI ext2fs read block (indir 2 1)"
1215 +                                      "malloc failed. **\n");
1216 +                               return -1;
1217 +                       }
1218 +                       ext4fs_indir1_size = blksz;
1219 +               }
1220 +               if ((__le32_to_cpu(inode->b.blocks.triple_indir_block) <<
1221 +                    log2_blksz) != ext4fs_indir1_blkno) {
1222 +                       status = ext4fs_devread
1223 +                           (__le32_to_cpu(inode->b.blocks.triple_indir_block)
1224 +                            << log2_blksz, 0, blksz,
1225 +                            (char *)ext4fs_indir1_block);
1226 +                       if (status == 0) {
1227 +                               printf("** TI ext2fs read block (indir 2 1)"
1228 +                                      "failed. **\n");
1229 +                               return -1;
1230 +                       }
1231 +                       ext4fs_indir1_blkno =
1232 +                           __le32_to_cpu(inode->b.blocks.triple_indir_block) <<
1233 +                           log2_blksz;
1234 +               }
1236 +               if (ext4fs_indir2_block == NULL) {
1237 +                       ext4fs_indir2_block = zalloc(blksz);
1238 +                       if (ext4fs_indir2_block == NULL) {
1239 +                               printf("** TI ext2fs read block (indir 2 2)"
1240 +                                      "malloc failed. **\n");
1241 +                               return -1;
1242 +                       }
1243 +                       ext4fs_indir2_size = blksz;
1244 +                       ext4fs_indir2_blkno = -1;
1245 +               }
1246 +               if (blksz != ext4fs_indir2_size) {
1247 +                       free(ext4fs_indir2_block);
1248 +                       ext4fs_indir2_block = NULL;
1249 +                       ext4fs_indir2_size = 0;
1250 +                       ext4fs_indir2_blkno = -1;
1251 +                       ext4fs_indir2_block = zalloc(blksz);
1252 +                       if (ext4fs_indir2_block == NULL) {
1253 +                               printf("** TI ext2fs read block (indir 2 2)"
1254 +                                      "malloc failed. **\n");
1255 +                               return -1;
1256 +                       }
1257 +                       ext4fs_indir2_size = blksz;
1258 +               }
1259 +               if ((__le32_to_cpu(ext4fs_indir1_block[rblock /
1260 +                                                      perblock_parent]) <<
1261 +                    log2_blksz)
1262 +                   != ext4fs_indir2_blkno) {
1263 +                       status = ext4fs_devread(__le32_to_cpu
1264 +                                               (ext4fs_indir1_block
1265 +                                                [rblock /
1266 +                                                 perblock_parent]) <<
1267 +                                               log2_blksz, 0, blksz,
1268 +                                               (char *)ext4fs_indir2_block);
1269 +                       if (status == 0) {
1270 +                               printf("** TI ext2fs read block (indir 2 2)"
1271 +                                      "failed. **\n");
1272 +                               return -1;
1273 +                       }
1274 +                       ext4fs_indir2_blkno =
1275 +                           __le32_to_cpu(ext4fs_indir1_block[rblock /
1276 +                                                             perblock_parent])
1277 +                           << log2_blksz;
1278 +               }
1280 +               if (ext4fs_indir3_block == NULL) {
1281 +                       ext4fs_indir3_block = zalloc(blksz);
1282 +                       if (ext4fs_indir3_block == NULL) {
1283 +                               printf("** TI ext2fs read block (indir 2 2)"
1284 +                                      "malloc failed. **\n");
1285 +                               return -1;
1286 +                       }
1287 +                       ext4fs_indir3_size = blksz;
1288 +                       ext4fs_indir3_blkno = -1;
1289 +               }
1290 +               if (blksz != ext4fs_indir3_size) {
1291 +                       free(ext4fs_indir3_block);
1292 +                       ext4fs_indir3_block = NULL;
1293 +                       ext4fs_indir3_size = 0;
1294 +                       ext4fs_indir3_blkno = -1;
1295 +                       ext4fs_indir3_block = zalloc(blksz);
1296 +                       if (ext4fs_indir3_block == NULL) {
1297 +                               printf("** TI ext2fs read block (indir 2 2)"
1298 +                                      "malloc failed. **\n");
1299 +                               return -1;
1300 +                       }
1301 +                       ext4fs_indir3_size = blksz;
1302 +               }
1303 +               if ((__le32_to_cpu(ext4fs_indir2_block[rblock
1304 +                                                      /
1305 +                                                      perblock_child]) <<
1306 +                    log2_blksz) != ext4fs_indir3_blkno) {
1307 +                       status =
1308 +                           ext4fs_devread(__le32_to_cpu
1309 +                                          (ext4fs_indir2_block
1310 +                                           [(rblock / perblock_child)
1311 +                                            % (blksz / 4)]) << log2_blksz, 0,
1312 +                                          blksz, (char *)ext4fs_indir3_block);
1313 +                       if (status == 0) {
1314 +                               printf("** TI ext2fs read block (indir 2 2)"
1315 +                                      "failed. **\n");
1316 +                               return -1;
1317 +                       }
1318 +                       ext4fs_indir3_blkno =
1319 +                           __le32_to_cpu(ext4fs_indir2_block[(rblock /
1320 +                                                              perblock_child) %
1321 +                                                             (blksz /
1322 +                                                              4)]) <<
1323 +                           log2_blksz;
1324 +               }
1326 +               blknr = __le32_to_cpu(ext4fs_indir3_block
1327 +                                     [rblock % perblock_child]);
1328 +       }
1329 +       debug("ext4fs_read_block %ld\n", blknr);
1331 +       return blknr;
1332 +}
1334 +void ext4fs_close(void)
1335 +{
1336 +       if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
1337 +               ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen);
1338 +               ext4fs_file = NULL;
1339 +       }
1340 +       if (ext4fs_root != NULL) {
1341 +               free(ext4fs_root);
1342 +               ext4fs_root = NULL;
1343 +       }
1344 +       if (ext4fs_indir1_block != NULL) {
1345 +               free(ext4fs_indir1_block);
1346 +               ext4fs_indir1_block = NULL;
1347 +               ext4fs_indir1_size = 0;
1348 +               ext4fs_indir1_blkno = -1;
1349 +       }
1350 +       if (ext4fs_indir2_block != NULL) {
1351 +               free(ext4fs_indir2_block);
1352 +               ext4fs_indir2_block = NULL;
1353 +               ext4fs_indir2_size = 0;
1354 +               ext4fs_indir2_blkno = -1;
1355 +       }
1356 +       if (ext4fs_indir3_block != NULL) {
1357 +               free(ext4fs_indir3_block);
1358 +               ext4fs_indir3_block = NULL;
1359 +               ext4fs_indir3_size = 0;
1360 +               ext4fs_indir3_blkno = -1;
1361 +       }
1362 +}
1364 +int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
1365 +                      struct ext2fs_node **fnode, int *ftype)
1366 +{
1367 +       unsigned int fpos = 0;
1368 +       int status;
1369 +       struct ext2fs_node *diro = (struct ext2fs_node *)dir;
1371 +#ifdef DEBUG
1372 +       if (name != NULL)
1373 +               printf("Iterate dir %s\n", name);
1374 +#endif                         /* of DEBUG */
1375 +       if (!diro->inode_read) {
1376 +               status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
1377 +               if (status == 0)
1378 +                       return 0;
1379 +       }
1380 +       /* Search the file.  */
1381 +       while (fpos < __le32_to_cpu(diro->inode.size)) {
1382 +               struct ext2_dirent dirent;
1384 +               status = ext4fs_read_file(diro, fpos,
1385 +                                         sizeof(struct ext2_dirent),
1386 +                                         (char *)&dirent);
1387 +               if (status < 1)
1388 +                       return 0;
1390 +               if (dirent.namelen != 0) {
1391 +                       char filename[dirent.namelen + 1];
1392 +                       struct ext2fs_node *fdiro;
1393 +                       int type = FILETYPE_UNKNOWN;
1395 +                       status = ext4fs_read_file(diro,
1396 +                                                 fpos +
1397 +                                                 sizeof(struct ext2_dirent),
1398 +                                                 dirent.namelen, filename);
1399 +                       if (status < 1)
1400 +                               return 0;
1402 +                       fdiro = zalloc(sizeof(struct ext2fs_node));
1403 +                       if (!fdiro)
1404 +                               return 0;
1406 +                       fdiro->data = diro->data;
1407 +                       fdiro->ino = __le32_to_cpu(dirent.inode);
1409 +                       filename[dirent.namelen] = '\0';
1411 +                       if (dirent.filetype != FILETYPE_UNKNOWN) {
1412 +                               fdiro->inode_read = 0;
1414 +                               if (dirent.filetype == FILETYPE_DIRECTORY)
1415 +                                       type = FILETYPE_DIRECTORY;
1416 +                               else if (dirent.filetype == FILETYPE_SYMLINK)
1417 +                                       type = FILETYPE_SYMLINK;
1418 +                               else if (dirent.filetype == FILETYPE_REG)
1419 +                                       type = FILETYPE_REG;
1420 +                       } else {
1421 +                               status = ext4fs_read_inode(diro->data,
1422 +                                                          __le32_to_cpu
1423 +                                                          (dirent.inode),
1424 +                                                          &fdiro->inode);
1425 +                               if (status == 0) {
1426 +                                       free(fdiro);
1427 +                                       return 0;
1428 +                               }
1429 +                               fdiro->inode_read = 1;
1431 +                               if ((__le16_to_cpu(fdiro->inode.mode) &
1432 +                                    FILETYPE_INO_MASK) ==
1433 +                                   FILETYPE_INO_DIRECTORY) {
1434 +                                       type = FILETYPE_DIRECTORY;
1435 +                               } else if ((__le16_to_cpu(fdiro->inode.mode)
1436 +                                           & FILETYPE_INO_MASK) ==
1437 +                                          FILETYPE_INO_SYMLINK) {
1438 +                                       type = FILETYPE_SYMLINK;
1439 +                               } else if ((__le16_to_cpu(fdiro->inode.mode)
1440 +                                           & FILETYPE_INO_MASK) ==
1441 +                                          FILETYPE_INO_REG) {
1442 +                                       type = FILETYPE_REG;
1443 +                               }
1444 +                       }
1445 +#ifdef DEBUG
1446 +                       printf("iterate >%s<\n", filename);
1447 +#endif                         /* of DEBUG */
1448 +                       if ((name != NULL) && (fnode != NULL)
1449 +                           && (ftype != NULL)) {
1450 +                               if (strcmp(filename, name) == 0) {
1451 +                                       *ftype = type;
1452 +                                       *fnode = fdiro;
1453 +                                       return 1;
1454 +                               }
1455 +                       } else {
1456 +                               if (fdiro->inode_read == 0) {
1457 +                                       status = ext4fs_read_inode(diro->data,
1458 +                                                                __le32_to_cpu(
1459 +                                                                dirent.inode),
1460 +                                                                &fdiro->inode);
1461 +                                       if (status == 0) {
1462 +                                               free(fdiro);
1463 +                                               return 0;
1464 +                                       }
1465 +                                       fdiro->inode_read = 1;
1466 +                               }
1467 +                               switch (type) {
1468 +                               case FILETYPE_DIRECTORY:
1469 +                                       printf("<DIR> ");
1470 +                                       break;
1471 +                               case FILETYPE_SYMLINK:
1472 +                                       printf("<SYM> ");
1473 +                                       break;
1474 +                               case FILETYPE_REG:
1475 +                                       printf("      ");
1476 +                                       break;
1477 +                               default:
1478 +                                       printf("< ? > ");
1479 +                                       break;
1480 +                               }
1481 +                               printf("%10d %s\n",
1482 +                                      __le32_to_cpu(fdiro->inode.size),
1483 +                                      filename);
1484 +                       }
1485 +                       free(fdiro);
1486 +               }
1487 +               fpos += __le16_to_cpu(dirent.direntlen);
1488 +       }
1489 +       return 0;
1490 +}
1492 +static char *ext4fs_read_symlink(struct ext2fs_node *node)
1493 +{
1494 +       char *symlink;
1495 +       struct ext2fs_node *diro = node;
1496 +       int status;
1498 +       if (!diro->inode_read) {
1499 +               status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
1500 +               if (status == 0)
1501 +                       return 0;
1502 +       }
1503 +       symlink = zalloc(__le32_to_cpu(diro->inode.size) + 1);
1504 +       if (!symlink)
1505 +               return 0;
1507 +       if (__le32_to_cpu(diro->inode.size) <= 60) {
1508 +               strncpy(symlink, diro->inode.b.symlink,
1509 +                       __le32_to_cpu(diro->inode.size));
1510 +       } else {
1511 +               status = ext4fs_read_file(diro, 0,
1512 +                                         __le32_to_cpu(diro->inode.size),
1513 +                                         symlink);
1514 +               if (status == 0) {
1515 +                       free(symlink);
1516 +                       return 0;
1517 +               }
1518 +       }
1519 +       symlink[__le32_to_cpu(diro->inode.size)] = '\0';
1520 +       return symlink;
1521 +}
1523 +static int ext4fs_find_file1(const char *currpath,
1524 +                            struct ext2fs_node *currroot,
1525 +                            struct ext2fs_node **currfound, int *foundtype)
1526 +{
1527 +       char fpath[strlen(currpath) + 1];
1528 +       char *name = fpath;
1529 +       char *next;
1530 +       int status;
1531 +       int type = FILETYPE_DIRECTORY;
1532 +       struct ext2fs_node *currnode = currroot;
1533 +       struct ext2fs_node *oldnode = currroot;
1535 +       strncpy(fpath, currpath, strlen(currpath) + 1);
1537 +       /* Remove all leading slashes. */
1538 +       while (*name == '/')
1539 +               name++;
1541 +       if (!*name) {
1542 +               *currfound = currnode;
1543 +               return 1;
1544 +       }
1546 +       for (;;) {
1547 +               int found;
1549 +               /* Extract the actual part from the pathname. */
1550 +               next = strchr(name, '/');
1551 +               if (next) {
1552 +                       /* Remove all leading slashes. */
1553 +                       while (*next == '/')
1554 +                               *(next++) = '\0';
1555 +               }
1557 +               if (type != FILETYPE_DIRECTORY) {
1558 +                       ext4fs_free_node(currnode, currroot);
1559 +                       return 0;
1560 +               }
1562 +               oldnode = currnode;
1564 +               /* Iterate over the directory. */
1565 +               found = ext4fs_iterate_dir(currnode, name, &currnode, &type);
1566 +               if (found == 0)
1567 +                       return 0;
1569 +               if (found == -1)
1570 +                       break;
1572 +               /* Read in the symlink and follow it. */
1573 +               if (type == FILETYPE_SYMLINK) {
1574 +                       char *symlink;
1576 +                       /* Test if the symlink does not loop. */
1577 +                       if (++symlinknest == 8) {
1578 +                               ext4fs_free_node(currnode, currroot);
1579 +                               ext4fs_free_node(oldnode, currroot);
1580 +                               return 0;
1581 +                       }
1583 +                       symlink = ext4fs_read_symlink(currnode);
1584 +                       ext4fs_free_node(currnode, currroot);
1586 +                       if (!symlink) {
1587 +                               ext4fs_free_node(oldnode, currroot);
1588 +                               return 0;
1589 +                       }
1591 +                       debug("Got symlink >%s<\n", symlink);
1593 +                       if (symlink[0] == '/') {
1594 +                               ext4fs_free_node(oldnode, currroot);
1595 +                               oldnode = &ext4fs_root->diropen;
1596 +                       }
1598 +                       /* Lookup the node the symlink points to. */
1599 +                       status = ext4fs_find_file1(symlink, oldnode,
1600 +                                                  &currnode, &type);
1602 +                       free(symlink);
1604 +                       if (status == 0) {
1605 +                               ext4fs_free_node(oldnode, currroot);
1606 +                               return 0;
1607 +                       }
1608 +               }
1610 +               ext4fs_free_node(oldnode, currroot);
1612 +               /* Found the node! */
1613 +               if (!next || *next == '\0') {
1614 +                       *currfound = currnode;
1615 +                       *foundtype = type;
1616 +                       return 1;
1617 +               }
1618 +               name = next;
1619 +       }
1620 +       return -1;
1621 +}
1623 +int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
1624 +       struct ext2fs_node **foundnode, int expecttype)
1625 +{
1626 +       int status;
1627 +       int foundtype = FILETYPE_DIRECTORY;
1629 +       symlinknest = 0;
1630 +       if (!path)
1631 +               return 0;
1633 +       status = ext4fs_find_file1(path, rootnode, foundnode, &foundtype);
1634 +       if (status == 0)
1635 +               return 0;
1637 +       /* Check if the node that was found was of the expected type. */
1638 +       if ((expecttype == FILETYPE_REG) && (foundtype != expecttype))
1639 +               return 0;
1640 +       else if ((expecttype == FILETYPE_DIRECTORY)
1641 +                  && (foundtype != expecttype))
1642 +               return 0;
1644 +       return 1;
1645 +}
1647 +int ext4fs_open(const char *filename)
1648 +{
1649 +       struct ext2fs_node *fdiro = NULL;
1650 +       int status;
1651 +       int len;
1653 +       if (ext4fs_root == NULL)
1654 +               return -1;
1656 +       ext4fs_file = NULL;
1657 +       status = ext4fs_find_file(filename, &ext4fs_root->diropen, &fdiro,
1658 +                                 FILETYPE_REG);
1659 +       if (status == 0)
1660 +               goto fail;
1662 +       if (!fdiro->inode_read) {
1663 +               status = ext4fs_read_inode(fdiro->data, fdiro->ino,
1664 +                                          &fdiro->inode);
1665 +               if (status == 0)
1666 +                       goto fail;
1667 +       }
1668 +       len = __le32_to_cpu(fdiro->inode.size);
1669 +       ext4fs_file = fdiro;
1671 +       return len;
1672 + fail:
1673 +       ext4fs_free_node(fdiro, &ext4fs_root->diropen);
1675 +       return -1;
1676 +}
1678 +int ext4fs_mount(unsigned part_length)
1679 +{
1680 +       struct ext2_data *data;
1681 +       int status;
1682 +       struct ext_filesystem *fs = get_fs();
1683 +       data = zalloc(sizeof(struct ext2_data));
1684 +       if (!data)
1685 +               return 0;
1687 +       /* Read the superblock. */
1688 +       status = ext4fs_devread(1 * 2, 0, sizeof(struct ext2_sblock),
1689 +                               (char *)&data->sblock);
1691 +       if (status == 0)
1692 +               goto fail;
1694 +       /* Make sure this is an ext2 filesystem. */
1695 +       if (__le16_to_cpu(data->sblock.magic) != EXT2_MAGIC)
1696 +               goto fail;
1698 +       if (__le32_to_cpu(data->sblock.revision_level == 0))
1699 +               fs->inodesz = 128;
1700 +       else
1701 +               fs->inodesz = __le16_to_cpu(data->sblock.inode_size);
1703 +       debug("EXT2 rev %d, inode_size %d\n",
1704 +             __le32_to_cpu(data->sblock.revision_level), fs->inodesz);
1706 +       data->diropen.data = data;
1707 +       data->diropen.ino = 2;
1708 +       data->diropen.inode_read = 1;
1709 +       data->inode = &data->diropen.inode;
1711 +       status = ext4fs_read_inode(data, 2, data->inode);
1712 +       if (status == 0)
1713 +               goto fail;
1715 +       ext4fs_root = data;
1717 +       return 1;
1718 + fail:
1719 +       printf("Failed to mount ext2 filesystem...\n");
1720 +       free(data);
1721 +       ext4fs_root = NULL;
1723 +       return 0;
1724 +}
1725 diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h
1726 new file mode 100644
1727 index 0000000..18e6ad1
1728 --- /dev/null
1729 +++ b/fs/ext4/ext4_common.h
1730 @@ -0,0 +1,63 @@
1731 +/*
1732 + * (C) Copyright 2011 - 2012 Samsung Electronics
1733 + * EXT4 filesystem implementation in Uboot by
1734 + * Uma Shankar <uma.shankar@samsung.com>
1735 + * Manjunatha C Achar <a.manjunatha@samsung.com>
1736 + *
1737 + * ext4ls and ext4load :  based on ext2 ls load support in Uboot.
1738 + *
1739 + * (C) Copyright 2004
1740 + * esd gmbh <www.esd-electronics.com>
1741 + * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
1742 + *
1743 + * based on code from grub2 fs/ext2.c and fs/fshelp.c by
1744 + * GRUB  --  GRand Unified Bootloader
1745 + * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
1746 + *
1747 + * This program is free software; you can redistribute it and/or modify
1748 + * it under the terms of the GNU General Public License as published by
1749 + * the Free Software Foundation; either version 2 of the License, or
1750 + * (at your option) any later version.
1751 + *
1752 + * This program is distributed in the hope that it will be useful,
1753 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1754 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1755 + * GNU General Public License for more details.
1756 + *
1757 + * You should have received a copy of the GNU General Public License
1758 + * along with this program; if not, write to the Free Software
1759 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1760 + */
1762 +#ifndef __EXT4_COMMON__
1763 +#define __EXT4_COMMON__
1764 +#include <ext_common.h>
1765 +#include <ext4fs.h>
1766 +#include <malloc.h>
1767 +#include <asm/errno.h>
1769 +#define YES            1
1770 +#define NO             0
1771 +#define TRUE           1
1772 +#define FALSE          0
1773 +#define RECOVER        1
1774 +#define SCAN           0
1776 +#define S_IFLNK        0120000         /* symbolic link */
1777 +#define BLOCK_NO_ONE           1
1778 +#define SUPERBLOCK_SECTOR      2
1779 +#define SUPERBLOCK_SIZE        1024
1780 +#define F_FILE                 1
1782 +#define zalloc(size) calloc(1, size)
1784 +extern unsigned long part_offset;
1785 +int ext4fs_read_inode(struct ext2_data *data, int ino,
1786 +                     struct ext2_inode *inode);
1787 +int ext4fs_read_file(struct ext2fs_node *node, int pos,
1788 +               unsigned int len, char *buf);
1789 +int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
1790 +                       struct ext2fs_node **foundnode, int expecttype);
1791 +int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
1792 +                       struct ext2fs_node **fnode, int *ftype);
1793 +#endif
1794 diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
1795 new file mode 100644
1796 index 0000000..7933769
1797 --- /dev/null
1798 +++ b/fs/ext4/ext4fs.c
1799 @@ -0,0 +1,228 @@
1800 +/*
1801 + * (C) Copyright 2011 - 2012 Samsung Electronics
1802 + * EXT4 filesystem implementation in Uboot by
1803 + * Uma Shankar <uma.shankar@samsung.com>
1804 + * Manjunatha C Achar <a.manjunatha@samsung.com>
1805 + *
1806 + * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
1807 + *                    Ext4 read optimization taken from Open-Moko
1808 + *                    Qi bootloader
1809 + *
1810 + * (C) Copyright 2004
1811 + * esd gmbh <www.esd-electronics.com>
1812 + * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
1813 + *
1814 + * based on code from grub2 fs/ext2.c and fs/fshelp.c by
1815 + * GRUB  --  GRand Unified Bootloader
1816 + * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
1817 + *
1818 + * This program is free software; you can redistribute it and/or modify
1819 + * it under the terms of the GNU General Public License as published by
1820 + * the Free Software Foundation; either version 2 of the License, or
1821 + * (at your option) any later version.
1822 + *
1823 + * This program is distributed in the hope that it will be useful,
1824 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1825 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1826 + * GNU General Public License for more details.
1827 + *
1828 + * You should have received a copy of the GNU General Public License
1829 + * along with this program; if not, write to the Free Software
1830 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1831 + */
1833 +#include <common.h>
1834 +#include <malloc.h>
1835 +#include <ext_common.h>
1836 +#include <ext4fs.h>
1837 +#include <linux/stat.h>
1838 +#include <linux/time.h>
1839 +#include <asm/byteorder.h>
1840 +#include "ext4_common.h"
1842 +int ext4fs_symlinknest;
1843 +block_dev_desc_t *ext4_dev_desc;
1845 +struct ext_filesystem *get_fs(void)
1846 +{
1847 +       if (ext4_dev_desc == NULL || ext4_dev_desc->priv == NULL)
1848 +               printf("Invalid Input Arguments %s\n", __func__);
1850 +       return ext4_dev_desc->priv;
1851 +}
1853 +int init_fs(block_dev_desc_t *dev_desc)
1854 +{
1855 +       struct ext_filesystem *fs;
1856 +       if (dev_desc == NULL) {
1857 +               printf("Invalid Input Arguments %s\n", __func__);
1858 +               return -EINVAL;
1859 +       }
1861 +       fs = zalloc(sizeof(struct ext_filesystem));
1862 +       if (fs == NULL) {
1863 +               printf("malloc failed: %s\n", __func__);
1864 +               return -ENOMEM;
1865 +       }
1867 +       fs->dev_desc = dev_desc;
1868 +       dev_desc->priv = fs;
1870 +       return 0;
1871 +}
1873 +void deinit_fs(block_dev_desc_t *dev_desc)
1874 +{
1875 +       if (dev_desc == NULL) {
1876 +               printf("Invalid Input Arguments %s\n", __func__);
1877 +               return;
1878 +       }
1879 +       free(dev_desc->priv);
1880 +       dev_desc->priv = NULL;
1881 +}
1883 +void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot)
1884 +{
1885 +       if ((node != &ext4fs_root->diropen) && (node != currroot))
1886 +               free(node);
1887 +}
1889 +/*
1890 + * Taken from openmoko-kernel mailing list: By Andy green
1891 + * Optimized read file API : collects and defers contiguous sector
1892 + * reads into one potentially more efficient larger sequential read action
1893 + */
1894 +int ext4fs_read_file(struct ext2fs_node *node, int pos,
1895 +                    unsigned int len, char *buf)
1896 +{
1897 +       int i;
1898 +       int blockcnt;
1899 +       int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data);
1900 +       int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
1901 +       unsigned int filesize = __le32_to_cpu(node->inode.size);
1902 +       int previous_block_number = -1;
1903 +       int delayed_start = 0;
1904 +       int delayed_extent = 0;
1905 +       int delayed_skipfirst = 0;
1906 +       int delayed_next = 0;
1907 +       char *delayed_buf = NULL;
1908 +       short status;
1910 +       /* Adjust len so it we can't read past the end of the file. */
1911 +       if (len > filesize)
1912 +               len = filesize;
1914 +       blockcnt = ((len + pos) + blocksize - 1) / blocksize;
1916 +       for (i = pos / blocksize; i < blockcnt; i++) {
1917 +               int blknr;
1918 +               int blockoff = pos % blocksize;
1919 +               int blockend = blocksize;
1920 +               int skipfirst = 0;
1921 +               blknr = read_allocated_block(&(node->inode), i);
1922 +               if (blknr < 0)
1923 +                       return -1;
1925 +               blknr = blknr << log2blocksize;
1927 +               /* Last block.  */
1928 +               if (i == blockcnt - 1) {
1929 +                       blockend = (len + pos) % blocksize;
1931 +                       /* The last portion is exactly blocksize. */
1932 +                       if (!blockend)
1933 +                               blockend = blocksize;
1934 +               }
1936 +               /* First block. */
1937 +               if (i == pos / blocksize) {
1938 +                       skipfirst = blockoff;
1939 +                       blockend -= skipfirst;
1940 +               }
1941 +               if (blknr) {
1942 +                       int status;
1944 +                       if (previous_block_number != -1) {
1945 +                               if (delayed_next == blknr) {
1946 +                                       delayed_extent += blockend;
1947 +                                       delayed_next += blockend >> SECTOR_BITS;
1948 +                               } else {        /* spill */
1949 +                                       status = ext4fs_devread(delayed_start,
1950 +                                                       delayed_skipfirst,
1951 +                                                       delayed_extent,
1952 +                                                       delayed_buf);
1953 +                                       if (status == 0)
1954 +                                               return -1;
1955 +                                       previous_block_number = blknr;
1956 +                                       delayed_start = blknr;
1957 +                                       delayed_extent = blockend;
1958 +                                       delayed_skipfirst = skipfirst;
1959 +                                       delayed_buf = buf;
1960 +                                       delayed_next = blknr +
1961 +                                           (blockend >> SECTOR_BITS);
1962 +                               }
1963 +                       } else {
1964 +                               previous_block_number = blknr;
1965 +                               delayed_start = blknr;
1966 +                               delayed_extent = blockend;
1967 +                               delayed_skipfirst = skipfirst;
1968 +                               delayed_buf = buf;
1969 +                               delayed_next = blknr +
1970 +                                   (blockend >> SECTOR_BITS);
1971 +                       }
1972 +               } else {
1973 +                       if (previous_block_number != -1) {
1974 +                               /* spill */
1975 +                               status = ext4fs_devread(delayed_start,
1976 +                                                       delayed_skipfirst,
1977 +                                                       delayed_extent,
1978 +                                                       delayed_buf);
1979 +                               if (status == 0)
1980 +                                       return -1;
1981 +                               previous_block_number = -1;
1982 +                       }
1983 +                       memset(buf, 0, blocksize - skipfirst);
1984 +               }
1985 +               buf += blocksize - skipfirst;
1986 +       }
1987 +       if (previous_block_number != -1) {
1988 +               /* spill */
1989 +               status = ext4fs_devread(delayed_start,
1990 +                                       delayed_skipfirst, delayed_extent,
1991 +                                       delayed_buf);
1992 +               if (status == 0)
1993 +                       return -1;
1994 +               previous_block_number = -1;
1995 +       }
1997 +       return len;
1998 +}
2000 +int ext4fs_ls(const char *dirname)
2001 +{
2002 +       struct ext2fs_node *dirnode;
2003 +       int status;
2005 +       if (dirname == NULL)
2006 +               return 0;
2008 +       status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
2009 +                                 FILETYPE_DIRECTORY);
2010 +       if (status != 1) {
2011 +               printf("** Can not find directory. **\n");
2012 +               return 1;
2013 +       }
2015 +       ext4fs_iterate_dir(dirnode, NULL, NULL, NULL);
2016 +       ext4fs_free_node(dirnode, &ext4fs_root->diropen);
2018 +       return 0;
2019 +}
2021 +int ext4fs_read(char *buf, unsigned len)
2022 +{
2023 +       if (ext4fs_root == NULL || ext4fs_file == NULL)
2024 +               return 0;
2026 +       return ext4fs_read_file(ext4fs_file, 0, len, buf);
2027 +}
2028 diff --git a/include/ext4fs.h b/include/ext4fs.h
2029 new file mode 100644
2030 index 0000000..58a6a1d
2031 --- /dev/null
2032 +++ b/include/ext4fs.h
2033 @@ -0,0 +1,132 @@
2034 +/*
2035 + * (C) Copyright 2011 - 2012 Samsung Electronics
2036 + * EXT4 filesystem implementation in Uboot by
2037 + * Uma Shankar <uma.shankar@samsung.com>
2038 + * Manjunatha C Achar <a.manjunatha@samsung.com>
2039 + *
2040 + * Ext4 Extent data structures are taken from  original ext4 fs code
2041 + * as found in the linux kernel.
2042 + *
2043 + * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com
2044 + * Written by Alex Tomas <alex@clusterfs.com>
2045 + *
2046 + * This program is free software; you can redistribute it and/or modify
2047 + * it under the terms of the GNU General Public License version 2 as
2048 + * published by the Free Software Foundation.
2049 + *
2050 + * This program is distributed in the hope that it will be useful,
2051 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2052 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2053 + * GNU General Public License for more details.
2054 + *
2055 + * You should have received a copy of the GNU General Public License
2056 + * along with this program; if not, write to the Free Software
2057 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
2058 + */
2060 +#ifndef __EXT4__
2061 +#define __EXT4__
2062 +#include <ext_common.h>
2064 +#define EXT4_EXTENTS_FL                0x00080000 /* Inode uses extents */
2065 +#define EXT4_EXT_MAGIC                 0xf30a
2066 +#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM        0x0010
2067 +#define EXT4_FEATURE_INCOMPAT_EXTENTS  0x0040
2068 +#define EXT4_INDIRECT_BLOCKS           12
2070 +#define EXT4_BG_INODE_UNINIT           0x0001
2071 +#define EXT4_BG_BLOCK_UNINIT           0x0002
2072 +#define EXT4_BG_INODE_ZEROED           0x0004
2074 +/*
2075 + * ext4_inode has i_block array (60 bytes total).
2076 + * The first 12 bytes store ext4_extent_header;
2077 + * the remainder stores an array of ext4_extent.
2078 + */
2080 +/*
2081 + * This is the extent on-disk structure.
2082 + * It's used at the bottom of the tree.
2083 + */
2084 +struct ext4_extent {
2085 +       __le32  ee_block;       /* first logical block extent covers */
2086 +       __le16  ee_len;         /* number of blocks covered by extent */
2087 +       __le16  ee_start_hi;    /* high 16 bits of physical block */
2088 +       __le32  ee_start_lo;    /* low 32 bits of physical block */
2089 +};
2091 +/*
2092 + * This is index on-disk structure.
2093 + * It's used at all the levels except the bottom.
2094 + */
2095 +struct ext4_extent_idx {
2096 +       __le32  ei_block;       /* index covers logical blocks from 'block' */
2097 +       __le32  ei_leaf_lo;     /* pointer to the physical block of the next *
2098 +                                * level. leaf or next index could be there */
2099 +       __le16  ei_leaf_hi;     /* high 16 bits of physical block */
2100 +       __u16   ei_unused;
2101 +};
2103 +/* Each block (leaves and indexes), even inode-stored has header. */
2104 +struct ext4_extent_header {
2105 +       __le16  eh_magic;       /* probably will support different formats */
2106 +       __le16  eh_entries;     /* number of valid entries */
2107 +       __le16  eh_max;         /* capacity of store in entries */
2108 +       __le16  eh_depth;       /* has tree real underlying blocks? */
2109 +       __le32  eh_generation;  /* generation of the tree */
2110 +};
2112 +struct ext_filesystem {
2113 +       /* Total Sector of partition */
2114 +       uint64_t total_sect;
2115 +       /* Block size  of partition */
2116 +       uint32_t blksz;
2117 +       /* Inode size of partition */
2118 +       uint32_t inodesz;
2119 +       /* Sectors per Block */
2120 +       uint32_t sect_perblk;
2121 +       /* Group Descriptor Block Number */
2122 +       uint32_t gdtable_blkno;
2123 +       /* Total block groups of partition */
2124 +       uint32_t no_blkgrp;
2125 +       /* No of blocks required for bgdtable */
2126 +       uint32_t no_blk_pergdt;
2127 +       /* Superblock */
2128 +       struct ext2_sblock *sb;
2129 +       /* Block group descritpor table */
2130 +       struct ext2_block_group *gd;
2131 +       char *gdtable;
2133 +       /* Block Bitmap Related */
2134 +       unsigned char **blk_bmaps;
2135 +       long int curr_blkno;
2136 +       uint16_t first_pass_bbmap;
2138 +       /* Inode Bitmap Related */
2139 +       unsigned char **inode_bmaps;
2140 +       int curr_inode_no;
2141 +       uint16_t first_pass_ibmap;
2143 +       /* Journal Related */
2145 +       /* Block Device Descriptor */
2146 +       block_dev_desc_t *dev_desc;
2147 +};
2149 +extern block_dev_desc_t *ext4_dev_desc;
2150 +extern struct ext2_data *ext4fs_root;
2151 +extern struct ext2fs_node *ext4fs_file;
2153 +struct ext_filesystem *get_fs(void);
2154 +int init_fs(block_dev_desc_t *dev_desc);
2155 +void deinit_fs(block_dev_desc_t *dev_desc);
2156 +int ext4fs_open(const char *filename);
2157 +int ext4fs_read(char *buf, unsigned len);
2158 +int ext4fs_mount(unsigned part_length);
2159 +void ext4fs_close(void);
2160 +int ext4fs_ls(const char *dirname);
2161 +void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot);
2162 +int ext4fs_devread(int sector, int byte_offset, int byte_len, char *buf);
2163 +int ext4fs_set_blk_dev(block_dev_desc_t *rbdd, int part);
2164 +long int read_allocated_block(struct ext2_inode *inode, int fileblock);
2165 +#endif
2166 diff --git a/include/ext_common.h b/include/ext_common.h
2167 new file mode 100644
2168 index 0000000..5d48021
2169 --- /dev/null
2170 +++ b/include/ext_common.h
2171 @@ -0,0 +1,188 @@
2172 +/*
2173 + * (C) Copyright 2011 - 2012 Samsung Electronics
2174 + * EXT4 filesystem implementation in Uboot by
2175 + * Uma Shankar <uma.shankar@samsung.com>
2176 + * Manjunatha C Achar <a.manjunatha@samsung.com>
2177 + *
2178 + * Data structures and headers for ext4 support have been taken from
2179 + * ext2 ls load support in Uboot
2180 + *
2181 + * (C) Copyright 2004
2182 + * esd gmbh <www.esd-electronics.com>
2183 + * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
2184 + *
2185 + * based on code from grub2 fs/ext2.c and fs/fshelp.c by
2186 + * GRUB  --  GRand Unified Bootloader
2187 + * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
2188 + *
2189 + * This program is free software; you can redistribute it and/or modify
2190 + * it under the terms of the GNU General Public License as published by
2191 + * the Free Software Foundation; either version 2 of the License, or
2192 + * (at your option) any later version.
2193 + *
2194 + * This program is distributed in the hope that it will be useful,
2195 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2196 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2197 + * GNU General Public License for more details.
2198 + *
2199 + * You should have received a copy of the GNU General Public License
2200 + * along with this program; if not, write to the Free Software
2201 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
2202 + */
2204 +#ifndef __EXT_COMMON__
2205 +#define __EXT_COMMON__
2207 +#define SECTOR_SIZE            0x200
2208 +#define SECTOR_BITS            9
2210 +/* Magic value used to identify an ext2 filesystem.  */
2211 +#define        EXT2_MAGIC              0xEF53
2212 +/* Amount of indirect blocks in an inode.  */
2213 +#define INDIRECT_BLOCKS                12
2214 +/* Maximum lenght of a pathname.  */
2215 +#define EXT2_PATH_MAX                  4096
2216 +/* Maximum nesting of symlinks, used to prevent a loop.  */
2217 +#define        EXT2_MAX_SYMLINKCNT             8
2219 +/* Filetype used in directory entry.  */
2220 +#define        FILETYPE_UNKNOWN                0
2221 +#define        FILETYPE_REG                    1
2222 +#define        FILETYPE_DIRECTORY              2
2223 +#define        FILETYPE_SYMLINK                7
2225 +/* Filetype information as used in inodes.  */
2226 +#define FILETYPE_INO_MASK              0170000
2227 +#define FILETYPE_INO_REG               0100000
2228 +#define FILETYPE_INO_DIRECTORY         0040000
2229 +#define FILETYPE_INO_SYMLINK           0120000
2230 +#define EXT2_ROOT_INO                  2 /* Root inode */
2232 +/* Bits used as offset in sector */
2233 +#define DISK_SECTOR_BITS               9
2234 +/* The size of an ext2 block in bytes.  */
2235 +#define EXT2_BLOCK_SIZE(data)     (1 << LOG2_BLOCK_SIZE(data))
2237 +/* Log2 size of ext2 block in 512 blocks.  */
2238 +#define LOG2_EXT2_BLOCK_SIZE(data) (__le32_to_cpu \
2239 +                               (data->sblock.log2_block_size) + 1)
2241 +/* Log2 size of ext2 block in bytes.  */
2242 +#define LOG2_BLOCK_SIZE(data)     (__le32_to_cpu \
2243 +               (data->sblock.log2_block_size) + 10)
2244 +#define INODE_SIZE_FILESYSTEM(data)    (__le32_to_cpu \
2245 +                       (data->sblock.inode_size))
2247 +#define EXT2_FT_DIR    2
2248 +#define SUCCESS        1
2250 +/* Macro-instructions used to manage several block sizes  */
2251 +#define EXT2_MIN_BLOCK_LOG_SIZE        10 /* 1024 */
2252 +#define EXT2_MAX_BLOCK_LOG_SIZE        16 /* 65536 */
2253 +#define EXT2_MIN_BLOCK_SIZE            (1 << EXT2_MIN_BLOCK_LOG_SIZE)
2254 +#define EXT2_MAX_BLOCK_SIZE            (1 << EXT2_MAX_BLOCK_LOG_SIZE)
2256 +/* The ext2 superblock.  */
2257 +struct ext2_sblock {
2258 +       uint32_t total_inodes;
2259 +       uint32_t total_blocks;
2260 +       uint32_t reserved_blocks;
2261 +       uint32_t free_blocks;
2262 +       uint32_t free_inodes;
2263 +       uint32_t first_data_block;
2264 +       uint32_t log2_block_size;
2265 +       uint32_t log2_fragment_size;
2266 +       uint32_t blocks_per_group;
2267 +       uint32_t fragments_per_group;
2268 +       uint32_t inodes_per_group;
2269 +       uint32_t mtime;
2270 +       uint32_t utime;
2271 +       uint16_t mnt_count;
2272 +       uint16_t max_mnt_count;
2273 +       uint16_t magic;
2274 +       uint16_t fs_state;
2275 +       uint16_t error_handling;
2276 +       uint16_t minor_revision_level;
2277 +       uint32_t lastcheck;
2278 +       uint32_t checkinterval;
2279 +       uint32_t creator_os;
2280 +       uint32_t revision_level;
2281 +       uint16_t uid_reserved;
2282 +       uint16_t gid_reserved;
2283 +       uint32_t first_inode;
2284 +       uint16_t inode_size;
2285 +       uint16_t block_group_number;
2286 +       uint32_t feature_compatibility;
2287 +       uint32_t feature_incompat;
2288 +       uint32_t feature_ro_compat;
2289 +       uint32_t unique_id[4];
2290 +       char volume_name[16];
2291 +       char last_mounted_on[64];
2292 +       uint32_t compression_info;
2293 +};
2295 +struct ext2_block_group {
2296 +       __u32 block_id; /* Blocks bitmap block */
2297 +       __u32 inode_id; /* Inodes bitmap block */
2298 +       __u32 inode_table_id;   /* Inodes table block */
2299 +       __u16 free_blocks;      /* Free blocks count */
2300 +       __u16 free_inodes;      /* Free inodes count */
2301 +       __u16 used_dir_cnt;     /* Directories count */
2302 +       __u16 bg_flags;
2303 +       __u32 bg_reserved[2];
2304 +       __u16 bg_itable_unused; /* Unused inodes count */
2305 +       __u16 bg_checksum;      /* crc16(s_uuid+grouo_num+group_desc)*/
2306 +};
2308 +/* The ext2 inode. */
2309 +struct ext2_inode {
2310 +       uint16_t mode;
2311 +       uint16_t uid;
2312 +       uint32_t size;
2313 +       uint32_t atime;
2314 +       uint32_t ctime;
2315 +       uint32_t mtime;
2316 +       uint32_t dtime;
2317 +       uint16_t gid;
2318 +       uint16_t nlinks;
2319 +       uint32_t blockcnt;      /* Blocks of 512 bytes!! */
2320 +       uint32_t flags;
2321 +       uint32_t osd1;
2322 +       union {
2323 +               struct datablocks {
2324 +                       uint32_t dir_blocks[INDIRECT_BLOCKS];
2325 +                       uint32_t indir_block;
2326 +                       uint32_t double_indir_block;
2327 +                       uint32_t triple_indir_block;
2328 +               } blocks;
2329 +               char symlink[60];
2330 +       } b;
2331 +       uint32_t version;
2332 +       uint32_t acl;
2333 +       uint32_t dir_acl;
2334 +       uint32_t fragment_addr;
2335 +       uint32_t osd2[3];
2336 +};
2338 +/* The header of an ext2 directory entry. */
2339 +struct ext2_dirent {
2340 +       uint32_t inode;
2341 +       uint16_t direntlen;
2342 +       uint8_t namelen;
2343 +       uint8_t filetype;
2344 +};
2346 +struct ext2fs_node {
2347 +       struct ext2_data *data;
2348 +       struct ext2_inode inode;
2349 +       int ino;
2350 +       int inode_read;
2351 +};
2353 +/* Information about a "mounted" ext2 filesystem. */
2354 +struct ext2_data {
2355 +       struct ext2_sblock sblock;
2356 +       struct ext2_inode *inode;
2357 +       struct ext2fs_node diropen;
2358 +};
2359 +#endif
2360 -- 
2361 1.7.10