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