* 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
*
* - 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.
#include <malloc.h>
#include <linux/stat.h>
#include <linux/time.h>
-
-#if defined(CONFIG_CMD_JFFS2)
-
+#include <watchdog.h>
#include <jffs2/jffs2.h>
#include <jffs2/jffs2_1pass.h>
#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<<BLKSIZE bytes */
+#define NODE_CHUNK 1024 /* size of memory allocation chunk in b_nodes */
+#define SPIN_BLKSIZE 18 /* spin after having scanned 1<<BLKSIZE bytes */
/* Debugging switches */
#undef DEBUG_DIRENTS /* print directory entry list after scan */
#undef DEBUG_FRAGMENTS /* print fragment list after scan */
-#undef DEBUG /* enable debugging messages */
+#undef DEBUG /* enable debugging messages */
#ifdef DEBUG
#if (defined(CONFIG_JFFS2_NAND) && \
defined(CONFIG_CMD_NAND) )
-#if defined(CFG_NAND_LEGACY)
+#if defined(CONFIG_NAND_LEGACY)
#include <linux/mtd/nand_legacy.h>
#else
#include <nand.h>
*
*/
-#if defined(CFG_NAND_LEGACY)
+#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);
-#else
-/* info for NAND chips, defined in drivers/mtd/nand/nand.c */
-extern nand_info_t nand_info[];
#endif
#define NAND_PAGE_SIZE 512
}
}
-#if defined(CFG_NAND_LEGACY)
+#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) {
}
#endif
+#if defined(CONFIG_CMD_ONENAND)
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <onenand_uboot.h>
+
+#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 defined(CONFIG_CMD_FLASH)
/*
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;
}
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;
}
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 */
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
}
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))
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.
*/
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
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
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;
}
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);
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) = ",
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);
}
/* 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 */
} 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);
}
return 1;
}
-
-#endif