X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=fs%2Fjffs2%2Fjffs2_1pass.c;h=0177268c3cee762862f2ca98f842aefc67550982;hb=6d0f6bcf337c5261c08fabe12982178c2c489d76;hp=0f2907183732ec30654921aaf90407818c58bfe6;hpb=e6f2e902334d5ee65bab9cf8292cf668243531e9;p=platform%2Fkernel%2Fu-boot.git diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 0f29071..0177268 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -52,7 +52,7 @@ * for a bootloader as small and simple as possible. Instead of worring about * unneccesary data copies, node scans, etc, I just optimized for the known * common case, a kernel, which looks like: - * (1) most pages are 4096 bytes + * (1) most pages are 4096 bytes * (2) version numbers are somewhat sorted in acsending order * (3) multiple compressed blocks making up one page is uncommon * @@ -92,7 +92,7 @@ * - implemented fragment sorting to ensure that the newest data is copied * if there are multiple copies of fragments for a certain file offset. * - * The fragment sorting feature must be enabled by CFG_JFFS2_SORT_FRAGMENTS. + * The fragment sorting feature must be enabled by CONFIG_SYS_JFFS2_SORT_FRAGMENTS. * Sorting is done while adding fragments to the lists, which is more or less a * bubble sort. This takes a lot of time, and is most probably not an issue if * the boot filesystem is always mounted readonly. @@ -116,22 +116,20 @@ #include #include #include - -#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) - +#include #include #include #include "jffs2_private.h" -#define NODE_CHUNK 1024 /* size of memory allocation chunk in b_nodes */ -#define SPIN_BLKSIZE 18 /* spin after having scanned 1< +#else +#include +#endif /* * Support for jffs2 on top of NAND-flash * @@ -154,9 +158,11 @@ static struct part_info *current_part; * */ -/* this one defined in cmd_nand.c */ +#if defined(CONFIG_NAND_LEGACY) +/* this one defined in nand_legacy.c */ int read_jffs2_nand(size_t start, size_t len, - size_t * retlen, u_char * buf, int nanddev); + size_t * retlen, u_char * buf, int nanddev); +#endif #define NAND_PAGE_SIZE 512 #define NAND_PAGE_SHIFT 9 @@ -191,6 +197,8 @@ static int read_nand_cached(u32 off, u32 size, u_char *buf) return -1; } } + +#if defined(CONFIG_NAND_LEGACY) if (read_jffs2_nand(nand_cache_off, NAND_CACHE_SIZE, &retlen, nand_cache, id->num) < 0 || retlen != NAND_CACHE_SIZE) { @@ -198,6 +206,16 @@ static int read_nand_cached(u32 off, u32 size, u_char *buf) nand_cache_off, NAND_CACHE_SIZE); return -1; } +#else + retlen = NAND_CACHE_SIZE; + if (nand_read(&nand_info[id->num], nand_cache_off, + &retlen, nand_cache) != 0 || + retlen != NAND_CACHE_SIZE) { + printf("read_nand_cached: error reading nand off %#x size %d bytes\n", + nand_cache_off, NAND_CACHE_SIZE); + return -1; + } +#endif } cpy_bytes = nand_cache_off + NAND_CACHE_SIZE - (off + bytes_read); if (cpy_bytes > size - bytes_read) @@ -248,10 +266,111 @@ static void put_fl_mem_nand(void *buf) { free(buf); } -#endif /* #if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) */ +#endif + +#if defined(CONFIG_CMD_ONENAND) + +#include +#include +#include + +#define ONENAND_PAGE_SIZE 2048 +#define ONENAND_PAGE_SHIFT 11 +#define ONENAND_PAGE_MASK (~(ONENAND_PAGE_SIZE-1)) + +#ifndef ONENAND_CACHE_PAGES +#define ONENAND_CACHE_PAGES 4 +#endif +#define ONENAND_CACHE_SIZE (ONENAND_CACHE_PAGES*ONENAND_PAGE_SIZE) + +static u8* onenand_cache; +static u32 onenand_cache_off = (u32)-1; + +static int read_onenand_cached(u32 off, u32 size, u_char *buf) +{ + u32 bytes_read = 0; + size_t retlen; + int cpy_bytes; + + while (bytes_read < size) { + if ((off + bytes_read < onenand_cache_off) || + (off + bytes_read >= onenand_cache_off + ONENAND_CACHE_SIZE)) { + onenand_cache_off = (off + bytes_read) & ONENAND_PAGE_MASK; + if (!onenand_cache) { + /* This memory never gets freed but 'cause + it's a bootloader, nobody cares */ + onenand_cache = malloc(ONENAND_CACHE_SIZE); + if (!onenand_cache) { + printf("read_onenand_cached: can't alloc cache size %d bytes\n", + ONENAND_CACHE_SIZE); + return -1; + } + } + + retlen = ONENAND_CACHE_SIZE; + if (onenand_read(&onenand_mtd, onenand_cache_off, retlen, + &retlen, onenand_cache) != 0 || + retlen != ONENAND_CACHE_SIZE) { + printf("read_onenand_cached: error reading nand off %#x size %d bytes\n", + onenand_cache_off, ONENAND_CACHE_SIZE); + return -1; + } + } + cpy_bytes = onenand_cache_off + ONENAND_CACHE_SIZE - (off + bytes_read); + if (cpy_bytes > size - bytes_read) + cpy_bytes = size - bytes_read; + memcpy(buf + bytes_read, + onenand_cache + off + bytes_read - onenand_cache_off, + cpy_bytes); + bytes_read += cpy_bytes; + } + return bytes_read; +} + +static void *get_fl_mem_onenand(u32 off, u32 size, void *ext_buf) +{ + u_char *buf = ext_buf ? (u_char *)ext_buf : (u_char *)malloc(size); + + if (NULL == buf) { + printf("get_fl_mem_onenand: can't alloc %d bytes\n", size); + return NULL; + } + if (read_onenand_cached(off, size, buf) < 0) { + if (!ext_buf) + free(buf); + return NULL; + } + + return buf; +} + +static void *get_node_mem_onenand(u32 off) +{ + struct jffs2_unknown_node node; + void *ret = NULL; + + if (NULL == get_fl_mem_onenand(off, sizeof(node), &node)) + return NULL; + + ret = get_fl_mem_onenand(off, node.magic == + JFFS2_MAGIC_BITMASK ? node.totlen : sizeof(node), + NULL); + if (!ret) { + printf("off = %#x magic %#x type %#x node.totlen = %d\n", + off, node.magic, node.nodetype, node.totlen); + } + return ret; +} + + +static void put_fl_mem_onenand(void *buf) +{ + free(buf); +} +#endif -#if (CONFIG_COMMANDS & CFG_CMD_FLASH) +#if defined(CONFIG_CMD_FLASH) /* * Support for jffs2 on top of NOR-flash * @@ -274,7 +393,7 @@ static inline void *get_node_mem_nor(u32 off) { return (void*)get_fl_mem_nor(off); } -#endif /* #if (CONFIG_COMMANDS & CFG_CMD_FLASH) */ +#endif /* @@ -285,16 +404,21 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf) { struct mtdids *id = current_part->dev->id; -#if (CONFIG_COMMANDS & CFG_CMD_FLASH) +#if defined(CONFIG_CMD_FLASH) if (id->type == MTD_DEV_TYPE_NOR) return get_fl_mem_nor(off); #endif -#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) +#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND) if (id->type == MTD_DEV_TYPE_NAND) return get_fl_mem_nand(off, size, ext_buf); #endif +#if defined(CONFIG_CMD_ONENAND) + if (id->type == MTD_DEV_TYPE_ONENAND) + return get_fl_mem_onenand(off, size, ext_buf); +#endif + printf("get_fl_mem: unknown device type, using raw offset!\n"); return (void*)off; } @@ -303,28 +427,42 @@ static inline void *get_node_mem(u32 off) { struct mtdids *id = current_part->dev->id; -#if (CONFIG_COMMANDS & CFG_CMD_FLASH) +#if defined(CONFIG_CMD_FLASH) if (id->type == MTD_DEV_TYPE_NOR) return get_node_mem_nor(off); #endif -#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) +#if defined(CONFIG_JFFS2_NAND) && \ + defined(CONFIG_CMD_NAND) if (id->type == MTD_DEV_TYPE_NAND) return get_node_mem_nand(off); #endif +#if defined(CONFIG_CMD_ONENAND) + if (id->type == MTD_DEV_TYPE_ONENAND) + return get_node_mem_onenand(off); +#endif + printf("get_node_mem: unknown device type, using raw offset!\n"); return (void*)off; } static inline void put_fl_mem(void *buf) { -#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) +#if defined(CONFIG_JFFS2_NAND) && \ + defined(CONFIG_CMD_NAND) struct mtdids *id = current_part->dev->id; if (id->type == MTD_DEV_TYPE_NAND) return put_fl_mem_nand(buf); #endif + +#if defined(CONFIG_CMD_ONENAND) + struct mtdids *id = current_part->dev->id; + + if (id->type == MTD_DEV_TYPE_ONENAND) + return put_fl_mem_onenand(buf); +#endif } /* Compression names */ @@ -406,7 +544,7 @@ static struct b_node * insert_node(struct b_list *list, u32 offset) { struct b_node *new; -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS struct b_node *b, *prev; #endif @@ -416,7 +554,7 @@ insert_node(struct b_list *list, u32 offset) } new->offset = offset; -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS if (list->listTail != NULL && list->listCompare(new, list->listTail)) prev = list->listTail; else if (list->listLast != NULL && list->listCompare(new, list->listLast)) @@ -453,7 +591,7 @@ insert_node(struct b_list *list, u32 offset) return new; } -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS /* Sort data entries with the latest version last, so that if there * is overlapping data the latest version will be used. */ @@ -496,7 +634,7 @@ static int compare_dirents(struct b_node *new, struct b_node *old) /* length is also the same, so use ascending sort by name */ - cmp = strncmp(jNew->name, jOld->name, jNew->nsize); + cmp = strncmp((char *)jNew->name, (char *)jOld->name, jNew->nsize); if (cmp != 0) return cmp > 0; @@ -556,7 +694,7 @@ jffs_init_1pass_list(struct part_info *part) pL = (struct b_lists *)part->jffs2_priv; memset(pL, 0, sizeof(*pL)); -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS pL->dir.listCompare = compare_dirents; pL->frag.listCompare = compare_inodes; #endif @@ -572,12 +710,12 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) struct jffs2_raw_inode *jNode; u32 totalSize = 0; u32 latestVersion = 0; - char *lDest; - char *src; + uchar *lDest; + uchar *src; long ret; int i; u32 counter = 0; -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS /* Find file size before loading any data, so fragments that * start past the end of file can be ignored. A fragment * that is partially in the file is loaded, so extra data may @@ -615,7 +753,7 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) putLabeledWord("read_inode: flags = ", jNode->flags); #endif -#ifndef CFG_JFFS2_SORT_FRAGMENTS +#ifndef CONFIG_SYS_JFFS2_SORT_FRAGMENTS /* get actual file length from the newest node */ if (jNode->version >= latestVersion) { totalSize = jNode->isize; @@ -624,14 +762,14 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) #endif if(dest) { - src = ((char *) jNode) + sizeof(struct jffs2_raw_inode); + src = ((uchar *) jNode) + sizeof(struct jffs2_raw_inode); /* ignore data behind latest known EOF */ if (jNode->offset > totalSize) { put_fl_mem(jNode); continue; } - lDest = (char *) (dest + jNode->offset); + lDest = (uchar *) (dest + jNode->offset); #if 0 putLabeledWord("read_inode: src = ", src); putLabeledWord("read_inode: dest = ", lDest); @@ -709,14 +847,14 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino) jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset); if ((pino == jDir->pino) && (len == jDir->nsize) && (jDir->ino) && /* 0 for unlink */ - (!strncmp(jDir->name, name, len))) { /* a match */ + (!strncmp((char *)jDir->name, name, len))) { /* a match */ if (jDir->version < version) { put_fl_mem(jDir); continue; } if (jDir->version == version && inode != 0) { - /* I'm pretty sure this isn't legal */ + /* I'm pretty sure this isn't legal */ putstr(" ** ERROR ** "); putnstr(jDir->name, jDir->nsize); putLabeledWord(" has dup version =", version); @@ -776,7 +914,7 @@ static inline void dump_stat(struct stat *st, const char *name) if (st->st_mtime == (time_t)(-1)) /* some ctimes really hate -1 */ st->st_mtime = 1; - ctime_r(&st->st_mtime, s/*,64*/); /* newlib ctime doesn't have buflen */ + ctime_r((time_t *)&st->st_mtime, s/*,64*/); /* newlib ctime doesn't have buflen */ if ((p = strchr(s,'\n')) != NULL) *p = '\0'; if ((p = strchr(s,'\r')) != NULL) *p = '\0'; @@ -796,7 +934,7 @@ static inline u32 dump_inode(struct b_lists * pL, struct jffs2_raw_dirent *d, st if(!d || !i) return -1; - strncpy(fname, d->name, d->nsize); + strncpy(fname, (char *)d->name, d->nsize); fname[d->nsize] = '\0'; memset(&st,0,sizeof(st)); @@ -934,13 +1072,13 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino) for(b = pL->dir.listHead; b; b = b->next) { jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset); if (ino == jDir->ino) { - if (jDir->version < version) { + if (jDir->version < version) { put_fl_mem(jDir); continue; } if (jDir->version == version && jDirFoundType) { - /* I'm pretty sure this isn't legal */ + /* I'm pretty sure this isn't legal */ putstr(" ** ERROR ** "); putnstr(jDir->name, jDir->nsize); putLabeledWord(" has dup version (resolve) = ", @@ -971,7 +1109,7 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino) putnstr(src, jNode->dsize); putstr("\r\n"); #endif - strncpy(tmp, src, jNode->dsize); + strncpy(tmp, (char *)src, jNode->dsize); tmp[jNode->dsize] = '\0'; put_fl_mem(jNode); break; @@ -1126,7 +1264,7 @@ dump_dirents(struct b_lists *pL) putLabeledWord("\tbuild_list: type = ", jDir->type); putLabeledWord("\tbuild_list: node_crc = ", jDir->node_crc); putLabeledWord("\tbuild_list: name_crc = ", jDir->name_crc); - putLabeledWord("\tbuild_list: offset = ", b->offset); /* FIXME: ? [RS] */ + putLabeledWord("\tbuild_list: offset = ", b->offset); /* FIXME: ? [RS] */ b = b->next; put_fl_mem(jDir); } @@ -1158,16 +1296,19 @@ jffs2_1pass_build_lists(struct part_info * part) /* start at the beginning of the partition */ while (offset < max) { - if ((oldoffset >> SPIN_BLKSIZE) != (offset >> SPIN_BLKSIZE)) { + if ((oldoffset >> SPIN_BLKSIZE) != (offset >> SPIN_BLKSIZE)) { printf("\b\b%c ", spinner[counter++ % sizeof(spinner)]); oldoffset = offset; } + WATCHDOG_RESET(); + node = (struct jffs2_unknown_node *) get_node_mem((u32)part->offset + offset); if (node->magic == JFFS2_MAGIC_BITMASK && hdr_crc(node)) { /* if its a fragment add it */ if (node->nodetype == JFFS2_NODETYPE_INODE && - inode_crc((struct jffs2_raw_inode *) node)) { + inode_crc((struct jffs2_raw_inode *) node) && + data_crc((struct jffs2_raw_inode *) node)) { if (insert_node(&pL->frag, (u32) part->offset + offset) == NULL) { put_fl_mem(node); @@ -1187,16 +1328,18 @@ jffs2_1pass_build_lists(struct part_info * part) } else if (node->nodetype == JFFS2_NODETYPE_CLEANMARKER) { if (node->totlen != sizeof(struct jffs2_unknown_node)) printf("OOPS Cleanmarker has bad size " - "%d != %d\n", node->totlen, + "%d != %zu\n", + node->totlen, sizeof(struct jffs2_unknown_node)); } else if (node->nodetype == JFFS2_NODETYPE_PADDING) { if (node->totlen < sizeof(struct jffs2_unknown_node)) printf("OOPS Padding has bad size " - "%d < %d\n", node->totlen, + "%d < %zu\n", + node->totlen, sizeof(struct jffs2_unknown_node)); } else { - printf("Unknown node type: %x len %d " - "offset 0x%x\n", node->nodetype, + printf("Unknown node type: %x len %d offset 0x%x\n", + node->nodetype, node->totlen, offset); } offset += ((node->totlen + 3) & ~3); @@ -1366,5 +1509,3 @@ jffs2_1pass_info(struct part_info * part) } return 1; } - -#endif /* CFG_CMD_JFFS2 */