1*a1596438SUma Shankar /* 2*a1596438SUma Shankar * (C) Copyright 2011 - 2012 Samsung Electronics 3*a1596438SUma Shankar * EXT4 filesystem implementation in Uboot by 4*a1596438SUma Shankar * Uma Shankar <uma.shankar@samsung.com> 5*a1596438SUma Shankar * Manjunatha C Achar <a.manjunatha@samsung.com> 6*a1596438SUma Shankar * 7*a1596438SUma Shankar * ext4ls and ext4load : Based on ext2 ls and load support in Uboot. 8*a1596438SUma Shankar * Ext4 read optimization taken from Open-Moko 9*a1596438SUma Shankar * Qi bootloader 10*a1596438SUma Shankar * 11*a1596438SUma Shankar * (C) Copyright 2004 12*a1596438SUma Shankar * esd gmbh <www.esd-electronics.com> 13*a1596438SUma Shankar * Reinhard Arlt <reinhard.arlt@esd-electronics.com> 14*a1596438SUma Shankar * 15*a1596438SUma Shankar * based on code from grub2 fs/ext2.c and fs/fshelp.c by 16*a1596438SUma Shankar * GRUB -- GRand Unified Bootloader 17*a1596438SUma Shankar * Copyright (C) 2003, 2004 Free Software Foundation, Inc. 18*a1596438SUma Shankar * 19*a1596438SUma Shankar * This program is free software; you can redistribute it and/or modify 20*a1596438SUma Shankar * it under the terms of the GNU General Public License as published by 21*a1596438SUma Shankar * the Free Software Foundation; either version 2 of the License, or 22*a1596438SUma Shankar * (at your option) any later version. 23*a1596438SUma Shankar * 24*a1596438SUma Shankar * This program is distributed in the hope that it will be useful, 25*a1596438SUma Shankar * but WITHOUT ANY WARRANTY; without even the implied warranty of 26*a1596438SUma Shankar * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27*a1596438SUma Shankar * GNU General Public License for more details. 28*a1596438SUma Shankar * 29*a1596438SUma Shankar * You should have received a copy of the GNU General Public License 30*a1596438SUma Shankar * along with this program; if not, write to the Free Software 31*a1596438SUma Shankar * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 32*a1596438SUma Shankar */ 33*a1596438SUma Shankar 34*a1596438SUma Shankar #include <common.h> 35*a1596438SUma Shankar #include <malloc.h> 36*a1596438SUma Shankar #include <ext_common.h> 37*a1596438SUma Shankar #include <ext4fs.h> 38*a1596438SUma Shankar #include <linux/stat.h> 39*a1596438SUma Shankar #include <linux/time.h> 40*a1596438SUma Shankar #include <asm/byteorder.h> 41*a1596438SUma Shankar #include "ext4_common.h" 42*a1596438SUma Shankar 43*a1596438SUma Shankar int ext4fs_symlinknest; 44*a1596438SUma Shankar block_dev_desc_t *ext4_dev_desc; 45*a1596438SUma Shankar 46*a1596438SUma Shankar struct ext_filesystem *get_fs(void) 47*a1596438SUma Shankar { 48*a1596438SUma Shankar if (ext4_dev_desc == NULL || ext4_dev_desc->priv == NULL) 49*a1596438SUma Shankar printf("Invalid Input Arguments %s\n", __func__); 50*a1596438SUma Shankar 51*a1596438SUma Shankar return ext4_dev_desc->priv; 52*a1596438SUma Shankar } 53*a1596438SUma Shankar 54*a1596438SUma Shankar int init_fs(block_dev_desc_t *dev_desc) 55*a1596438SUma Shankar { 56*a1596438SUma Shankar struct ext_filesystem *fs; 57*a1596438SUma Shankar if (dev_desc == NULL) { 58*a1596438SUma Shankar printf("Invalid Input Arguments %s\n", __func__); 59*a1596438SUma Shankar return -EINVAL; 60*a1596438SUma Shankar } 61*a1596438SUma Shankar 62*a1596438SUma Shankar fs = zalloc(sizeof(struct ext_filesystem)); 63*a1596438SUma Shankar if (fs == NULL) { 64*a1596438SUma Shankar printf("malloc failed: %s\n", __func__); 65*a1596438SUma Shankar return -ENOMEM; 66*a1596438SUma Shankar } 67*a1596438SUma Shankar 68*a1596438SUma Shankar fs->dev_desc = dev_desc; 69*a1596438SUma Shankar dev_desc->priv = fs; 70*a1596438SUma Shankar 71*a1596438SUma Shankar return 0; 72*a1596438SUma Shankar } 73*a1596438SUma Shankar 74*a1596438SUma Shankar void deinit_fs(block_dev_desc_t *dev_desc) 75*a1596438SUma Shankar { 76*a1596438SUma Shankar if (dev_desc == NULL) { 77*a1596438SUma Shankar printf("Invalid Input Arguments %s\n", __func__); 78*a1596438SUma Shankar return; 79*a1596438SUma Shankar } 80*a1596438SUma Shankar free(dev_desc->priv); 81*a1596438SUma Shankar dev_desc->priv = NULL; 82*a1596438SUma Shankar } 83*a1596438SUma Shankar 84*a1596438SUma Shankar void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot) 85*a1596438SUma Shankar { 86*a1596438SUma Shankar if ((node != &ext4fs_root->diropen) && (node != currroot)) 87*a1596438SUma Shankar free(node); 88*a1596438SUma Shankar } 89*a1596438SUma Shankar 90*a1596438SUma Shankar /* 91*a1596438SUma Shankar * Taken from openmoko-kernel mailing list: By Andy green 92*a1596438SUma Shankar * Optimized read file API : collects and defers contiguous sector 93*a1596438SUma Shankar * reads into one potentially more efficient larger sequential read action 94*a1596438SUma Shankar */ 95*a1596438SUma Shankar int ext4fs_read_file(struct ext2fs_node *node, int pos, 96*a1596438SUma Shankar unsigned int len, char *buf) 97*a1596438SUma Shankar { 98*a1596438SUma Shankar int i; 99*a1596438SUma Shankar int blockcnt; 100*a1596438SUma Shankar int log2blocksize = LOG2_EXT2_BLOCK_SIZE(node->data); 101*a1596438SUma Shankar int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS); 102*a1596438SUma Shankar unsigned int filesize = __le32_to_cpu(node->inode.size); 103*a1596438SUma Shankar int previous_block_number = -1; 104*a1596438SUma Shankar int delayed_start = 0; 105*a1596438SUma Shankar int delayed_extent = 0; 106*a1596438SUma Shankar int delayed_skipfirst = 0; 107*a1596438SUma Shankar int delayed_next = 0; 108*a1596438SUma Shankar char *delayed_buf = NULL; 109*a1596438SUma Shankar short status; 110*a1596438SUma Shankar 111*a1596438SUma Shankar /* Adjust len so it we can't read past the end of the file. */ 112*a1596438SUma Shankar if (len > filesize) 113*a1596438SUma Shankar len = filesize; 114*a1596438SUma Shankar 115*a1596438SUma Shankar blockcnt = ((len + pos) + blocksize - 1) / blocksize; 116*a1596438SUma Shankar 117*a1596438SUma Shankar for (i = pos / blocksize; i < blockcnt; i++) { 118*a1596438SUma Shankar int blknr; 119*a1596438SUma Shankar int blockoff = pos % blocksize; 120*a1596438SUma Shankar int blockend = blocksize; 121*a1596438SUma Shankar int skipfirst = 0; 122*a1596438SUma Shankar blknr = read_allocated_block(&(node->inode), i); 123*a1596438SUma Shankar if (blknr < 0) 124*a1596438SUma Shankar return -1; 125*a1596438SUma Shankar 126*a1596438SUma Shankar blknr = blknr << log2blocksize; 127*a1596438SUma Shankar 128*a1596438SUma Shankar /* Last block. */ 129*a1596438SUma Shankar if (i == blockcnt - 1) { 130*a1596438SUma Shankar blockend = (len + pos) % blocksize; 131*a1596438SUma Shankar 132*a1596438SUma Shankar /* The last portion is exactly blocksize. */ 133*a1596438SUma Shankar if (!blockend) 134*a1596438SUma Shankar blockend = blocksize; 135*a1596438SUma Shankar } 136*a1596438SUma Shankar 137*a1596438SUma Shankar /* First block. */ 138*a1596438SUma Shankar if (i == pos / blocksize) { 139*a1596438SUma Shankar skipfirst = blockoff; 140*a1596438SUma Shankar blockend -= skipfirst; 141*a1596438SUma Shankar } 142*a1596438SUma Shankar if (blknr) { 143*a1596438SUma Shankar int status; 144*a1596438SUma Shankar 145*a1596438SUma Shankar if (previous_block_number != -1) { 146*a1596438SUma Shankar if (delayed_next == blknr) { 147*a1596438SUma Shankar delayed_extent += blockend; 148*a1596438SUma Shankar delayed_next += blockend >> SECTOR_BITS; 149*a1596438SUma Shankar } else { /* spill */ 150*a1596438SUma Shankar status = ext4fs_devread(delayed_start, 151*a1596438SUma Shankar delayed_skipfirst, 152*a1596438SUma Shankar delayed_extent, 153*a1596438SUma Shankar delayed_buf); 154*a1596438SUma Shankar if (status == 0) 155*a1596438SUma Shankar return -1; 156*a1596438SUma Shankar previous_block_number = blknr; 157*a1596438SUma Shankar delayed_start = blknr; 158*a1596438SUma Shankar delayed_extent = blockend; 159*a1596438SUma Shankar delayed_skipfirst = skipfirst; 160*a1596438SUma Shankar delayed_buf = buf; 161*a1596438SUma Shankar delayed_next = blknr + 162*a1596438SUma Shankar (blockend >> SECTOR_BITS); 163*a1596438SUma Shankar } 164*a1596438SUma Shankar } else { 165*a1596438SUma Shankar previous_block_number = blknr; 166*a1596438SUma Shankar delayed_start = blknr; 167*a1596438SUma Shankar delayed_extent = blockend; 168*a1596438SUma Shankar delayed_skipfirst = skipfirst; 169*a1596438SUma Shankar delayed_buf = buf; 170*a1596438SUma Shankar delayed_next = blknr + 171*a1596438SUma Shankar (blockend >> SECTOR_BITS); 172*a1596438SUma Shankar } 173*a1596438SUma Shankar } else { 174*a1596438SUma Shankar if (previous_block_number != -1) { 175*a1596438SUma Shankar /* spill */ 176*a1596438SUma Shankar status = ext4fs_devread(delayed_start, 177*a1596438SUma Shankar delayed_skipfirst, 178*a1596438SUma Shankar delayed_extent, 179*a1596438SUma Shankar delayed_buf); 180*a1596438SUma Shankar if (status == 0) 181*a1596438SUma Shankar return -1; 182*a1596438SUma Shankar previous_block_number = -1; 183*a1596438SUma Shankar } 184*a1596438SUma Shankar memset(buf, 0, blocksize - skipfirst); 185*a1596438SUma Shankar } 186*a1596438SUma Shankar buf += blocksize - skipfirst; 187*a1596438SUma Shankar } 188*a1596438SUma Shankar if (previous_block_number != -1) { 189*a1596438SUma Shankar /* spill */ 190*a1596438SUma Shankar status = ext4fs_devread(delayed_start, 191*a1596438SUma Shankar delayed_skipfirst, delayed_extent, 192*a1596438SUma Shankar delayed_buf); 193*a1596438SUma Shankar if (status == 0) 194*a1596438SUma Shankar return -1; 195*a1596438SUma Shankar previous_block_number = -1; 196*a1596438SUma Shankar } 197*a1596438SUma Shankar 198*a1596438SUma Shankar return len; 199*a1596438SUma Shankar } 200*a1596438SUma Shankar 201*a1596438SUma Shankar int ext4fs_ls(const char *dirname) 202*a1596438SUma Shankar { 203*a1596438SUma Shankar struct ext2fs_node *dirnode; 204*a1596438SUma Shankar int status; 205*a1596438SUma Shankar 206*a1596438SUma Shankar if (dirname == NULL) 207*a1596438SUma Shankar return 0; 208*a1596438SUma Shankar 209*a1596438SUma Shankar status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode, 210*a1596438SUma Shankar FILETYPE_DIRECTORY); 211*a1596438SUma Shankar if (status != 1) { 212*a1596438SUma Shankar printf("** Can not find directory. **\n"); 213*a1596438SUma Shankar return 1; 214*a1596438SUma Shankar } 215*a1596438SUma Shankar 216*a1596438SUma Shankar ext4fs_iterate_dir(dirnode, NULL, NULL, NULL); 217*a1596438SUma Shankar ext4fs_free_node(dirnode, &ext4fs_root->diropen); 218*a1596438SUma Shankar 219*a1596438SUma Shankar return 0; 220*a1596438SUma Shankar } 221*a1596438SUma Shankar 222*a1596438SUma Shankar int ext4fs_read(char *buf, unsigned len) 223*a1596438SUma Shankar { 224*a1596438SUma Shankar if (ext4fs_root == NULL || ext4fs_file == NULL) 225*a1596438SUma Shankar return 0; 226*a1596438SUma Shankar 227*a1596438SUma Shankar return ext4fs_read_file(ext4fs_file, 0, len, buf); 228*a1596438SUma Shankar } 229