All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/5] New environment code
@ 2010-07-17 19:45 Wolfgang Denk
  2010-07-17 19:45 ` [U-Boot] [PATCH 1/5] Add basic errno support Wolfgang Denk
                   ` (9 more replies)
  0 siblings, 10 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-17 19:45 UTC (permalink / raw)
  To: u-boot

The following patch series adds some utilities (qsort and hash table
based database functions) and uses these to reimplement the code used
for the internal handling of environment variables.


Motivation:

* Old environment code used a pessimizing implementation:
  - variable lookup used linear search => slow
  - changed/added variables were added at the end, i. e. most
    frequently used variables had the slowest access times => slow
  - each setenv() would calculate the CRC32 checksum over the whole
    environment block => slow
* "redundant" envrionment was locked down to two copies
* No easy way to implement features like "reset to factory defaults",
  or to select one out of several pre-defined (previously saved) sets
  of environment settings ("profiles")
* No easy way to import or export environment settings

======================================================================

API Changes:

- Variable names starting with '#' are no longer allowed

  I didn't find any such variable names being used; it is highly
  recommended to follow standard conventions and start variable names
  with an alphanumeric character

- "printenv" will now print a backslash at the end of all but the last
  lines of a multi-line variable value.

  Multi-line variables have never been formally defined, allthough
  there is no reason not to use them. Now we define rules how to deal
  with them, allowing for import and export.

- Function forceenv() and the related code in saveenv() was removed.
  At the moment this is causing build problems for the only user of
  this code (schmoogie - which has no entry in MAINTAINERS); may be
  fixed later by implementing the "env set -f" feature.

Inconsistencies:

- "printenv" will '\\'-escape the '\n' in multi-line variables, while
  "printenv var" will not do that.

======================================================================

Advantages:

- "printenv" output much better readable (sorted)
- faster!
- extendable (additional variable properties can be added)
- new, powerful features like "factory reset" or easy switching
  between several different environment settings ("profiles")

Disadvantages:

- Image size grows by typically 5...7 KiB (might shrink a bit again on
  systems with redundant environment with a following patch series)

======================================================================

Implemented:

- env command with subcommands:

  - env print [arg ...]

    same as "printenv": print environment

  - env set [-f] name [arg ...]

    same as "setenv": set (and delete) environment variables

    ["-f" - force setting even for read-only variables - not
    implemented yet.]

  - end delete [-f] name

    not implemented yet

    ["-f" - force delete even for read-only variables]

  - env save

    same as "saveenv": save environment

  - env export [-t | -b | -c] addr [size]

    export internal representation (hash table) in formats usable for
    persistent storage or processing:

	-t:	export as text format; if size is given, data will be
		padded with '\0' bytes; if not, one terminating '\0'
		will be added (which is included in the "filesize"
		setting so you can for exmple copy this to flash and
		keep the termination).
	-b:	export as binary format (name=value pairs separated by
		'\0', list end marked by double "\0\0")
	-c:	export as checksum protected environment format as
		used for example by "saveenv" command
	addr:	memory address where environment gets stored
	size:	size of output buffer

	With "-c" and size is NOT given, then the export command will
	format the data as currently used for the persistent storage,
	i. e. it will use CONFIG_ENV_SECT_SIZE as output block size and
	prepend a valid CRC32 checksum and, in case of resundant
	environment, a "current" redundancy flag. If size is given, this
	value will be used instead of CONFIG_ENV_SECT_SIZE; again, CRC32
	checksum and redundancy flag will be inserted.

	With "-b" and "-t", always only the real data (including a
	terminating '\0' byte) will be written; here the optional size
	argument will be used to make sure not to overflow the user
	provided buffer; the command will abort if the size is not
	sufficient. Any remainign space will be '\0' padded.

        On successful return, the variable "filesize" will be set.
        Note that filesize includes the trailing/terminating '\0'
        byte(s).

        Usage szenario: create a text snapshot/backup of the current
	settings:

		=> env export -t 100000
		=> era ${backup_addr} +${filesize}
		=> cp.b 100000 ${backup_addr} ${filesize}

	Re-import this snapshot, deleting all other settings:

		=> env import -d -t ${backup_addr}

  - env import [-d] [-t | -b | -c] addr [size]

    import external format (text or binary) into hash table,
    optionally deleting existing values:

	-d:	delete existing environment before importing;
		otherwise overwrite / append to existion definitions
	-t:	assume text format; either "size" must be given or the
		text data must be '\0' terminated
	-b:	assume binary format ('\0' separated, "\0\0" terminated)
	-c:	assume checksum protected environment format
	addr:	memory address to read from
	size:	length of input data; if missing, proper '\0'
		termination is mandatory

  - env default -f

    reset default environment: drop all environment settings and load
    default environment

  - env ask name [message] [size]

    same as "askenv": ask for environment variable

  - env edit name

    same as "editenv": edit environment variable

  - env run

    same as "run": run commands in an environment variable

======================================================================

TODO:

- drop default env as implemented now; provide a text file based
  initialization instead (eventually using several text files to
  incrementally build it from common blocks) and a tool to convert it
  into a binary blob / object file.

- It would be nice if we could add wildcard support for environment
  variables; this is needed for variable name auto-completion,
  but it would also be nice to be able to say "printenv ip*" or
  "printenv *addr*"

- Some boards don't link any more due to the grown code size:
  AR405, CANBT, DU405, PMC440, canyonlands, sc3, sequoia, socrates.

	=> cc: Matthias Fuchs <matthias.fuchs@esd-electronics.com>,
	       Stefan Roese <sr@denx.de>,
	       Heiko Schocher <hs@denx.de>

- Dropping forceenv() causes build problems on schmoogie

	=> cc: Sergey Kubushyn <ksi@koi8.net>

- Build tested on PPC and ARM only; runtime tested with NOR and NAND
  flash only => needs testing!!



Wolfgang Denk (5):
      Add basic errno support.
      Add qsort - add support for sorting data arrays
      Add hash table support as base for new environment code
      Remove support for CONFIG_HAS_UID and "forceenv" command
      New implementation for internal handling of environment variables.

 README                              |    8 +
 board/zeus/zeus.c                   |   25 +-
 common/cmd_nvedit.c                 |  668 ++++++++++++++++++++++----------
 common/command.c                    |    3 +-
 common/dlmalloc.c                   |   25 +-
 common/env_common.c                 |  125 +++---
 common/env_dataflash.c              |  114 ++++--
 common/env_eeprom.c                 |   85 +++--
 common/env_flash.c                  |  245 +++++++------
 common/env_mgdisk.c                 |   33 +-
 common/env_nand.c                   |  188 +++++----
 common/env_nowhere.c                |   11 +-
 common/env_nvram.c                  |   46 ++-
 common/env_onenand.c                |   65 ++--
 common/env_sf.c                     |  132 ++++---
 common/exports.c                    |    4 -
 include/_exports.h                  |    1 -
 include/common.h                    |    7 +-
 include/configs/MVSMR.h             |    1 -
 include/configs/davinci_schmoogie.h |    1 -
 include/environment.h               |    5 +-
 include/errno.h                     |    9 +
 include/exports.h                   |    3 -
 include/search.h                    |  106 +++++
 lib/Makefile                        |    3 +
 lib/errno.c                         |    1 +
 lib/hashtable.c                     |  735 +++++++++++++++++++++++++++++++++++
 lib/qsort.c                         |   69 ++++
 28 files changed, 1998 insertions(+), 720 deletions(-)
 create mode 100644 include/errno.h
 create mode 100644 include/search.h
 create mode 100644 lib/errno.c
 create mode 100644 lib/hashtable.c
 create mode 100644 lib/qsort.c

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 1/5] Add basic errno support.
  2010-07-17 19:45 [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
@ 2010-07-17 19:45 ` Wolfgang Denk
  2010-07-17 21:17   ` Mike Frysinger
  2010-09-12 19:16   ` Wolfgang Denk
  2010-07-17 19:45 ` [U-Boot] [PATCH 2/5] Add qsort - add support for sorting data arrays Wolfgang Denk
                   ` (8 subsequent siblings)
  9 siblings, 2 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-17 19:45 UTC (permalink / raw)
  To: u-boot

Needed for hash table support; probably useful in a lot of other
places as well.

Signed-off-by: Wolfgang Denk <wd@denx.de>
---
 include/errno.h |    9 +++++++++
 lib/Makefile    |    1 +
 lib/errno.c     |    1 +
 3 files changed, 11 insertions(+), 0 deletions(-)
 create mode 100644 include/errno.h
 create mode 100644 lib/errno.c

diff --git a/include/errno.h b/include/errno.h
new file mode 100644
index 0000000..e24a33b
--- /dev/null
+++ b/include/errno.h
@@ -0,0 +1,9 @@
+#ifndef _ERRNO_H
+
+#include <asm-generic/errno.h>
+
+extern int errno;
+
+#define __set_errno(val) do { errno = val; } while (0)
+
+#endif /* _ERRNO_H */
diff --git a/lib/Makefile b/lib/Makefile
index c45f07c..c26536d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -37,6 +37,7 @@ COBJS-y += crc32.o
 COBJS-y += ctype.o
 COBJS-y += display_options.o
 COBJS-y += div64.o
+COBJS-y += errno.o
 COBJS-$(CONFIG_GZIP) += gunzip.o
 COBJS-$(CONFIG_LMB) += lmb.o
 COBJS-y += ldiv.o
diff --git a/lib/errno.c b/lib/errno.c
new file mode 100644
index 0000000..8330a8f
--- /dev/null
+++ b/lib/errno.c
@@ -0,0 +1 @@
+int errno = 0;
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 2/5] Add qsort - add support for sorting data arrays
  2010-07-17 19:45 [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
  2010-07-17 19:45 ` [U-Boot] [PATCH 1/5] Add basic errno support Wolfgang Denk
@ 2010-07-17 19:45 ` Wolfgang Denk
  2010-09-12 19:16   ` Wolfgang Denk
  2010-07-17 19:45 ` [U-Boot] [PATCH 3/5] Add hash table support as base for new environment code Wolfgang Denk
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-17 19:45 UTC (permalink / raw)
  To: u-boot

Code adapted from uClibc-0.9.30.3

Signed-off-by: Wolfgang Denk <wd@denx.de>
---
 include/common.h |    4 +++
 lib/Makefile     |    1 +
 lib/qsort.c      |   69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 74 insertions(+), 0 deletions(-)
 create mode 100644 lib/qsort.c

diff --git a/include/common.h b/include/common.h
index eddec22..e4b4ec0 100644
--- a/include/common.h
+++ b/include/common.h
@@ -631,6 +631,10 @@ static inline IPaddr_t getenv_IPaddr (char *var)
 	return (string_to_ip(getenv(var)));
 }
 
+/* lib/qsort.c */
+void qsort(void *base, size_t nmemb, size_t size,
+	   int(*compar)(const void *, const void *));
+
 /* lib/time.c */
 void	udelay        (unsigned long);
 
diff --git a/lib/Makefile b/lib/Makefile
index c26536d..2d969a3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -43,6 +43,7 @@ COBJS-$(CONFIG_LMB) += lmb.o
 COBJS-y += ldiv.o
 COBJS-$(CONFIG_MD5) += md5.o
 COBJS-y += net_utils.o
+COBJS-y += qsort.o
 COBJS-$(CONFIG_SHA1) += sha1.o
 COBJS-$(CONFIG_SHA256) += sha256.o
 COBJS-y += string.o
diff --git a/lib/qsort.c b/lib/qsort.c
new file mode 100644
index 0000000..bb47319
--- /dev/null
+++ b/lib/qsort.c
@@ -0,0 +1,69 @@
+/*
+ * Code adapted from uClibc-0.9.30.3
+ *
+ * It is therefore covered by the GNU LESSER GENERAL PUBLIC LICENSE
+ * Version 2.1, February 1999
+ *
+ * Wolfgang Denk <wd@denx.de>
+ */
+
+/* This code is derived from a public domain shell sort routine by
+ * Ray Gardner and found in Bob Stout's snippets collection.  The
+ * original code is included below in an #if 0/#endif block.
+ *
+ * I modified it to avoid the possibility of overflow in the wgap
+ * calculation, as well as to reduce the generated code size with
+ * bcc and gcc. */
+
+#include <linux/types.h>
+#if 0
+#include <assert.h>
+#else
+#define assert(arg)
+#endif
+
+void qsort(void  *base,
+           size_t nel,
+           size_t width,
+           int (*comp)(const void *, const void *))
+{
+	size_t wgap, i, j, k;
+	char tmp;
+
+	if ((nel > 1) && (width > 0)) {
+		assert(nel <= ((size_t)(-1)) / width); /* check for overflow */
+		wgap = 0;
+		do {
+			wgap = 3 * wgap + 1;
+		} while (wgap < (nel-1)/3);
+		/* From the above, we know that either wgap == 1 < nel or */
+		/* ((wgap-1)/3 < (int) ((nel-1)/3) <= (nel-1)/3 ==> wgap <  nel. */
+		wgap *= width;			/* So this can not overflow if wnel doesn't. */
+		nel *= width;			/* Convert nel to 'wnel' */
+		do {
+			i = wgap;
+			do {
+				j = i;
+				do {
+					register char *a;
+					register char *b;
+
+					j -= wgap;
+					a = j + ((char *)base);
+					b = a + wgap;
+					if ((*comp)(a, b) <= 0) {
+						break;
+					}
+					k = width;
+					do {
+						tmp = *a;
+						*a++ = *b;
+						*b++ = tmp;
+					} while (--k);
+				} while (j >= wgap);
+				i += width;
+			} while (i < nel);
+			wgap = (wgap - width)/3;
+		} while (wgap);
+	}
+}
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 3/5] Add hash table support as base for new environment code
  2010-07-17 19:45 [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
  2010-07-17 19:45 ` [U-Boot] [PATCH 1/5] Add basic errno support Wolfgang Denk
  2010-07-17 19:45 ` [U-Boot] [PATCH 2/5] Add qsort - add support for sorting data arrays Wolfgang Denk
@ 2010-07-17 19:45 ` Wolfgang Denk
  2010-09-12 19:16   ` Wolfgang Denk
  2010-12-08  9:44   ` Mike Frysinger
  2010-07-17 19:45 ` [U-Boot] [PATCH 4/5] Remove support for CONFIG_HAS_UID and "forceenv" command Wolfgang Denk
                   ` (6 subsequent siblings)
  9 siblings, 2 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-17 19:45 UTC (permalink / raw)
  To: u-boot

This implementation is based on code from uClibc-0.9.30.3 but was
modified and extended for use within U-Boot.

Major modifications and extensions:

* hsearch() [modified / extended]:
  - While the standard version does not make any assumptions about
    the type of the stored data objects at all, this implementation
    works with NUL terminated strings only.
  - Instead of storing just pointers to the original objects, we
    create local copies so the caller does not need to care about the
    data any more.
  - The standard implementation does not provide a way to update an
    existing entry.  This version will create a new entry or update an
    existing one when both "action == ENTER" and "item.data != NULL".
  - hsearch_r(): Instead of returning 1 on success, we return the
    index into the internal hash table, which is also guaranteed to be
    positive.  This allows us direct access to the found hash table
    slot for example for functions like hdelete().
* hdelete() [added]:
  - The standard implementation of hsearch(3) does not provide any way
    to delete any entries from the hash table.  We extend the code to
    do that.
* hexport() [added]:
  - Export the data stored in the hash table in linearized form:
    Entries are exported as "name=value" strings, separated by an
    arbitrary (non-NUL, of course) separator character. This allows to
    use this function both when formatting the U-Boot environment for
    external storage (using '\0' as separator), but also when using it
    for the "printenv" command to print all variables, simply by using
    as '\n" as separator. This can also be used for new features like
    exporting the environment data as text file, including the option
    for later re-import.
  - The entries in the result list will be sorted by ascending key
    values.
* himport() [added]:
  - Import linearized data into hash table.  This is the inverse
    function to hexport(): it takes a linear list of "name=value"
    pairs and creates hash table entries from it.
  - Entries without "value", i. e. consisting of only "name" or
    "name=", will cause this entry to be deleted from the hash table.
  - The "flag" argument can be used to control the behaviour: when
    the H_NOCLEAR bit is set, then an existing hash table will kept,
    i. e. new data will be added to an existing hash table;
    otherwise, old data will be discarded and a new hash table will
    be created.
  - The separator character for the "name=value" pairs can be
    selected, so we both support importing from externally stored
    environment data (separated by NUL characters) and from plain text
    files (entries separated by newline characters).
  - To allow for nicely formatted text input, leading white space
    (sequences of SPACE and TAB chars) is ignored, and entries
    starting (after removal of any leading white space) with a '#'
    character are considered comments and ignored.
  - NOTE: this means that a variable name cannot start with a '#'
    character.
  - When using a non-NUL separator character, backslash is used as
    escape character in the value part, allowing for example fo
    multi-line values.
  - In theory, arbitrary separator characters can be used, but only
    '\0' and '\n' have really been tested.

Signed-off-by: Wolfgang Denk <wd@denx.de>
---
 include/search.h |  106 ++++++++
 lib/Makefile     |    1 +
 lib/hashtable.c  |  721 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 828 insertions(+), 0 deletions(-)
 create mode 100644 include/search.h
 create mode 100644 lib/hashtable.c

diff --git a/include/search.h b/include/search.h
new file mode 100644
index 0000000..fccc757
--- /dev/null
+++ b/include/search.h
@@ -0,0 +1,106 @@
+/*
+ * Declarations for System V style searching functions.
+ * Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc.
+ * This file is part of the GNU C Library.
+ *
+ * The GNU C Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * The GNU C Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the GNU C Library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA.
+ */
+
+/*
+ * Based on code from uClibc-0.9.30.3
+ * Extensions for use within U-Boot
+ * Copyright (C) 2010 Wolfgang Denk <wd@denx.de>
+ */
+
+#ifndef _SEARCH_H
+#define	_SEARCH_H 1
+
+#include <stddef.h>
+
+#define __set_errno(val) do { errno = val; } while (0)
+
+/*
+ * Prototype structure for a linked-list data structure.
+ * This is the type used by the `insque' and `remque' functions.
+ */
+
+/* For use with hsearch(3).  */
+typedef int (*__compar_fn_t) (__const void *, __const void *);
+typedef __compar_fn_t comparison_fn_t;
+
+/* Action which shall be performed in the call the hsearch.  */
+typedef enum {
+	FIND,
+	ENTER
+} ACTION;
+
+typedef struct entry {
+	char *key;
+	char *data;
+} ENTRY;
+
+/* Opaque type for internal use.  */
+struct _ENTRY;
+
+/*
+ * Family of hash table handling functions.  The functions also
+ * have reentrant counterparts ending with _r.  The non-reentrant
+ * functions all work on a signle internal hashing table.
+ */
+
+/* Data type for reentrant functions.  */
+struct hsearch_data {
+	struct _ENTRY *table;
+	unsigned int size;
+	unsigned int filled;
+};
+
+/* Create a new hashing table which will at most contain NEL elements.  */
+extern int hcreate(size_t __nel);
+extern int hcreate_r(size_t __nel, struct hsearch_data *__htab);
+
+/* Destroy current internal hashing table.  */
+extern void hdestroy(void);
+extern void hdestroy_r(struct hsearch_data *__htab);
+
+/*
+ * Search for entry matching ITEM.key in internal hash table.  If
+ * ACTION is `FIND' return found entry or signal error by returning
+ * NULL.  If ACTION is `ENTER' replace existing data (if any) with
+ * ITEM.data.
+ * */
+extern ENTRY *hsearch(ENTRY __item, ACTION __action);
+extern int hsearch_r(ENTRY __item, ACTION __action, ENTRY ** __retval,
+		     struct hsearch_data *__htab);
+
+/* Search and delete entry matching ITEM.key in internal hash table. */
+extern int hdelete(const char *__key);
+extern int hdelete_r(const char *__key, struct hsearch_data *__htab);
+
+extern ssize_t hexport(const char __sep, char **__resp, size_t __size);
+extern ssize_t hexport_r(struct hsearch_data *__htab,
+		     const char __sep, char **__resp, size_t __size);
+
+extern int himport(const char *__env, size_t __size, const char __sep,
+		   int __flag);
+extern int himport_r(struct hsearch_data *__htab,
+		     const char *__env, size_t __size, const char __sep,
+		     int __flag);
+
+/* Flags for himport() / himport_r() */
+#define	H_NOCLEAR	1	/* do not clear hash table before importing */
+
+#endif /* search.h */
diff --git a/lib/Makefile b/lib/Makefile
index 2d969a3..a8de3e1 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -39,6 +39,7 @@ COBJS-y += display_options.o
 COBJS-y += div64.o
 COBJS-y += errno.o
 COBJS-$(CONFIG_GZIP) += gunzip.o
+COBJS-y += hashtable.o
 COBJS-$(CONFIG_LMB) += lmb.o
 COBJS-y += ldiv.o
 COBJS-$(CONFIG_MD5) += md5.o
diff --git a/lib/hashtable.c b/lib/hashtable.c
new file mode 100644
index 0000000..2f3b5c8
--- /dev/null
+++ b/lib/hashtable.c
@@ -0,0 +1,721 @@
+/*
+ * This implementation is based on code from uClibc-0.9.30.3 but was
+ * modified and extended for use within U-Boot.
+ *
+ * Copyright (C) 2010 Wolfgang Denk <wd@denx.de>
+ *
+ * Original license header:
+ *
+ * Copyright (C) 1993, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ * This file is part of the GNU C Library.
+ * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1993.
+ *
+ * The GNU C Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * The GNU C Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the GNU C Library; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA.
+ */
+
+#include <errno.h>
+#include <malloc.h>
+
+#ifdef USE_HOSTCC		/* HOST build */
+# include <string.h>
+# include <assert.h>
+
+# ifndef debug
+#  ifdef DEBUG
+#   define debug(fmt,args...)	printf(fmt ,##args)
+#  else
+#   define debug(fmt,args...)
+#  endif
+# endif
+#else				/* U-Boot build */
+# include <common.h>
+# include <linux/string.h>
+#endif
+
+#include "search.h"
+
+/*
+ * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
+ * [Knuth]            The Art of Computer Programming, part 3 (6.4)
+ */
+
+/*
+ * The non-reentrant version use a global space for storing the hash table.
+ */
+static struct hsearch_data htab;
+
+/*
+ * The reentrant version has no static variables to maintain the state.
+ * Instead the interface of all functions is extended to take an argument
+ * which describes the current status.
+ */
+typedef struct _ENTRY {
+	unsigned int used;
+	ENTRY entry;
+} _ENTRY;
+
+
+/*
+ * hcreate()
+ */
+
+/*
+ * For the used double hash method the table size has to be a prime. To
+ * correct the user given table size we need a prime test.  This trivial
+ * algorithm is adequate because
+ * a)  the code is (most probably) called a few times per program run and
+ * b)  the number is small because the table must fit in the core
+ * */
+static int isprime(unsigned int number)
+{
+	/* no even number will be passed */
+	unsigned int div = 3;
+
+	while (div * div < number && number % div != 0)
+		div += 2;
+
+	return number % div != 0;
+}
+
+int hcreate(size_t nel)
+{
+	return hcreate_r(nel, &htab);
+}
+
+/*
+ * Before using the hash table we must allocate memory for it.
+ * Test for an existing table are done. We allocate one element
+ * more as the found prime number says. This is done for more effective
+ * indexing as explained in the comment for the hsearch function.
+ * The contents of the table is zeroed, especially the field used
+ * becomes zero.
+ */
+int hcreate_r(size_t nel, struct hsearch_data *htab)
+{
+	/* Test for correct arguments.  */
+	if (htab == NULL) {
+		__set_errno(EINVAL);
+		return 0;
+	}
+
+	/* There is still another table active. Return with error. */
+	if (htab->table != NULL)
+		return 0;
+
+	/* Change nel to the first prime number not smaller as nel. */
+	nel |= 1;		/* make odd */
+	while (!isprime(nel))
+		nel += 2;
+
+	htab->size = nel;
+	htab->filled = 0;
+
+	/* allocate memory and zero out */
+	htab->table = (_ENTRY *) calloc(htab->size + 1, sizeof(_ENTRY));
+	if (htab->table == NULL)
+		return 0;
+
+	/* everything went alright */
+	return 1;
+}
+
+
+/*
+ * hdestroy()
+ */
+void hdestroy(void)
+{
+	hdestroy_r(&htab);
+}
+
+/*
+ * After using the hash table it has to be destroyed. The used memory can
+ * be freed and the local static variable can be marked as not used.
+ */
+void hdestroy_r(struct hsearch_data *htab)
+{
+	int i;
+
+	/* Test for correct arguments.  */
+	if (htab == NULL) {
+		__set_errno(EINVAL);
+		return;
+	}
+
+	/* free used memory */
+	for (i = 1; i <= htab->size; ++i) {
+		if (htab->table[i].used) {
+			ENTRY *ep = &htab->table[i].entry;
+
+			free(ep->key);
+			free(ep->data);
+		}
+	}
+	free(htab->table);
+
+	/* the sign for an existing table is an value != NULL in htable */
+	htab->table = NULL;
+}
+
+/*
+ * hsearch()
+ */
+
+/*
+ * This is the search function. It uses double hashing with open addressing.
+ * The argument item.key has to be a pointer to an zero terminated, most
+ * probably strings of chars. The function for generating a number of the
+ * strings is simple but fast. It can be replaced by a more complex function
+ * like ajw (see [Aho,Sethi,Ullman]) if the needs are shown.
+ *
+ * We use an trick to speed up the lookup. The table is created by hcreate
+ * with one more element available. This enables us to use the index zero
+ * special. This index will never be used because we store the first hash
+ * index in the field used where zero means not used. Every other value
+ * means used. The used field can be used as a first fast comparison for
+ * equality of the stored and the parameter value. This helps to prevent
+ * unnecessary expensive calls of strcmp.
+ *
+ * This implementation differs from the standard library version of
+ * this function in a number of ways:
+ *
+ * - While the standard version does not make any assumptions about
+ *   the type of the stored data objects at all, this implementation
+ *   works with NUL terminated strings only.
+ * - Instead of storing just pointers to the original objects, we
+ *   create local copies so the caller does not need to care about the
+ *   data any more.
+ * - The standard implementation does not provide a way to update an
+ *   existing entry.  This version will create a new entry or update an
+ *   existing one when both "action == ENTER" and "item.data != NULL".
+ * - Instead of returning 1 on success, we return the index into the
+ *   internal hash table, which is also guaranteed to be positive.
+ *   This allows us direct access to the found hash table slot for
+ *   example for functions like hdelete().
+ */
+
+ENTRY *hsearch(ENTRY item, ACTION action)
+{
+	ENTRY *result;
+
+	(void) hsearch_r(item, action, &result, &htab);
+
+	return result;
+}
+
+int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
+	      struct hsearch_data *htab)
+{
+	unsigned int hval;
+	unsigned int count;
+	unsigned int len = strlen(item.key);
+	unsigned int idx;
+
+	/* Compute an value for the given string. Perhaps use a better method. */
+	hval = len;
+	count = len;
+	while (count-- > 0) {
+		hval <<= 4;
+		hval += item.key[count];
+	}
+
+	/*
+	 * First hash function:
+	 * simply take the modul but prevent zero.
+	 */
+	hval %= htab->size;
+	if (hval == 0)
+		++hval;
+
+	/* The first index tried. */
+	idx = hval;
+
+	if (htab->table[idx].used) {
+		/*
+                 * Further action might be required according to the
+		 * action value.
+		 */
+		unsigned hval2;
+
+		if (htab->table[idx].used == hval
+		    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
+			/* Overwrite existing value? */
+			if ((action == ENTER) && (item.data != NULL)) {
+				free(htab->table[idx].entry.data);
+				htab->table[idx].entry.data =
+					strdup(item.data);
+				if (!htab->table[idx].entry.data) {
+					__set_errno(ENOMEM);
+					*retval = NULL;
+					return 0;
+				}
+			}
+			/* return found entry */
+			*retval = &htab->table[idx].entry;
+			return idx;
+		}
+
+		/*
+		 * Second hash function:
+		 * as suggested in [Knuth]
+		 */
+		hval2 = 1 + hval % (htab->size - 2);
+
+		do {
+			/*
+                         * Because SIZE is prime this guarantees to
+                         * step through all available indices.
+			 */
+			if (idx <= hval2)
+				idx = htab->size + idx - hval2;
+			else
+				idx -= hval2;
+
+			/*
+			 * If we visited all entries leave the loop
+			 * unsuccessfully.
+			 */
+			if (idx == hval)
+				break;
+
+			/* If entry is found use it. */
+			if ((htab->table[idx].used == hval)
+			    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
+				/* Overwrite existing value? */
+				if ((action == ENTER) && (item.data != NULL)) {
+					free(htab->table[idx].entry.data);
+					htab->table[idx].entry.data =
+						strdup(item.data);
+					if (!htab->table[idx].entry.data) {
+						__set_errno(ENOMEM);
+						*retval = NULL;
+						return 0;
+					}
+				}
+				/* return found entry */
+				*retval = &htab->table[idx].entry;
+				return idx;
+			}
+		}
+		while (htab->table[idx].used);
+	}
+
+	/* An empty bucket has been found. */
+	if (action == ENTER) {
+		/*
+                 * If table is full and another entry should be
+                 * entered return with error.
+		 */
+		if (htab->filled == htab->size) {
+			__set_errno(ENOMEM);
+			*retval = NULL;
+			return 0;
+		}
+
+		/*
+		 * Create new entry;
+		 * create copies of item.key and item.data
+		 */
+		htab->table[idx].used = hval;
+		htab->table[idx].entry.key = strdup(item.key);
+		htab->table[idx].entry.data = strdup(item.data);
+		if (!htab->table[idx].entry.key ||
+		    !htab->table[idx].entry.data) {
+			__set_errno(ENOMEM);
+			*retval = NULL;
+			return 0;
+		}
+
+		++htab->filled;
+
+		/* return new entry */
+		*retval = &htab->table[idx].entry;
+		return 1;
+	}
+
+	__set_errno(ESRCH);
+	*retval = NULL;
+	return 0;
+}
+
+
+/*
+ * hdelete()
+ */
+
+/*
+ * The standard implementation of hsearch(3) does not provide any way
+ * to delete any entries from the hash table.  We extend the code to
+ * do that.
+ */
+
+int hdelete(const char *key)
+{
+	return hdelete_r(key, &htab);
+}
+
+int hdelete_r(const char *key, struct hsearch_data *htab)
+{
+	ENTRY e, *ep;
+	int idx;
+
+	debug("hdelete: DELETE key \"%s\"\n", key);
+
+	e.key = (char *)key;
+
+	if ((idx = hsearch_r(e, FIND, &ep, htab)) == 0) {
+		__set_errno(ESRCH);
+		return 0;	/* not found */
+	}
+
+	/* free used ENTRY */
+	debug("hdelete: DELETING key \"%s\"\n", key);
+
+	free(ep->key);
+	free(ep->data);
+	htab->table[idx].used = 0;
+
+	--htab->filled;
+
+	return 1;
+}
+
+/*
+ * hexport()
+ */
+
+/*
+ * Export the data stored in the hash table in linearized form.
+ *
+ * Entries are exported as "name=value" strings, separated by an
+ * arbitrary (non-NUL, of course) separator character. This allows to
+ * use this function both when formatting the U-Boot environment for
+ * external storage (using '\0' as separator), but also when using it
+ * for the "printenv" command to print all variables, simply by using
+ * as '\n" as separator. This can also be used for new features like
+ * exporting the environment data as text file, including the option
+ * for later re-import.
+ *
+ * The entries in the result list will be sorted by ascending key
+ * values.
+ *
+ * If the separator character is different from NUL, then any
+ * separator characters and backslash characters in the values will
+ * be escaped by a preceeding backslash in output. This is needed for
+ * example to enable multi-line values, especially when the output
+ * shall later be parsed (for example, for re-import).
+ *
+ * There are several options how the result buffer is handled:
+ *
+ * *resp  size
+ * -----------
+ *  NULL    0	A string of sufficient length will be allocated.
+ *  NULL   >0	A string of the size given will be
+ *		allocated. An error will be returned if the size is
+ *		not sufficient.  Any unused bytes in the string will
+ *		be '\0'-padded.
+ * !NULL    0	The user-supplied buffer will be used. No length
+ *		checking will be performed, i. e. it is assumed that
+ *		the buffer size will always be big enough. DANGEROUS.
+ * !NULL   >0	The user-supplied buffer will be used. An error will
+ *		be returned if the size is not sufficient.  Any unused
+ *		bytes in the string will be '\0'-padded.
+ */
+
+ssize_t hexport(const char sep, char **resp, size_t size)
+{
+	return hexport_r(&htab, sep, resp, size);
+}
+
+static int cmpkey(const void *p1, const void *p2)
+{
+	ENTRY *e1 = *(ENTRY **) p1;
+	ENTRY *e2 = *(ENTRY **) p2;
+
+	return (strcmp(e1->key, e2->key));
+}
+
+ssize_t hexport_r(struct hsearch_data *htab, const char sep,
+		 char **resp, size_t size)
+{
+	ENTRY *list[htab->size];
+	char *res, *p;
+	size_t totlen;
+	int i, n;
+
+	/* Test for correct arguments.  */
+	if ((resp == NULL) || (htab == NULL)) {
+		__set_errno(EINVAL);
+		return (-1);
+	}
+
+	debug("EXPORT  table = %p, htab.size = %d, htab.filled = %d, size = %d\n",
+		htab, htab->size, htab->filled, size);
+	/*
+	 * Pass 1:
+	 * search used entries,
+	 * save addresses and compute total length
+	 */
+	for (i = 1, n = 0, totlen = 0; i <= htab->size; ++i) {
+
+		if (htab->table[i].used) {
+			ENTRY *ep = &htab->table[i].entry;
+
+			list[n++] = ep;
+
+			totlen += strlen(ep->key) + 2;
+
+			if (sep == '\0') {
+				totlen += strlen(ep->data);
+			} else {	/* check if escapes are needed */
+				char *s = ep->data;
+
+				while (*s) {
+					++totlen;
+					/* add room for needed escape chars */
+					if ((*s == sep) || (*s == '\\'))
+						++totlen;
+					++s;
+				}
+			}
+			totlen += 2;	/* for '=' and 'sep' char */
+		}
+	}
+
+#ifdef DEBUG
+	/* Pass 1a: print unsorted list */
+	printf("Unsorted: n=%d\n", n);
+	for (i = 0; i < n; ++i) {
+		printf("\t%3d: %p ==> %-10s => %s\n",
+		       i, list[i], list[i]->key, list[i]->data);
+	}
+#endif
+
+	/* Sort list by keys */
+	qsort(list, n, sizeof(ENTRY *), cmpkey);
+
+	/* Check if the user supplied buffer size is sufficient */
+	if (size) {
+		if (size < totlen + 1) {	/* provided buffer too small */
+			debug("### buffer too small: %d, but need %d\n",
+				size, totlen + 1);
+			__set_errno(ENOMEM);
+			return (-1);
+		}
+	} else {
+		size = totlen + 1;
+	}
+
+	/* Check if the user provided a buffer */
+	if (*resp) {
+		/* yes; clear it */
+		res = *resp;
+		memset(res, '\0', size);
+	} else {
+		/* no, allocate and clear one */
+		*resp = res = calloc(1, size);
+		if (res == NULL) {
+			__set_errno(ENOMEM);
+			return (-1);
+		}
+	}
+	/*
+	 * Pass 2:
+	 * export sorted list of result data
+	 */
+	for (i = 0, p = res; i < n; ++i) {
+		char *s;
+
+		s = list[i]->key;
+		while (*s)
+			*p++ = *s++;
+		*p++ = '=';
+
+		s = list[i]->data;
+
+		while (*s) {
+			if ((*s == sep) || (*s == '\\'))
+				*p++ = '\\';	/* escape */
+			*p++ = *s++;
+		}
+		*p++ = sep;
+	}
+	*p = '\0';		/* terminate result */
+
+	return size;
+}
+
+
+/*
+ * himport()
+ */
+
+/*
+ * Import linearized data into hash table.
+ *
+ * This is the inverse function to hexport(): it takes a linear list
+ * of "name=value" pairs and creates hash table entries from it.
+ *
+ * Entries without "value", i. e. consisting of only "name" or
+ * "name=", will cause this entry to be deleted from the hash table.
+ *
+ * The "flag" argument can be used to control the behaviour: when the
+ * H_NOCLEAR bit is set, then an existing hash table will kept, i. e.
+ * new data will be added to an existing hash table; otherwise, old
+ * data will be discarded and a new hash table will be created.
+ *
+ * The separator character for the "name=value" pairs can be selected,
+ * so we both support importing from externally stored environment
+ * data (separated by NUL characters) and from plain text files
+ * (entries separated by newline characters).
+ *
+ * To allow for nicely formatted text input, leading white space
+ * (sequences of SPACE and TAB chars) is ignored, and entries starting
+ * (after removal of any leading white space) with a '#' character are
+ * considered comments and ignored.
+ *
+ * [NOTE: this means that a variable name cannot start with a '#'
+ * character.]
+ *
+ * When using a non-NUL separator character, backslash is used as
+ * escape character in the value part, allowing for example for
+ * multi-line values.
+ *
+ * In theory, arbitrary separator characters can be used, but only
+ * '\0' and '\n' have really been tested.
+ */
+
+int himport(const char *env, size_t size, const char sep, int flag)
+{
+	return himport_r(&htab, env, size, sep, flag);
+}
+
+int himport_r(struct hsearch_data *htab,
+	      const char *env, size_t size, const char sep, int flag)
+{
+	char *data, *sp, *dp, *name, *value;
+
+	/* Test for correct arguments.  */
+	if (htab == NULL) {
+		__set_errno(EINVAL);
+		return 0;
+	}
+
+	/* we allocate new space to make sure we can write to the array */
+	if ((data = malloc(size)) == NULL) {
+		debug("himport_r: can't malloc %d bytes\n", size);
+		__set_errno(ENOMEM);
+		return 0;
+	}
+	memcpy(data, env, size);
+	dp = data;
+
+	if ((flag & H_NOCLEAR) == 0) {
+		/* Destroy old hash table if one exists */
+		debug("Destroy Hash Table: %p table = %p\n", htab,
+		       htab->table);
+		if (htab->table)
+			hdestroy_r(htab);
+	}
+
+	/*
+	 * Create new hash table (if needed).  The computation of the hash
+	 * table size is based on heuristics: in a sample of some 70+
+	 * existing systems we found an average size of 39+ bytes per entry
+	 * in the environment (for the whole key=value pair). Assuming a
+	 * size of 7 per entry (= safety factor of >5) should provide enough
+	 * safety margin for any existing environment definitons and still
+	 * allow for more than enough dynamic additions. Note that the
+	 * "size" argument is supposed to give the maximum enviroment size
+	 * (CONFIG_ENV_SIZE).
+	 */
+
+	if (!htab->table) {
+		int nent = size / 7;
+
+		debug("Create Hash Table: N=%d\n", nent);
+
+		if (hcreate_r(nent, htab) == 0) {
+			free(data);
+			return 0;
+		}
+	}
+
+	/* Parse environment; allow for '\0' and 'sep' as separators */
+	do {
+		ENTRY e, *rv;
+
+		/* skip leading white space */
+		while ((*dp == ' ') || (*dp == '\t'))
+			++dp;
+
+		/* skip comment lines */
+		if (*dp == '#') {
+			while (*dp && (*dp != sep))
+				++dp;
+			++dp;
+			continue;
+		}
+
+		/* parse name */
+		for (name = dp; *dp != '=' && *dp && *dp != sep; ++dp)
+			;
+
+		/* deal with "name" and "name=" entries (delete var) */
+		if (*dp == '\0' || *(dp + 1) == '\0' ||
+		    *dp == sep || *(dp + 1) == sep) {
+			if (*dp == '=')
+				*dp++ = '\0';
+			*dp++ = '\0';	/* terminate name */
+
+			debug("DELETE CANDIDATE: \"%s\"\n", name);
+
+			if (hdelete_r(name, htab) == 0)
+				debug("DELETE ERROR ##############################\n");
+
+			continue;
+		}
+		*dp++ = '\0';	/* terminate name */
+
+		/* parse value; deal with escapes */
+		for (value = sp = dp; *dp && (*dp != sep); ++dp) {
+			if ((*dp == '\\') && *(dp + 1))
+				++dp;
+			*sp++ = *dp;
+		}
+		*sp++ = '\0';	/* terminate value */
+		++dp;
+
+		/* enter into hash table */
+		e.key = name;
+		e.data = value;
+
+		hsearch_r(e, ENTER, &rv, htab);
+		if (rv == NULL) {
+			printf("himport_r: can't insert \"%s=%s\" into hash table\n", name, value);
+			return 0;
+		}
+
+		debug("INSERT: %p ==> name=\"%s\" value=\"%s\"\n", rv, name,
+		       value);
+		debug("        table = %p, size = %d, filled = %d\n", htab,
+		       htab->size, htab->filled);
+	} while ((dp < data + size) && *dp);	/* size check needed for text */
+						/* without '\0' termination */
+	free(data);
+
+	return 1;		/* everything OK */
+}
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 4/5] Remove support for CONFIG_HAS_UID and "forceenv" command
  2010-07-17 19:45 [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
                   ` (2 preceding siblings ...)
  2010-07-17 19:45 ` [U-Boot] [PATCH 3/5] Add hash table support as base for new environment code Wolfgang Denk
@ 2010-07-17 19:45 ` Wolfgang Denk
  2010-07-17 22:12   ` Sergey Kubushyn
  2010-09-12 19:18   ` Wolfgang Denk
  2010-07-17 19:45 ` [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables Wolfgang Denk
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-17 19:45 UTC (permalink / raw)
  To: u-boot

This (undocumented) concept was only in use for the MVSMR and
davinci_schmoogie Sergey Kubushyn <ksi@koi8.net> boards.
Drop it for now.  If really needed, it should be reimplemented
later in the context of the new environment command set.

Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: Andre Schwarz <andre.schwarz@matrix-vision.de>
Cc: Sergey Kubushyn <ksi@koi8.net>
---
 common/cmd_nvedit.c                 |   13 -------------
 common/exports.c                    |    3 ---
 include/_exports.h                  |    1 -
 include/common.h                    |    3 ---
 include/configs/MVSMR.h             |    1 -
 include/configs/davinci_schmoogie.h |    1 -
 include/exports.h                   |    3 ---
 7 files changed, 0 insertions(+), 25 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 13325bc..8c86f15 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -247,12 +247,7 @@ int _do_setenv (int flag, int argc, char * const argv[])
 		 * ver is readonly.
 		 */
 		if (
-#ifdef CONFIG_HAS_UID
-		/* Allow serial# forced overwrite with 0xdeaf4add flag */
-		    ((strcmp (name, "serial#") == 0) && (flag != 0xdeaf4add)) ||
-#else
 		    (strcmp (name, "serial#") == 0) ||
-#endif
 		    ((strcmp (name, "ethaddr") == 0)
 #if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
 		     && (strcmp ((char *)env_get_addr(oldval),MK_STR(CONFIG_ETHADDR)) != 0)
@@ -397,14 +392,6 @@ int setenv (char *varname, char *varvalue)
 		return _do_setenv (0, 3, argv);
 }
 
-#ifdef CONFIG_HAS_UID
-void forceenv (char *varname, char *varvalue)
-{
-	char * const argv[4] = { "forceenv", varname, varvalue, NULL };
-	_do_setenv (0xdeaf4add, 3, argv);
-}
-#endif
-
 int do_setenv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	if (argc < 2) {
diff --git a/common/exports.c b/common/exports.c
index cefe6f6..bde52a6 100644
--- a/common/exports.c
+++ b/common/exports.c
@@ -35,9 +35,6 @@ unsigned long get_version(void)
 # define spi_release_bus   dummy
 # define spi_xfer          dummy
 #endif
-#ifndef CONFIG_HAS_UID
-# define forceenv          dummy
-#endif
 
 void jumptable_init(void)
 {
diff --git a/include/_exports.h b/include/_exports.h
index f3df568..d89b65b 100644
--- a/include/_exports.h
+++ b/include/_exports.h
@@ -18,7 +18,6 @@ EXPORT_FUNC(vprintf)
 EXPORT_FUNC(do_reset)
 EXPORT_FUNC(getenv)
 EXPORT_FUNC(setenv)
-EXPORT_FUNC(forceenv)
 EXPORT_FUNC(simple_strtoul)
 EXPORT_FUNC(simple_strtol)
 EXPORT_FUNC(strcmp)
diff --git a/include/common.h b/include/common.h
index e4b4ec0..5eef9c7 100644
--- a/include/common.h
+++ b/include/common.h
@@ -262,9 +262,6 @@ int	saveenv	     (void);
 int inline setenv   (char *, char *);
 #else
 int	setenv	     (char *, char *);
-#ifdef CONFIG_HAS_UID
-void	forceenv     (char *, char *);
-#endif
 #endif /* CONFIG_PPC */
 #ifdef CONFIG_ARM
 # include <asm/mach-types.h>
diff --git a/include/configs/MVSMR.h b/include/configs/MVSMR.h
index 6492068..000c4c6 100644
--- a/include/configs/MVSMR.h
+++ b/include/configs/MVSMR.h
@@ -185,7 +185,6 @@
  */
 #define CONFIG_ENV_IS_IN_FLASH
 #undef	CONFIG_SYS_FLASH_PROTECTION
-#define CONFIG_HAS_UID
 #define	CONFIG_OVERWRITE_ETHADDR_ONCE
 
 #define CONFIG_ENV_OFFSET	0x8000
diff --git a/include/configs/davinci_schmoogie.h b/include/configs/davinci_schmoogie.h
index 875dda4..04cdc21 100644
--- a/include/configs/davinci_schmoogie.h
+++ b/include/configs/davinci_schmoogie.h
@@ -99,7 +99,6 @@
 /*=====================*/
 #define CONFIG_RTC_DS1307		/* RTC chip on SCHMOOGIE */
 #define CONFIG_SYS_I2C_RTC_ADDR	0x6f	/* RTC chip I2C address */
-#define CONFIG_HAS_UID
 #define CONFIG_UID_DS28CM00		/* Unique ID on SCHMOOGIE */
 #define CONFIG_SYS_UID_ADDR		0x50	/* UID chip I2C address */
 /*==============================*/
diff --git a/include/exports.h b/include/exports.h
index 1d79a31..7404a7c 100644
--- a/include/exports.h
+++ b/include/exports.h
@@ -26,9 +26,6 @@ int setenv (char *varname, char *varvalue);
 long simple_strtol(const char *cp,char **endp,unsigned int base);
 int strcmp(const char * cs,const char * ct);
 int ustrtoul(const char *cp, char **endp, unsigned int base);
-#ifdef CONFIG_HAS_UID
-void forceenv (char *varname, char *varvalue);
-#endif
 #if defined(CONFIG_CMD_I2C)
 int i2c_write (uchar, uint, int , uchar* , int);
 int i2c_read (uchar, uint, int , uchar* , int);
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-17 19:45 [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
                   ` (3 preceding siblings ...)
  2010-07-17 19:45 ` [U-Boot] [PATCH 4/5] Remove support for CONFIG_HAS_UID and "forceenv" command Wolfgang Denk
@ 2010-07-17 19:45 ` Wolfgang Denk
  2010-07-17 22:48   ` [U-Boot] [PATCH] new env: fix off-by-one error in setenv command Wolfgang Denk
                     ` (4 more replies)
  2010-07-17 19:49 ` [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
                   ` (4 subsequent siblings)
  9 siblings, 5 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-17 19:45 UTC (permalink / raw)
  To: u-boot

Motivation:

* Old environment code used a pessimizing implementation:
  - variable lookup used linear search => slow
  - changed/added variables were added at the end, i. e. most
    frequently used variables had the slowest access times => slow
  - each setenv() would calculate the CRC32 checksum over the whole
    environment block => slow
* "redundant" envrionment was locked down to two copies
* No easy way to implement features like "reset to factory defaults",
  or to select one out of several pre-defined (previously saved) sets
  of environment settings ("profiles")
* No easy way to import or export environment settings

======================================================================

API Changes:

- Variable names starting with '#' are no longer allowed

  I didn't find any such variable names being used; it is highly
  recommended to follow standard conventions and start variable names
  with an alphanumeric character

- "printenv" will now print a backslash at the end of all but the last
  lines of a multi-line variable value.

  Multi-line variables have never been formally defined, allthough
  there is no reason not to use them. Now we define rules how to deal
  with them, allowing for import and export.

- Function forceenv() and the related code in saveenv() was removed.
  At the moment this is causing build problems for the only user of
  this code (schmoogie - which has no entry in MAINTAINERS); may be
  fixed later by implementing the "env set -f" feature.

Inconsistencies:

- "printenv" will '\\'-escape the '\n' in multi-line variables, while
  "printenv var" will not do that.

======================================================================

Advantages:

- "printenv" output much better readable (sorted)
- faster!
- extendable (additional variable properties can be added)
- new, powerful features like "factory reset" or easy switching
  between several different environment settings ("profiles")

Disadvantages:

- Image size grows by typically 5...7 KiB (might shrink a bit again on
  systems with redundant environment with a following patch series)

======================================================================

Implemented:

- env command with subcommands:

  - env print [arg ...]

    same as "printenv": print environment

  - env set [-f] name [arg ...]

    same as "setenv": set (and delete) environment variables

    ["-f" - force setting even for read-only variables - not
    implemented yet.]

  - end delete [-f] name

    not implemented yet

    ["-f" - force delete even for read-only variables]

  - env save

    same as "saveenv": save environment

  - env export [-t | -b | -c] addr [size]

    export internal representation (hash table) in formats usable for
    persistent storage or processing:

	-t:	export as text format; if size is given, data will be
		padded with '\0' bytes; if not, one terminating '\0'
		will be added (which is included in the "filesize"
		setting so you can for exmple copy this to flash and
		keep the termination).
	-b:	export as binary format (name=value pairs separated by
		'\0', list end marked by double "\0\0")
	-c:	export as checksum protected environment format as
		used for example by "saveenv" command
	addr:	memory address where environment gets stored
	size:	size of output buffer

	With "-c" and size is NOT given, then the export command will
	format the data as currently used for the persistent storage,
	i. e. it will use CONFIG_ENV_SECT_SIZE as output block size and
	prepend a valid CRC32 checksum and, in case of resundant
	environment, a "current" redundancy flag. If size is given, this
	value will be used instead of CONFIG_ENV_SECT_SIZE; again, CRC32
	checksum and redundancy flag will be inserted.

	With "-b" and "-t", always only the real data (including a
	terminating '\0' byte) will be written; here the optional size
	argument will be used to make sure not to overflow the user
	provided buffer; the command will abort if the size is not
	sufficient. Any remainign space will be '\0' padded.

        On successful return, the variable "filesize" will be set.
        Note that filesize includes the trailing/terminating '\0'
        byte(s).

        Usage szenario: create a text snapshot/backup of the current
	settings:

		=> env export -t 100000
		=> era ${backup_addr} +${filesize}
		=> cp.b 100000 ${backup_addr} ${filesize}

	Re-import this snapshot, deleting all other settings:

		=> env import -d -t ${backup_addr}

  - env import [-d] [-t | -b | -c] addr [size]

    import external format (text or binary) into hash table,
    optionally deleting existing values:

	-d:	delete existing environment before importing;
		otherwise overwrite / append to existion definitions
	-t:	assume text format; either "size" must be given or the
		text data must be '\0' terminated
	-b:	assume binary format ('\0' separated, "\0\0" terminated)
	-c:	assume checksum protected environment format
	addr:	memory address to read from
	size:	length of input data; if missing, proper '\0'
		termination is mandatory

  - env default -f

    reset default environment: drop all environment settings and load
    default environment

  - env ask name [message] [size]

    same as "askenv": ask for environment variable

  - env edit name

    same as "editenv": edit environment variable

  - env run

    same as "run": run commands in an environment variable

======================================================================

TODO:

- drop default env as implemented now; provide a text file based
  initialization instead (eventually using several text files to
  incrementally build it from common blocks) and a tool to convert it
  into a binary blob / object file.

- It would be nice if we could add wildcard support for environment
  variables; this is needed for variable name auto-completion,
  but it would also be nice to be able to say "printenv ip*" or
  "printenv *addr*"

- Some boards don't link any more due to the grown code size:
  AR405, CANBT, DU405, PMC440, canyonlands, sc3, sequoia, socrates.

	=> cc: Matthias Fuchs <matthias.fuchs@esd-electronics.com>,
	       Stefan Roese <sr@denx.de>,
	       Heiko Schocher <hs@denx.de>

- Dropping forceenv() causes build problems on schmoogie

	=> cc: Sergey Kubushyn <ksi@koi8.net>

- Build tested on PPC and ARM only; runtime tested with NOR and NAND
  flash only => needs testing!!

Signed-off-by: Wolfgang Denk <wd@denx.de>
Cc: Matthias Fuchs <matthias.fuchs@esd-electronics.com>,
Cc: Stefan Roese <sr@denx.de>,
Cc: Heiko Schocher <hs@denx.de>
Cc: Sergey Kubushyn <ksi@koi8.net>
---
 README                 |    8 +
 board/zeus/zeus.c      |   25 +--
 common/cmd_nvedit.c    |  655 +++++++++++++++++++++++++++++++++---------------
 common/command.c       |    3 +-
 common/dlmalloc.c      |   25 +-
 common/env_common.c    |  125 +++++-----
 common/env_dataflash.c |  114 ++++++----
 common/env_eeprom.c    |   85 ++++---
 common/env_flash.c     |  245 ++++++++++---------
 common/env_mgdisk.c    |   33 +--
 common/env_nand.c      |  188 ++++++++------
 common/env_nowhere.c   |   11 +-
 common/env_nvram.c     |   46 +++-
 common/env_onenand.c   |   65 +++---
 common/env_sf.c        |  132 ++++++-----
 common/exports.c       |    1 -
 include/environment.h  |    5 +-
 lib/hashtable.c        |   32 ++-
 18 files changed, 1094 insertions(+), 704 deletions(-)

diff --git a/README b/README
index a9c98f2..3a3c631 100644
--- a/README
+++ b/README
@@ -2354,6 +2354,14 @@ Configuration Settings:
 		on high Ethernet traffic.
 		Defaults to 4 if not defined.
 
+- CONFIG_ENV_MAX_ENTRIES
+
+        Maximum number of entries in the hash table that is used
+        internally to store the environment settings. The default
+        setting is supposed to be generous and should work in most
+        cases. This setting can be used to tune behaviour; see
+        lib/hashtable.c for details.
+
 The following definitions that deal with the placement and management
 of environment data (variable area); in general, we support the
 following configurations:
diff --git a/board/zeus/zeus.c b/board/zeus/zeus.c
index e295151..4e6878a 100644
--- a/board/zeus/zeus.c
+++ b/board/zeus/zeus.c
@@ -222,27 +222,8 @@ static int restore_default(void)
 	char *buf_save;
 	u32 crc;
 
-	/*
-	 * Unprotect and erase environment area
-	 */
-	flash_protect(FLAG_PROTECT_CLEAR,
-		      CONFIG_ENV_ADDR_REDUND,
-		      CONFIG_ENV_ADDR_REDUND + 2*CONFIG_ENV_SECT_SIZE - 1,
-		      &flash_info[0]);
+	set_default_env("");
 
-	flash_sect_erase(CONFIG_ENV_ADDR_REDUND,
-			 CONFIG_ENV_ADDR_REDUND + 2*CONFIG_ENV_SECT_SIZE - 1);
-
-	/*
-	 * Now restore default environment from U-Boot image
-	 * -> ipaddr, serverip...
-	 */
-	memset(env_ptr, 0, sizeof(env_t));
-	memcpy(env_ptr->data, default_environment, ENV_SIZE);
-#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
-	env_ptr->flags = 0xFF;
-#endif
-	env_crc_update();
 	gd->env_valid = 1;
 
 	/*
@@ -251,6 +232,10 @@ static int restore_default(void)
 	 * -> ethaddr, eth1addr, serial#
 	 */
 	buf = buf_save = malloc(FACTORY_RESET_ENV_SIZE);
+	if (buf == NULL) {
+		printf("ERROR: malloc() failed\n");
+		return -1;
+	}
 	if (eeprom_read(FACTORY_RESET_I2C_EEPROM, FACTORY_RESET_ENV_OFFS,
 			(u8 *)buf, FACTORY_RESET_ENV_SIZE)) {
 		puts("\nError reading EEPROM!\n");
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 8c86f15..976a30b 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2000-2002
+ * (C) Copyright 2000-2010
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
  *
  * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
@@ -24,27 +24,26 @@
  * MA 02111-1307 USA
  */
 
-/**************************************************************************
- *
+/*
  * Support for persistent environment data
  *
- * The "environment" is stored as a list of '\0' terminated
- * "name=value" strings. The end of the list is marked by a double
- * '\0'. New entries are always added at the end. Deleting an entry
- * shifts the remaining entries to the front. Replacing an entry is a
- * combination of deleting the old value and adding the new one.
- *
- * The environment is preceeded by a 32 bit CRC over the data part.
+ * The "environment" is stored on external storage as a list of '\0'
+ * terminated "name=value" strings. The end of the list is marked by
+ * a double '\0'. The environment is preceeded by a 32 bit CRC over
+ * the data part and, in case of redundant environment, a byte of
+ * flags.
  *
- **************************************************************************
+ * This linearized representation will also be used before
+ * relocation, i. e. as long as we don't have a full C runtime
+ * environment. After that, we use a hash table.
  */
 
 #include <common.h>
 #include <command.h>
 #include <environment.h>
-#if defined(CONFIG_CMD_EDITENV)
+#include <search.h>
+#include <errno.h>
 #include <malloc.h>
-#endif
 #include <watchdog.h>
 #include <serial.h>
 #include <linux/stddef.h>
@@ -71,8 +70,10 @@ SPI_FLASH|MG_DISK|NVRAM|NOWHERE}
 #define XMK_STR(x)	#x
 #define MK_STR(x)	XMK_STR(x)
 
-/************************************************************************
-************************************************************************/
+/*
+ * Maximum expected input data size for import command
+ */
+#define	MAX_ENV_SIZE	(1 << 20)	/* 1 MiB */
 
 /*
  * Table with supported baudrates (defined in config_xyz.h)
@@ -81,7 +82,7 @@ static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
 #define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
 
 /*
- * This variable is incremented on each do_setenv (), so it can
+ * This variable is incremented on each do_env_set(), so it can
  * be used via get_env_id() as an indication, if the environment
  * has changed or not. So it is possible to reread an environment
  * variable only if the environment was changed ... done so for
@@ -93,61 +94,51 @@ int get_env_id (void)
 {
 	return env_id;
 }
-/************************************************************************
- * Command interface: print one or all environment variables
- */
 
 /*
- * state 0: finish printing this string and return (matched!)
- * state 1: no matching to be done; print everything
- * state 2: continue searching for matched name
+ * Command interface: print one or all environment variables
+ *
+ * Returns 0 in case of error, or length of printed string
  */
-static int printenv(char *name, int state)
+static int env_print(char *name)
 {
-	int i, j;
-	char c, buf[17];
-
-	i = 0;
-	buf[16] = '\0';
-
-	while (state && env_get_char(i) != '\0') {
-		if (state == 2 && envmatch((uchar *)name, i) >= 0)
-			state = 0;
-
-		j = 0;
-		do {
-			buf[j++] = c = env_get_char(i++);
-			if (j == sizeof(buf) - 1) {
-				if (state <= 1)
-					puts(buf);
-				j = 0;
-			}
-		} while (c != '\0');
+	char *res = NULL;
+	size_t len;
+
+	if (name) {		/* print a single name */
+		ENTRY e, *ep;
+
+		e.key = name;
+		e.data = NULL;
+		ep = hsearch (e, FIND);
+		if (ep == NULL)
+			return 0;
+		len = printf ("%s=%s\n", ep->key, ep->data);
+		return len;
+	}
 
-		if (state <= 1) {
-			if (j)
-				puts(buf);
-			putc('\n');
-		}
+	/* print whole list */
+	len = hexport('\n', &res, 0);
 
-		if (ctrlc())
-			return -1;
+	if (len > 0) {
+		puts(res);
+		free(res);
+		return len;
 	}
 
-	if (state == 0)
-		i = 0;
-	return i;
+	/* should never happen */
+	return 0;
 }
 
-int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_env_print (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	int i;
 	int rcode = 0;
 
 	if (argc == 1) {
 		/* print all env vars */
-		rcode = printenv(NULL, 1);
-		if (rcode < 0)
+		rcode = env_print(NULL);
+		if (!rcode)
 			return 1;
 		printf("\nEnvironment size: %d/%ld bytes\n",
 			rcode, (ulong)ENV_SIZE);
@@ -156,9 +147,9 @@ int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
 	/* print selected env vars */
 	for (i = 1; i < argc; ++i) {
-		char *name = argv[i];
-		if (printenv(name, 2)) {
-			printf("## Error: \"%s\" not defined\n", name);
+		int rc = env_print(argv[i]);
+		if (!rc) {
+			printf("## Error: \"%s\" not defined\n", argv[i]);
 			++rcode;
 		}
 	}
@@ -166,25 +157,18 @@ int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	return rcode;
 }
 
-/************************************************************************
+/*
  * Set a new environment variable,
  * or replace or delete an existing one.
- *
- * This function will ONLY work with a in-RAM copy of the environment
  */
 
-int _do_setenv (int flag, int argc, char * const argv[])
+int _do_env_set (int flag, int argc, char * const argv[])
 {
-	int   i, len, oldval;
+	bd_t  *bd = gd->bd;
+	int   i, len;
 	int   console = -1;
-	uchar *env, *nxt = NULL;
-	char *name;
-	bd_t *bd = gd->bd;
-
-	uchar *env_data = env_get_addr(0);
-
-	if (!env_data)	/* need copy in RAM */
-		return 1;
+	char  *name, *value, *s;
+	ENTRY e, *ep;
 
 	name = argv[1];
 
@@ -197,13 +181,9 @@ int _do_setenv (int flag, int argc, char * const argv[])
 	/*
 	 * search if variable with this name already exists
 	 */
-	oldval = -1;
-	for (env=env_data; *env; env=nxt+1) {
-		for (nxt=env; *nxt; ++nxt)
-			;
-		if ((oldval = envmatch((uchar *)name, env-env_data)) >= 0)
-			break;
-	}
+	e.key = name;
+	e.data = NULL;
+	ep = hsearch (e, FIND);
 
 	/* Check for console redirection */
 	if (strcmp(name,"stdin") == 0) {
@@ -237,31 +217,25 @@ int _do_setenv (int flag, int argc, char * const argv[])
 	}
 
 	/*
-	 * Delete any existing definition
+	 * Some variables like "ethaddr" and "serial#" can be set only
+	 * once and cannot be deleted; also, "ver" is readonly.
 	 */
-	if (oldval >= 0) {
+	if (ep) {		/* variable exists */
 #ifndef CONFIG_ENV_OVERWRITE
-
-		/*
-		 * Ethernet Address and serial# can be set only once,
-		 * ver is readonly.
-		 */
-		if (
-		    (strcmp (name, "serial#") == 0) ||
+		if ((strcmp (name, "serial#") == 0) ||
 		    ((strcmp (name, "ethaddr") == 0)
 #if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
-		     && (strcmp ((char *)env_get_addr(oldval),MK_STR(CONFIG_ETHADDR)) != 0)
+		     && (strcmp (ep->data,MK_STR(CONFIG_ETHADDR)) != 0)
 #endif	/* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */
 		    ) ) {
 			printf ("Can't overwrite \"%s\"\n", name);
 			return 1;
 		}
 #endif
-
 		/*
 		 * Switch to new baudrate if new baudrate is supported
 		 */
-		if (strcmp(argv[1],"baudrate") == 0) {
+		if (strcmp(name,"baudrate") == 0) {
 			int baudrate = simple_strtoul(argv[2], NULL, 10);
 			int i;
 			for (i=0; i<N_BAUDRATES; ++i) {
@@ -288,75 +262,50 @@ int _do_setenv (int flag, int argc, char * const argv[])
 				      break;
 			}
 		}
-
-		if (*++nxt == '\0') {
-			if (env > env_data) {
-				env--;
-			} else {
-				*env = '\0';
-			}
-		} else {
-			for (;;) {
-				*env = *nxt++;
-				if ((*env == '\0') && (*nxt == '\0'))
-					break;
-				++env;
-			}
-		}
-		*++env = '\0';
 	}
 
 	/* Delete only ? */
 	if ((argc < 3) || argv[2] == NULL) {
-		env_crc_update ();
-		return 0;
+		int rc = hdelete(name);
+		return !rc;
 	}
 
 	/*
-	 * Append new definition@the end
-	 */
-	for (env=env_data; *env || *(env+1); ++env)
-		;
-	if (env > env_data)
-		++env;
-	/*
-	 * Overflow when:
-	 * "name" + "=" + "val" +"\0\0"  > ENV_SIZE - (env-env_data)
+	 * Insert / replace new value
 	 */
-	len = strlen(name) + 2;
-	/* add '=' for first arg, ' ' for all others */
-	for (i=2; i<argc; ++i) {
+	for (i=2,len=1; i<argc; ++i) {
 		len += strlen(argv[i]) + 1;
 	}
-	if (len > (&env_data[ENV_SIZE]-env)) {
-		printf ("## Error: environment overflow, \"%s\" deleted\n", name);
+	if ((value = malloc(len)) == NULL) {
+		printf("## Can't malloc %d bytes\n", len);
 		return 1;
 	}
-	while ((*env = *name++) != '\0')
-		env++;
-	for (i=2; i<argc; ++i) {
-		char *val = argv[i];
+	for (i=2,s=value; i<argc; ++i) {
+		char *v = argv[i];
 
-		*env = (i==2) ? '=' : ' ';
-		while ((*++env = *val++) != '\0')
+		while ((*s++ = *v++) != '\0')
 			;
+		*s++ = ' ';
+	}
+	if (s != value)
+		*--s = '\0';
+
+	e.key  = name;
+	e.data = value;
+	ep = hsearch(e, ENTER);
+	free(value);
+	if (!ep) {
+		printf("## Error inserting \"%s\" variable, errno=%d\n",
+			name, errno);
+		return 1;
 	}
-
-	/* end is marked with double '\0' */
-	*++env = '\0';
-
-	/* Update CRC */
-	env_crc_update ();
 
 	/*
 	 * Some variables should be updated when the corresponding
-	 * entry in the enviornment is changed
+	 * entry in the environment is changed
 	 */
 
-	if (strcmp(argv[1],"ethaddr") == 0)
-		return 0;
-
-	if (strcmp(argv[1],"ipaddr") == 0) {
+	if (strcmp(name,"ipaddr") == 0) {
 		char *s = argv[2];	/* always use only one arg */
 		char *e;
 		unsigned long addr;
@@ -369,13 +318,12 @@ int _do_setenv (int flag, int argc, char * const argv[])
 		}
 		bd->bi_ip_addr = htonl(addr);
 		return 0;
-	}
-	if (strcmp(argv[1],"loadaddr") == 0) {
+	} else if (strcmp(argv[1],"loadaddr") == 0) {
 		load_addr = simple_strtoul(argv[2], NULL, 16);
 		return 0;
 	}
 #if defined(CONFIG_CMD_NET)
-	if (strcmp(argv[1],"bootfile") == 0) {
+	else if (strcmp(argv[1],"bootfile") == 0) {
 		copy_filename (BootFile, argv[2], sizeof(BootFile));
 		return 0;
 	}
@@ -387,32 +335,31 @@ int setenv (char *varname, char *varvalue)
 {
 	char * const argv[4] = { "setenv", varname, varvalue, NULL };
 	if ((varvalue == NULL) || (varvalue[0] == '\0'))
-		return _do_setenv (0, 2, argv);
+		return _do_env_set(0, 2, argv);
 	else
-		return _do_setenv (0, 3, argv);
+		return _do_env_set(0, 3, argv);
 }
 
-int do_setenv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_env_set (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	if (argc < 2) {
 		cmd_usage(cmdtp);
 		return 1;
 	}
 
-	return _do_setenv (flag, argc, argv);
+	return _do_env_set(flag, argc, argv);
 }
 
-/************************************************************************
+/*
  * Prompt for environment variable
  */
-
 #if defined(CONFIG_CMD_ASKENV)
-int do_askenv ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_env_ask ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	extern char console_buffer[CONFIG_SYS_CBSIZE];
 	char message[CONFIG_SYS_CBSIZE];
 	int size = CONFIG_SYS_CBSIZE - 1;
-	int len;
+	int i, len, pos;
 	char *local_args[4];
 
 	local_args[0] = argv[0];
@@ -420,40 +367,31 @@ int do_askenv ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	local_args[2] = NULL;
 	local_args[3] = NULL;
 
-	if (argc < 2) {
-		cmd_usage(cmdtp);
-		return 1;
-	}
 	/* Check the syntax */
 	switch (argc) {
 	case 1:
 		cmd_usage(cmdtp);
 		return 1;
 
-	case 2:		/* askenv envname */
-		sprintf (message, "Please enter '%s':", argv[1]);
+	case 2:		/* env_ask envname */
+		sprintf(message, "Please enter '%s':", argv[1]);
 		break;
 
-	case 3:		/* askenv envname size */
-		sprintf (message, "Please enter '%s':", argv[1]);
-		size = simple_strtoul (argv[2], NULL, 10);
+	case 3:		/* env_ask envname size */
+		sprintf(message, "Please enter '%s':", argv[1]);
+		size = simple_strtoul(argv[2], NULL, 10);
 		break;
 
-	default:	/* askenv envname message1 ... messagen size */
-	    {
-		int i;
-		int pos = 0;
-
-		for (i = 2; i < argc - 1; i++) {
+	default:	/* env_ask envname message1 ... messagen size */
+		for (i=2,pos=0; i < argc - 1; i++) {
 			if (pos) {
 				message[pos++] = ' ';
 			}
-			strcpy (message+pos, argv[i]);
+			strcpy(message+pos, argv[i]);
 			pos += strlen(argv[i]);
 		}
 		message[pos] = '\0';
-		size = simple_strtoul (argv[argc - 1], NULL, 10);
-	    }
+		size = simple_strtoul(argv[argc - 1], NULL, 10);
 		break;
 	}
 
@@ -464,7 +402,7 @@ int do_askenv ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		return 1;
 
 	/* prompt for input */
-	len = readline (message);
+	len = readline(message);
 
 	if (size < len)
 		console_buffer[size] = '\0';
@@ -476,15 +414,15 @@ int do_askenv ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	}
 
 	/* Continue calling setenv code */
-	return _do_setenv (flag, len, local_args);
+	return _do_env_set(flag, len, local_args);
 }
 #endif
 
-/************************************************************************
+/*
  * Interactively edit an environment variable
  */
 #if defined(CONFIG_CMD_EDITENV)
-int do_editenv(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_env_edit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	char buffer[CONFIG_SYS_CBSIZE];
 	char *init_val;
@@ -508,34 +446,27 @@ int do_editenv(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 #endif /* CONFIG_CMD_EDITENV */
 
-/************************************************************************
+/*
  * Look up variable from environment,
  * return address of storage for that variable,
  * or NULL if not found
  */
-
 char *getenv (char *name)
 {
-	int i, nxt;
+	ENTRY e, *ep;
 
 	WATCHDOG_RESET();
 
-	for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
-		int val;
+	e.key  = name;
+	e.data = NULL;
+	ep = hsearch (e, FIND);
 
-		for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) {
-			if (nxt >= CONFIG_ENV_SIZE) {
-				return (NULL);
-			}
-		}
-		if ((val=envmatch((uchar *)name, i)) < 0)
-			continue;
-		return ((char *)env_get_addr(val));
-	}
-
-	return (NULL);
+	return (ep ? ep->data : NULL);
 }
 
+/*
+ * Look up variable from environment for restricted C runtime env.
+ */
 int getenv_r (char *name, char *buf, unsigned len)
 {
 	int i, nxt;
@@ -563,7 +494,7 @@ int getenv_r (char *name, char *buf, unsigned len)
 
 #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
 
-int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_env_save (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	extern char * env_name_spec;
 
@@ -573,7 +504,7 @@ int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 
 U_BOOT_CMD(
-	saveenv, 1, 0,	do_saveenv,
+	saveenv, 1, 0,	do_env_save,
 	"save environment variables to persistent storage",
 	""
 );
@@ -581,7 +512,7 @@ U_BOOT_CMD(
 #endif
 
 
-/************************************************************************
+/*
  * Match a name / name=value pair
  *
  * s1 is either a simple 'name', or a 'name=value' pair.
@@ -600,12 +531,343 @@ int envmatch (uchar *s1, int i2)
 	return(-1);
 }
 
+static int do_env_default(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+	if ((argc != 2) || (strcmp(argv[1], "-f") != 0)) {
+		cmd_usage(cmdtp);
+		return 1;
+	}
+	set_default_env("## Resetting to default environment\n");
+	return 0;
+}
+
+static int do_env_delete(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+	printf("Not implemented yet\n");
+	return 0;
+}
+
+/*
+ * env export [-t | -b | -c] addr [size]
+ *	-t:	export as text format; if size is given, data will be
+ *		padded with '\0' bytes; if not, one terminating '\0'
+ *		will be added (which is included in the "filesize"
+ *		setting so you can for exmple copy this to flash and
+ *		keep the termination).
+ *	-b:	export as binary format (name=value pairs separated by
+ *		'\0', list end marked by double "\0\0")
+ *	-c:	export as checksum protected environment format as
+ *		used for example by "saveenv" command
+ *	addr:	memory address where environment gets stored
+ *	size:	size of output buffer
+ *
+ * With "-c" and size is NOT given, then the export command will
+ * format the data as currently used for the persistent storage,
+ * i. e. it will use CONFIG_ENV_SECT_SIZE as output block size and
+ * prepend a valid CRC32 checksum and, in case of resundant
+ * environment, a "current" redundancy flag. If size is given, this
+ * value will be used instead of CONFIG_ENV_SECT_SIZE; again, CRC32
+ * checksum and redundancy flag will be inserted.
+ *
+ * With "-b" and "-t", always only the real data (including a
+ * terminating '\0' byte) will be written; here the optional size
+ * argument will be used to make sure not to overflow the user
+ * provided buffer; the command will abort if the size is not
+ * sufficient. Any remainign space will be '\0' padded.
+ *
+ * On successful return, the variable "filesize" will be set.
+ * Note that filesize includes the trailing/terminating '\0' byte(s).
+ *
+ * Usage szenario:  create a text snapshot/backup of the current settings:
+ *
+ *	=> env export -t 100000
+ *	=> era ${backup_addr} +${filesize}
+ *	=> cp.b 100000 ${backup_addr} ${filesize}
+ *
+ * Re-import this snapshot, deleting all other settings:
+ *
+ *	=> env import -d -t ${backup_addr}
+ */
+static int do_env_export(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	char	buf[32];
+	char	*addr, *cmd, *res;
+	size_t	size;
+	ssize_t	len;
+	env_t	*envp = (env_t *)addr;
+	char	sep = '\n';
+	int	chk = 0;
+	int	fmt = 0;
+
+	cmd = *argv;
+
+	while (--argc > 0 && **++argv == '-') {
+		char *arg = *argv;
+		while (*++arg) {
+			switch (*arg) {
+			case 'b':		/* raw binary format */
+				if (fmt++)
+					goto sep_err;
+				sep = '\0';
+				break;
+			case 'c':		/* external checksum format */
+				if (fmt++)
+					goto sep_err;
+				sep = '\0';
+				chk = 1;
+				break;
+			case 't':		/* text format */
+				if (fmt++)
+					goto sep_err;
+				sep = '\n';
+				break;
+			default:
+				cmd_usage(cmdtp);
+				return 1;
+			}
+		}
+	}
 
-/**************************************************/
+	if (argc < 1) {
+		cmd_usage(cmdtp);
+		return 1;
+	}
+
+	addr = (char *)simple_strtoul(argv[0], NULL, 16);
+
+	if (argc == 2) {
+		size = simple_strtoul(argv[1], NULL, 16);
+		memset(addr, '\0', size);
+	} else {
+		size = 0;
+	}
+
+	if (sep) {		/* export as text file */
+		len = hexport(sep, &addr, size);
+		if (len < 0) {
+			error("Cannot export environment: errno = %d\n",
+				errno);
+			return 1;
+		}
+		sprintf(buf, "%zX", len);
+		setenv("filesize", buf);
+
+		return 0;
+	}
+
+	if (chk) {		/* export as checksum protected block */
+		res = (char *)&envp->data;
+	} else {		/* export as raw binary data */
+		res = (char *)&addr;
+	}
+
+	len = hexport('\0', &res, ENV_SIZE);
+	if (len < 0) {
+		error("Cannot export environment: errno = %d\n",
+			errno);
+		return 1;
+	}
+
+	if (chk) {
+		envp->crc   = crc32(0, envp->data, ENV_SIZE);
+#ifdef CONFIG_ENV_ADDR_REDUND
+		envp->flags = ACTIVE_FLAG;
+#endif
+	}
+	sprintf(buf, "%zX", len + offsetof(env_t,data));
+	setenv("filesize", buf);
+
+	return 0;
+
+sep_err:
+	printf("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",
+		cmd);
+	return 1;
+}
+
+/*
+ * env import [-d] [-t | -b | -c] addr [size]
+ *	-d:	delete existing environment before importing;
+ *		otherwise overwrite / append to existion definitions
+ *	-t:	assume text format; either "size" must be given or the
+ *		text data must be '\0' terminated
+ *	-b:	assume binary format ('\0' separated, "\0\0" terminated)
+ *	-c:	assume checksum protected environment format
+ *	addr:	memory address to read from
+ *	size:	length of input data; if missing, proper '\0'
+ *		termination is mandatory
+ */
+static int do_env_import(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+{
+	char	*cmd, *addr;
+	char	sep = '\n';
+	int	chk = 0;
+	int	fmt = 0;
+	int	del = 0;
+	size_t	size;
+
+	cmd = *argv;
+
+	while (--argc > 0 && **++argv == '-') {
+		char *arg = *argv;
+		while (*++arg) {
+			switch (*arg) {
+			case 'b':		/* raw binary format */
+				if (fmt++)
+					goto sep_err;
+				sep = '\0';
+				break;
+			case 'c':		/* external checksum format */
+				if (fmt++)
+					goto sep_err;
+				sep = '\0';
+				chk = 1;
+				break;
+			case 't':		/* text format */
+				if (fmt++)
+					goto sep_err;
+				sep = '\n';
+				break;
+			case 'd':
+				del = 1;
+				break;
+			default:
+				cmd_usage(cmdtp);
+				return 1;
+			}
+		}
+	}
+
+	if (argc < 1) {
+		cmd_usage(cmdtp);
+		return 1;
+	}
+
+	if (!fmt)
+		printf("## Warning: defaulting to text format\n");
+
+	addr = (char *)simple_strtoul(argv[0], NULL, 16);
+
+	if (argc == 2) {
+		size = simple_strtoul(argv[1], NULL, 16);
+	} else {
+		char *s = addr;
+
+		size = 0;
+
+		while (size < MAX_ENV_SIZE) {
+			if ((*s == sep) && (*(s+1) == '\0'))
+				break;
+			++s;
+			++size;
+		}
+		if (size == MAX_ENV_SIZE) {
+			printf("## Warning: Input data exceeds %d bytes"
+				" - truncated\n", MAX_ENV_SIZE);
+		}
+		++size;
+		printf("## Info: input data size = %zd = 0x%zX\n", size, size);
+	}
+
+	if (chk) {
+		uint32_t crc;
+		env_t *ep = (env_t *)addr;
+
+		size -= offsetof(env_t, data);
+		memcpy(&crc, &ep->crc, sizeof(crc));
+
+		if (crc32(0, ep->data, size) != crc) {
+			puts("## Error: bad CRC, import failed\n");
+			return 1;
+		}
+		addr = (char *)ep->data;
+	}
+
+	if (himport(addr, size, sep, del ? 0 : H_NOCLEAR) == 0) {
+		error("Environment import failed: errno = %d\n", errno);
+		return 1;
+	}
+
+	return 0;
+
+sep_err:
+	printf("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",
+		cmd);
+	return 1;
+}
+
+#if defined(CONFIG_CMD_RUN)
+extern int do_run (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+#endif
+
+/*
+ * New command line interface: "env" command with subcommands
+ */
+static cmd_tbl_t cmd_env_sub[] = {
+#if defined(CONFIG_CMD_ASKENV)
+	U_BOOT_CMD_MKENT(ask, CONFIG_SYS_MAXARGS, 1, do_env_ask, "", ""),
+#endif
+	U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""),
+	U_BOOT_CMD_MKENT(delete, 2, 0, do_env_delete, "", ""),
+#if defined(CONFIG_CMD_EDITENV)
+	U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""),
+#endif
+	U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),
+	U_BOOT_CMD_MKENT(import, 5, 0, do_env_import, "", ""),
+	U_BOOT_CMD_MKENT(print, CONFIG_SYS_MAXARGS, 1, do_env_print, "", ""),
+#if defined(CONFIG_CMD_RUN)
+	U_BOOT_CMD_MKENT(run, CONFIG_SYS_MAXARGS, 1, do_run, "", ""),
+#endif
+#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
+	U_BOOT_CMD_MKENT(save, 1, 0, do_env_save, "", ""),
+#endif
+	U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 0, do_env_set, "", ""),
+};
+
+static int do_env (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	cmd_tbl_t *cp;
+
+	/* drop initial "env" arg */
+	argc--;
+	argv++;
+
+	cp = find_cmd_tbl(argv[0], cmd_env_sub, ARRAY_SIZE(cmd_env_sub));
+
+	if (cp)
+		return cp->cmd(cmdtp, flag, argc, argv);
+
+	cmd_usage(cmdtp);
+	return 1;
+}
+
+U_BOOT_CMD(
+	env, CONFIG_SYS_MAXARGS, 1, do_env,
+	"environment handling commands",
+#if defined(CONFIG_CMD_ASKENV)
+	"ask name [message] [size] - ask for environment variable\nenv "
+#endif
+	"default -f - reset default environment\n"
+#if defined(CONFIG_CMD_EDITENV)
+	"env edit name - edit environment variable\n"
+#endif
+	"env export [-t | -b | -c] addr [size] - export environmnt\n"
+	"env import [-d] [-t | -b | -c] addr [size] - import environmnt\n"
+	"env print [name ...] - print environment\n"
+#if defined(CONFIG_CMD_RUN)
+	"env run var [...] - run commands in an environment variable\n"
+#endif
+	"env save - save environment\n"
+	"env set [-f] name [arg ...]\n"
+);
+
+/*
+ * Old command line interface, kept for compatibility
+ */
 
 #if defined(CONFIG_CMD_EDITENV)
 U_BOOT_CMD(
-	editenv, 2, 0,	do_editenv,
+	editenv, 2, 0,	do_env_edit,
 	"edit environment variable",
 	"name\n"
 	"    - edit environment variable 'name'"
@@ -613,7 +875,7 @@ U_BOOT_CMD(
 #endif
 
 U_BOOT_CMD(
-	printenv, CONFIG_SYS_MAXARGS, 1,	do_printenv,
+	printenv, CONFIG_SYS_MAXARGS, 1,	do_env_print,
 	"print environment variables",
 	"\n    - print values of all environment variables\n"
 	"printenv name ...\n"
@@ -621,7 +883,7 @@ U_BOOT_CMD(
 );
 
 U_BOOT_CMD(
-	setenv, CONFIG_SYS_MAXARGS, 0,	do_setenv,
+	setenv, CONFIG_SYS_MAXARGS, 0,	do_env_set,
 	"set environment variables",
 	"name value ...\n"
 	"    - set environment variable 'name' to 'value ...'\n"
@@ -632,7 +894,7 @@ U_BOOT_CMD(
 #if defined(CONFIG_CMD_ASKENV)
 
 U_BOOT_CMD(
-	askenv,	CONFIG_SYS_MAXARGS,	1,	do_askenv,
+	askenv,	CONFIG_SYS_MAXARGS,	1,	do_env_ask,
 	"get environment variables from stdin",
 	"name [message] [size]\n"
 	"    - get environment variable 'name' from stdin (max 'size' chars)\n"
@@ -647,7 +909,6 @@ U_BOOT_CMD(
 #endif
 
 #if defined(CONFIG_CMD_RUN)
-int do_run (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 U_BOOT_CMD(
 	run,	CONFIG_SYS_MAXARGS,	1,	do_run,
 	"run commands in an environment variable",
diff --git a/common/command.c b/common/command.c
index a1fc592..b12a278 100644
--- a/common/command.c
+++ b/common/command.c
@@ -160,6 +160,7 @@ int cmd_usage(cmd_tbl_t *cmdtp)
 
 int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
 {
+#if 0 /* need to reimplement */
 	static char tmp_buf[512];
 	int space;
 
@@ -170,7 +171,7 @@ int var_complete(int argc, char * const argv[], char last_char, int maxv, char *
 
 	if (!space && argc == 2)
 		return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
-
+#endif
 	return 0;
 }
 
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index 2276532..ae5702d 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -222,7 +222,6 @@
 
 \f
 
-
 /* Preliminaries */
 
 #ifndef __STD_C
@@ -935,10 +934,10 @@ struct mallinfo mALLINFo();
 #endif
 
 /* ---------- To make a malloc.h, end cutting here ------------ */
-#else				/* Moved to malloc.h */
+#endif	/* 0 */			/* Moved to malloc.h */
 
 #include <malloc.h>
-#if 0
+#ifdef DEBUG
 #if __STD_C
 static void malloc_update_mallinfo (void);
 void malloc_stats (void);
@@ -946,9 +945,7 @@ void malloc_stats (void);
 static void malloc_update_mallinfo ();
 void malloc_stats();
 #endif
-#endif	/* 0 */
-
-#endif	/* 0 */			/* Moved to malloc.h */
+#endif	/* DEBUG */
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -1618,9 +1615,9 @@ static struct mallinfo current_mallinfo = {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
 /* Tracking mmaps */
 
-#if 0
+#ifdef DEBUG
 static unsigned int n_mmaps = 0;
-#endif	/* 0 */
+#endif	/* DEBUG */
 static unsigned long mmapped_mem = 0;
 #if HAVE_MMAP
 static unsigned int max_n_mmaps = 0;
@@ -3101,7 +3098,7 @@ size_t malloc_usable_size(mem) Void_t* mem;
 
 /* Utility to update current_mallinfo for malloc_stats and mallinfo() */
 
-#if 0
+#ifdef DEBUG
 static void malloc_update_mallinfo()
 {
   int i;
@@ -3139,7 +3136,7 @@ static void malloc_update_mallinfo()
   current_mallinfo.keepcost = chunksize(top);
 
 }
-#endif	/* 0 */
+#endif	/* DEBUG */
 
 \f
 
@@ -3158,7 +3155,7 @@ static void malloc_update_mallinfo()
 
 */
 
-#if 0
+#ifdef DEBUG
 void malloc_stats()
 {
   malloc_update_mallinfo();
@@ -3173,19 +3170,19 @@ void malloc_stats()
 	  (unsigned int)max_n_mmaps);
 #endif
 }
-#endif	/* 0 */
+#endif	/* DEBUG */
 
 /*
   mallinfo returns a copy of updated current mallinfo.
 */
 
-#if 0
+#ifdef DEBUG
 struct mallinfo mALLINFo()
 {
   malloc_update_mallinfo();
   return current_mallinfo;
 }
-#endif	/* 0 */
+#endif	/* DEBUG */
 
 
 \f
diff --git a/common/env_common.c b/common/env_common.c
index 460309b..c263ee5 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -1,10 +1,10 @@
 /*
- * (C) Copyright 2000-2002
+ * (C) Copyright 2000-2010
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
  *
  * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  * Andreas Heppel <aheppel@sysgo.de>
-
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -28,17 +28,12 @@
 #include <command.h>
 #include <environment.h>
 #include <linux/stddef.h>
+#include <search.h>
+#include <errno.h>
 #include <malloc.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#undef DEBUG_ENV
-#ifdef DEBUG_ENV
-#define DEBUGF(fmt,args...) printf(fmt ,##args)
-#else
-#define DEBUGF(fmt,args...)
-#endif
-
 extern env_t *env_ptr;
 
 extern void env_relocate_spec (void);
@@ -134,33 +129,22 @@ uchar default_environment[] = {
 	"\0"
 };
 
-void env_crc_update (void)
-{
-	env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);
-}
-
 static uchar env_get_char_init (int index)
 {
 	uchar c;
 
 	/* if crc was bad, use the default environment */
 	if (gd->env_valid)
-	{
 		c = env_get_char_spec(index);
-	} else {
+	else
 		c = default_environment[index];
-	}
 
 	return (c);
 }
 
 uchar env_get_char_memory (int index)
 {
-	if (gd->env_valid) {
-		return ( *((uchar *)(gd->env_addr + index)) );
-	} else {
-		return ( default_environment[index] );
-	}
+	return *env_get_addr(index);
 }
 
 uchar env_get_char (int index)
@@ -178,70 +162,81 @@ uchar env_get_char (int index)
 
 uchar *env_get_addr (int index)
 {
-	if (gd->env_valid) {
-		return ( ((uchar *)(gd->env_addr + index)) );
-	} else {
-		return (&default_environment[index]);
-	}
+	if (gd->env_valid)
+		return (uchar *)(gd->env_addr + index);
+	else
+		return &default_environment[index];
 }
 
-void set_default_env(void)
+void set_default_env(const char *s)
 {
 	if (sizeof(default_environment) > ENV_SIZE) {
-		puts ("*** Error - default environment is too large\n\n");
+		puts("*** Error - default environment is too large\n\n");
 		return;
 	}
 
-	memset(env_ptr, 0, sizeof(env_t));
-	memcpy(env_ptr->data, default_environment,
-	       sizeof(default_environment));
-#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
-	env_ptr->flags = 0xFF;
-#endif
-	env_crc_update ();
-	gd->env_valid = 1;
+	if (s) {
+		if (*s == '!') {
+			printf("*** Warning - %s, "
+				"using default environment\n\n",
+				s+1);
+		} else {
+			puts(s);
+		}
+	} else {
+		puts("Using default environment\n\n");
+	}
+
+	if (himport((char *)default_environment,
+		    sizeof(default_environment), '\0', 0) == 0) {
+		error("Environment import failed: errno = %d\n", errno);
+	}
 }
 
-void env_relocate (void)
+/*
+ * Check if CRC is valid and (if yes) import the environment.
+ * Note that "buf" may or may not be aligned.
+ */
+int env_import(const char *buf, int check)
 {
-#ifndef CONFIG_RELOC_FIXUP_WORKS
-	DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
-		gd->reloc_off);
-#endif
+	env_t *ep = (env_t *)buf;
 
-#ifdef ENV_IS_EMBEDDED
-	/*
-	 * The environment buffer is embedded with the text segment,
-	 * just relocate the environment pointer
-	 */
-#ifndef CONFIG_RELOC_FIXUP_WORKS
-	env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
-#endif
-	DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
-#else
-	/*
-	 * We must allocate a buffer for the environment
-	 */
-	env_ptr = (env_t *)malloc (CONFIG_ENV_SIZE);
-	DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
-#endif
+	if (check) {
+		uint32_t crc;
+
+		memcpy(&crc, &ep->crc, sizeof(crc));
 
+		if (crc32(0, ep->data, ENV_SIZE) != crc) {
+			set_default_env("!bad CRC");
+			return 0;
+		}
+	}
+
+	if (himport((char *)ep->data, ENV_SIZE, '\0', 0))
+		return 1;
+
+	error("Cannot import environment: errno = %d\n", errno);
+
+	set_default_env("!import failed");
+
+	return 0;
+}
+
+void env_relocate (void)
+{
 	if (gd->env_valid == 0) {
 #if defined(CONFIG_ENV_IS_NOWHERE)	/* Environment not changable */
-		puts ("Using default environment\n\n");
+		set_default_env(NULL);
 #else
-		puts ("*** Warning - bad CRC, using default environment\n\n");
 		show_boot_progress (-60);
 #endif
-		set_default_env();
-	}
-	else {
+		set_default_env("!bad CRC");
+	} else {
 		env_relocate_spec ();
 	}
-	gd->env_addr = (ulong)&(env_ptr->data);
 }
 
-#ifdef CONFIG_AUTO_COMPLETE
+#if 0 /* need to reimplement - def CONFIG_AUTO_COMPLETE */
 int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf)
 {
 	int i, nxt, len, vallen, found;
diff --git a/common/env_dataflash.c b/common/env_dataflash.c
index 27a3bbc..270f2b3 100644
--- a/common/env_dataflash.c
+++ b/common/env_dataflash.c
@@ -1,4 +1,5 @@
-/* LowLevel function for DataFlash environment support
+/*
+ * LowLevel function for DataFlash environment support
  * Author : Gilles Gastaldi (Atmel)
  *
  * This program is free software; you can redistribute it and/or
@@ -15,13 +16,14 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  * MA 02111-1307 USA
- *
  */
 #include <common.h>
 #include <command.h>
 #include <environment.h>
 #include <linux/stddef.h>
 #include <dataflash.h>
+#include <search.h>
+#include <errno.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -29,39 +31,59 @@ env_t *env_ptr = NULL;
 
 char * env_name_spec = "dataflash";
 
-extern int read_dataflash (unsigned long addr, unsigned long size, char
-*result);
-extern int write_dataflash (unsigned long addr_dest, unsigned long addr_src,
-		     unsigned long size);
-extern int AT91F_DataflashInit (void);
-extern uchar default_environment[];
+extern int read_dataflash(unsigned long addr, unsigned long size,
+	char *result);
+extern int write_dataflash(unsigned long addr_dest,
+	unsigned long addr_src, unsigned long size);
+extern int AT91F_DataflashInit(void);
 
+extern uchar default_environment[];
 
-uchar env_get_char_spec (int index)
+uchar env_get_char_spec(int index)
 {
 	uchar c;
+
 	read_dataflash(CONFIG_ENV_ADDR + index + offsetof(env_t,data),
-	1, (char *)&c);
+			1, (char *)&c);
 	return (c);
 }
 
-void env_relocate_spec (void)
+void env_relocate_spec(void)
 {
-	read_dataflash(CONFIG_ENV_ADDR, CONFIG_ENV_SIZE, (char *)env_ptr);
+	char buf[CONFIG_ENV_SIZE];
+
+	read_dataflash(CONFIG_ENV_ADDR, CONFIG_ENV_SIZE, buf);
+
+	env_import(buf, 1);
 }
 
+#ifdef CONFIG_ENV_OFFSET_REDUND
+#error No support for redundant environment on dataflash yet!
+#endif
+
 int saveenv(void)
 {
-	/* env must be copied to do not alter env structure in memory*/
-	unsigned char temp[CONFIG_ENV_SIZE];
-	memcpy(temp, env_ptr, CONFIG_ENV_SIZE);
-	return write_dataflash(CONFIG_ENV_ADDR, (unsigned long)temp, CONFIG_ENV_SIZE);
+	env_t	env_new;
+	ssize_t	len;
+	char	*res;
+
+	res = (char *)&env_new.data;
+	len = hexport('\0', &res, ENV_SIZE);
+	if (len < 0) {
+		error("Cannot export environment: errno = %d\n", errno);
+		return 1;
+	}
+	env_new.crc   = crc32(0, env_new.data, ENV_SIZE);
+
+	return write_dataflash(CONFIG_ENV_ADDR,
+				(unsigned long)&env_new,
+				CONFIG_ENV_SIZE);
 }
 
-/************************************************************************
- * Initialize Environment use
+/*
+ * Initialize environment use
  *
- * We are still running from ROM, so data use is limited
+ * We are still running from ROM, so data use is limited.
  * Use a (moderately small) buffer on the stack
  */
 int env_init(void)
@@ -69,30 +91,36 @@ int env_init(void)
 	ulong crc, len, new;
 	unsigned off;
 	uchar buf[64];
-	if (gd->env_valid == 0){
-		AT91F_DataflashInit();	/* prepare for DATAFLASH read/write */
-
-		/* read old CRC */
-		read_dataflash(CONFIG_ENV_ADDR + offsetof(env_t, crc),
-			sizeof(ulong), (char *)&crc);
-		new = 0;
-		len = ENV_SIZE;
-		off = offsetof(env_t,data);
-		while (len > 0) {
-			int n = (len > sizeof(buf)) ? sizeof(buf) : len;
-			read_dataflash(CONFIG_ENV_ADDR + off, n, (char *)buf);
-			new = crc32 (new, buf, n);
-			len -= n;
-			off += n;
-		}
-		if (crc == new) {
-			gd->env_addr  = offsetof(env_t,data);
-			gd->env_valid = 1;
-		} else {
-			gd->env_addr  = (ulong)&default_environment[0];
-			gd->env_valid = 0;
-		}
+
+	if (gd->env_valid)
+		return 0;
+
+	AT91F_DataflashInit();	/* prepare for DATAFLASH read/write */
+
+	/* read old CRC */
+	read_dataflash(CONFIG_ENV_ADDR + offsetof(env_t, crc),
+		sizeof(ulong), (char *)&crc);
+
+	new = 0;
+	len = ENV_SIZE;
+	off = offsetof(env_t,data);
+	while (len > 0) {
+		int n = (len > sizeof(buf)) ? sizeof(buf) : len;
+
+		read_dataflash(CONFIG_ENV_ADDR + off, n, (char *)buf);
+
+		new = crc32 (new, buf, n);
+		len -= n;
+		off += n;
+	}
+
+	if (crc == new) {
+		gd->env_addr  = offsetof(env_t,data);
+		gd->env_valid = 1;
+	} else {
+		gd->env_addr  = (ulong)&default_environment[0];
+		gd->env_valid = 0;
 	}
 
-	return (0);
+	return 0;
 }
diff --git a/common/env_eeprom.c b/common/env_eeprom.c
index 8fe59f8..792b44f 100644
--- a/common/env_eeprom.c
+++ b/common/env_eeprom.c
@@ -1,10 +1,10 @@
 /*
- * (C) Copyright 2000-2002
+ * (C) Copyright 2000-2010
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
  *
  * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  * Andreas Heppel <aheppel@sysgo.de>
-
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -31,16 +31,19 @@
 #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
 #include <i2c.h>
 #endif
+#include <search.h>
+#include <errno.h>
+#include <linux/compiler.h>	/* for BUG_ON */
 
 DECLARE_GLOBAL_DATA_PTR;
 
 env_t *env_ptr = NULL;
 
-char * env_name_spec = "EEPROM";
+char *env_name_spec = "EEPROM";
 int env_eeprom_bus = -1;
 
-static int eeprom_bus_read (unsigned dev_addr, unsigned offset, uchar *buffer,
-				unsigned cnt)
+static int eeprom_bus_read(unsigned dev_addr, unsigned offset,
+	uchar *buffer, unsigned cnt)
 {
 	int rcode;
 #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
@@ -51,9 +54,9 @@ static int eeprom_bus_read (unsigned dev_addr, unsigned offset, uchar *buffer,
 			I2C_MUX_DEVICE *dev = NULL;
 			dev = i2c_mux_ident_muxstring(
 				(uchar *)CONFIG_I2C_ENV_EEPROM_BUS);
-			if (dev != NULL) {
+			if (dev != NULL)
 				env_eeprom_bus = dev->busid;
-			} else
+			else
 				printf ("error adding env eeprom bus.\n");
 		}
 		if (old_bus != env_eeprom_bus) {
@@ -67,6 +70,7 @@ static int eeprom_bus_read (unsigned dev_addr, unsigned offset, uchar *buffer,
 #endif
 
 	rcode = eeprom_read (dev_addr, offset, buffer, cnt);
+
 #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
 	if (old_bus != env_eeprom_bus)
 		i2c_set_bus_num(old_bus);
@@ -74,8 +78,8 @@ static int eeprom_bus_read (unsigned dev_addr, unsigned offset, uchar *buffer,
 	return rcode;
 }
 
-static int eeprom_bus_write (unsigned dev_addr, unsigned offset, uchar *buffer,
-				unsigned cnt)
+static int eeprom_bus_write(unsigned dev_addr, unsigned offset,
+	uchar *buffer, unsigned cnt)
 {
 	int rcode;
 #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
@@ -83,7 +87,7 @@ static int eeprom_bus_write (unsigned dev_addr, unsigned offset, uchar *buffer,
 
 	rcode = i2c_mux_ident_muxstring_f((uchar *)CONFIG_I2C_ENV_EEPROM_BUS);
 #endif
-	rcode = eeprom_write (dev_addr, offset, buffer, cnt);
+	rcode = eeprom_write(dev_addr, offset, buffer, cnt);
 #if defined(CONFIG_I2C_ENV_EEPROM_BUS)
 	i2c_set_bus_num(old_bus);
 #endif
@@ -95,12 +99,12 @@ uchar env_get_char_spec (int index)
 	uchar c;
 	unsigned int off;
 	off = CONFIG_ENV_OFFSET;
+
 #ifdef CONFIG_ENV_OFFSET_REDUND
 	if (gd->env_valid == 2)
 		off = CONFIG_ENV_OFFSET_REDUND;
 #endif
-
-	eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
+	eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
 		     off + index + offsetof(env_t,data),
 		     &c, 1);
 
@@ -109,40 +113,60 @@ uchar env_get_char_spec (int index)
 
 void env_relocate_spec (void)
 {
+	char buf[CONFIG_ENV_SIZE];
 	unsigned int off = CONFIG_ENV_OFFSET;
+
 #ifdef CONFIG_ENV_OFFSET_REDUND
 	if (gd->env_valid == 2)
 		off = CONFIG_ENV_OFFSET_REDUND;
 #endif
-	eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
+	eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
 		     off,
-		     (uchar*)env_ptr,
+		     (uchar *)buf,
 		     CONFIG_ENV_SIZE);
+
+	env_import(buf, 1);
 }
 
 int saveenv(void)
 {
+	env_t	env_new;
+	ssize_t	len;
+	char	*res;
 	int rc;
 	unsigned int off = CONFIG_ENV_OFFSET;
 #ifdef CONFIG_ENV_OFFSET_REDUND
 	unsigned int off_red = CONFIG_ENV_OFFSET_REDUND;
 	char flag_obsolete = OBSOLETE_FLAG;
+#endif
+
+	BUG_ON(env_ptr != NULL);
+
+	res = (char *)&env_new.data;
+	len = hexport('\0', &res, ENV_SIZE);
+	if (len < 0) {
+		error("Cannot export environment: errno = %d\n", errno);
+		return 1;
+	}
+	env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
 	if (gd->env_valid == 1) {
 		off = CONFIG_ENV_OFFSET_REDUND;
 		off_red = CONFIG_ENV_OFFSET;
 	}
 
-	env_ptr->flags = ACTIVE_FLAG;
+	env_new.flags = ACTIVE_FLAG;
 #endif
 
-	rc = eeprom_bus_write (CONFIG_SYS_DEF_EEPROM_ADDR,
+	rc = eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
 			     off,
-			     (uchar *)env_ptr,
+			     (uchar *)&env_new,
 			     CONFIG_ENV_SIZE);
 
 #ifdef CONFIG_ENV_OFFSET_REDUND
 	if (rc == 0) {
-		eeprom_bus_write (CONFIG_SYS_DEF_EEPROM_ADDR,
+		eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
 				  off_red + offsetof(env_t,flags),
 				  (uchar *)&flag_obsolete,
 				  1);
@@ -157,10 +181,10 @@ int saveenv(void)
 	return rc;
 }
 
-/************************************************************************
+/*
  * Initialize Environment use
  *
- * We are still running from ROM, so data use is limited
+ * We are still running from ROM, so data use is limited.
  * Use a (moderately small) buffer on the stack
  */
 
@@ -175,31 +199,31 @@ int env_init(void)
 	unsigned char flags[2];
 	int i;
 
-	eeprom_init ();	/* prepare for EEPROM read/write */
+	eeprom_init();	/* prepare for EEPROM read/write */
 
 	off_env[0] = CONFIG_ENV_OFFSET;
 	off_env[1] = CONFIG_ENV_OFFSET_REDUND;
 
 	for (i = 0; i < 2; i++) {
 		/* read CRC */
-		eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
+		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
 			off_env[i] + offsetof(env_t,crc),
 			(uchar *)&crc[i], sizeof(ulong));
 		/* read FLAGS */
-		eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
+		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
 			off_env[i] + offsetof(env_t,flags),
 			(uchar *)&flags[i], sizeof(uchar));
 
-		crc_tmp= 0;
+		crc_tmp = 0;
 		len = ENV_SIZE;
 		off = off_env[i] + offsetof(env_t,data);
 		while (len > 0) {
 			int n = (len > sizeof(buf)) ? sizeof(buf) : len;
 
-			eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR, off,
+			eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR, off,
 				buf, n);
 
-			crc_tmp = crc32 (crc_tmp, buf, n);
+			crc_tmp = crc32(crc_tmp, buf, n);
 			len -= n;
 			off += n;
 		}
@@ -245,22 +269,23 @@ int env_init(void)
 	unsigned off;
 	uchar buf[64];
 
-	eeprom_init ();	/* prepare for EEPROM read/write */
+	eeprom_init();	/* prepare for EEPROM read/write */
 
 	/* read old CRC */
-	eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
+	eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
 		     CONFIG_ENV_OFFSET+offsetof(env_t,crc),
 		     (uchar *)&crc, sizeof(ulong));
 
 	new = 0;
 	len = ENV_SIZE;
 	off = offsetof(env_t,data);
+
 	while (len > 0) {
 		int n = (len > sizeof(buf)) ? sizeof(buf) : len;
 
-		eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
+		eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
 				CONFIG_ENV_OFFSET + off, buf, n);
-		new = crc32 (new, buf, n);
+		new = crc32(new, buf, n);
 		len -= n;
 		off += n;
 	}
diff --git a/common/env_flash.c b/common/env_flash.c
index 925c5a0..1da78b7 100644
--- a/common/env_flash.c
+++ b/common/env_flash.c
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2000-2002
+ * (C) Copyright 2000-2010
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
  *
  * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
@@ -31,6 +31,8 @@
 #include <environment.h>
 #include <linux/stddef.h>
 #include <malloc.h>
+#include <search.h>
+#include <errno.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -51,36 +53,38 @@ char * env_name_spec = "Flash";
 extern uchar environment[];
 env_t *env_ptr = (env_t *)(&environment[0]);
 
-#ifdef CMD_SAVEENV
-/* static env_t *flash_addr = (env_t *)(&environment[0]);-broken on ARM-wd-*/
 static env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR;
-#endif
 
 #else /* ! ENV_IS_EMBEDDED */
 
 env_t *env_ptr = (env_t *)CONFIG_ENV_ADDR;
-#ifdef CMD_SAVEENV
 static env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR;
-#endif
 
 #endif /* ENV_IS_EMBEDDED */
 
+#if defined(CMD_SAVEENV) || defined(CONFIG_ENV_ADDR_REDUND)
+/* CONFIG_ENV_ADDR is supposed to be on sector boundary */
+static ulong end_addr = CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1;
+#endif
+
 #ifdef CONFIG_ENV_ADDR_REDUND
 static env_t *flash_addr_new = (env_t *)CONFIG_ENV_ADDR_REDUND;
 
-/* CONFIG_ENV_ADDR is supposed to be on sector boundary */
-static ulong end_addr = CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1;
+/* CONFIG_ENV_ADDR_REDUND is supposed to be on sector boundary */
 static ulong end_addr_new = CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1;
 #endif /* CONFIG_ENV_ADDR_REDUND */
 
 extern uchar default_environment[];
 
 
-uchar env_get_char_spec (int index)
+uchar env_get_char_spec(int index)
 {
-	return ( *((uchar *)(gd->env_addr + index)) );
+	return (*((uchar *)(gd->env_addr + index)));
 }
 
+#undef debug
+#define debug printf
+
 #ifdef CONFIG_ENV_ADDR_REDUND
 
 int  env_init(void)
@@ -123,91 +127,97 @@ int  env_init(void)
 		gd->env_valid = 2;
 	}
 
-	return (0);
+	return 0;
 }
 
 #ifdef CMD_SAVEENV
 int saveenv(void)
 {
-	char *saved_data = NULL;
-	int rc = 1;
-	char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
+	env_t	env_new;
+	ssize_t	len;
+	char	*saved_data = NULL;
+	char	*res;
+	int	rc = 1;
+	char	flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
 #if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
-	ulong up_data = 0;
+	ulong	up_data = 0;
 #endif
 
-	debug ("Protect off %08lX ... %08lX\n",
+	debug("Protect off %08lX ... %08lX\n",
 		(ulong)flash_addr, end_addr);
 
-	if (flash_sect_protect (0, (ulong)flash_addr, end_addr)) {
-		goto Done;
+	if (flash_sect_protect(0, (ulong)flash_addr, end_addr)) {
+		goto done;
 	}
 
-	debug ("Protect off %08lX ... %08lX\n",
+	debug("Protect off %08lX ... %08lX\n",
 		(ulong)flash_addr_new, end_addr_new);
 
-	if (flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new)) {
-		goto Done;
+	if (flash_sect_protect(0, (ulong)flash_addr_new, end_addr_new)) {
+		goto done;
+	}
+
+	res = (char *)&env_new.data;
+	len = hexport('\0', &res, ENV_SIZE);
+	if (len < 0) {
+		error("Cannot export environment: errno = %d\n", errno);
+		goto done;
 	}
+	env_new.crc   = crc32(0, env_new.data, ENV_SIZE);
+	env_new.flags = new_flag;
 
 #if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
 	up_data = (end_addr_new + 1 - ((long)flash_addr_new + CONFIG_ENV_SIZE));
-	debug ("Data to save 0x%x\n", up_data);
+	debug("Data to save 0x%lX\n", up_data);
 	if (up_data) {
 		if ((saved_data = malloc(up_data)) == NULL) {
 			printf("Unable to save the rest of sector (%ld)\n",
 				up_data);
-			goto Done;
+			goto done;
 		}
 		memcpy(saved_data,
 			(void *)((long)flash_addr_new + CONFIG_ENV_SIZE), up_data);
-		debug ("Data (start 0x%x, len 0x%x) saved at 0x%x\n",
-			   (long)flash_addr_new + CONFIG_ENV_SIZE,
-				up_data, saved_data);
+		debug("Data (start 0x%lX, len 0x%lX) saved at 0x%p\n",
+			(long)flash_addr_new + CONFIG_ENV_SIZE,
+			up_data, saved_data);
 	}
 #endif
-	puts ("Erasing Flash...");
-	debug (" %08lX ... %08lX ...",
+	puts("Erasing Flash...");
+	debug(" %08lX ... %08lX ...",
 		(ulong)flash_addr_new, end_addr_new);
 
-	if (flash_sect_erase ((ulong)flash_addr_new, end_addr_new)) {
-		goto Done;
+	if (flash_sect_erase((ulong)flash_addr_new, end_addr_new)) {
+		goto done;
 	}
 
-	puts ("Writing to Flash... ");
-	debug (" %08lX ... %08lX ...",
+	puts("Writing to Flash... ");
+	debug(" %08lX ... %08lX ...",
 		(ulong)&(flash_addr_new->data),
 		sizeof(env_ptr->data)+(ulong)&(flash_addr_new->data));
-	if ((rc = flash_write((char *)env_ptr->data,
-			(ulong)&(flash_addr_new->data),
-			sizeof(env_ptr->data))) ||
-	    (rc = flash_write((char *)&(env_ptr->crc),
-			(ulong)&(flash_addr_new->crc),
-			sizeof(env_ptr->crc))) ||
+	if ((rc = flash_write((char *)&env_new,
+			(ulong)flash_addr_new,
+			sizeof(env_new))) ||
 	    (rc = flash_write(&flag,
 			(ulong)&(flash_addr->flags),
-			sizeof(flash_addr->flags))) ||
-	    (rc = flash_write(&new_flag,
-			(ulong)&(flash_addr_new->flags),
-			sizeof(flash_addr_new->flags))))
-	{
-		flash_perror (rc);
-		goto Done;
+			sizeof(flash_addr->flags))) ) {
+		flash_perror(rc);
+		goto done;
 	}
-	puts ("done\n");
 
 #if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
 	if (up_data) { /* restore the rest of sector */
-		debug ("Restoring the rest of data to 0x%x len 0x%x\n",
-			   (long)flash_addr_new + CONFIG_ENV_SIZE, up_data);
+		debug("Restoring the rest of data to 0x%lX len 0x%lX\n",
+			(long)flash_addr_new + CONFIG_ENV_SIZE, up_data);
 		if (flash_write(saved_data,
 				(long)flash_addr_new + CONFIG_ENV_SIZE,
 				up_data)) {
 			flash_perror(rc);
-			goto Done;
+			goto done;
 		}
 	}
 #endif
+	puts("done\n");
+
 	{
 		env_t * etmp = flash_addr;
 		ulong ltmp = end_addr;
@@ -220,13 +230,12 @@ int saveenv(void)
 	}
 
 	rc = 0;
-Done:
-
+done:
 	if (saved_data)
-		free (saved_data);
+		free(saved_data);
 	/* try to re-protect */
-	(void) flash_sect_protect (1, (ulong)flash_addr, end_addr);
-	(void) flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
+	(void) flash_sect_protect(1, (ulong)flash_addr, end_addr);
+	(void) flash_sect_protect(1, (ulong)flash_addr_new, end_addr_new);
 
 	return rc;
 }
@@ -244,83 +253,93 @@ int  env_init(void)
 
 	gd->env_addr  = (ulong)&default_environment[0];
 	gd->env_valid = 0;
-	return (0);
+	return 0;
 }
 
 #ifdef CMD_SAVEENV
 
 int saveenv(void)
 {
-	int	len, rc;
-	ulong	end_addr;
-	ulong	flash_sect_addr;
-#if defined(CONFIG_ENV_SECT_SIZE) && (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE)
-	ulong	flash_offset;
-	uchar	env_buffer[CONFIG_ENV_SECT_SIZE];
-#else
-	uchar *env_buffer = (uchar *)env_ptr;
-#endif	/* CONFIG_ENV_SECT_SIZE */
-	int rcode = 0;
-
-#if defined(CONFIG_ENV_SECT_SIZE) && (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE)
-
-	flash_offset    = ((ulong)flash_addr) & (CONFIG_ENV_SECT_SIZE-1);
-	flash_sect_addr = ((ulong)flash_addr) & ~(CONFIG_ENV_SECT_SIZE-1);
-
-	debug ( "copy old content: "
-		"sect_addr: %08lX  env_addr: %08lX  offset: %08lX\n",
-		flash_sect_addr, (ulong)flash_addr, flash_offset);
-
-	/* copy old contents to temporary buffer */
-	memcpy (env_buffer, (void *)flash_sect_addr, CONFIG_ENV_SECT_SIZE);
-
-	/* copy current environment to temporary buffer */
-	memcpy ((uchar *)((unsigned long)env_buffer + flash_offset),
-		env_ptr,
-		CONFIG_ENV_SIZE);
+	env_t	env_new;
+	ssize_t	len;
+	int	rc = 1;
+	char	*res;
+	char	*saved_data = NULL;
+#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
+	ulong	up_data = 0;
 
-	len	 = CONFIG_ENV_SECT_SIZE;
-#else
-	flash_sect_addr = (ulong)flash_addr;
-	len	 = CONFIG_ENV_SIZE;
+	up_data = (end_addr + 1 - ((long)flash_addr + CONFIG_ENV_SIZE));
+	debug("Data to save 0x%lx\n", up_data);
+	if (up_data) {
+		if ((saved_data = malloc(up_data)) == NULL) {
+			printf("Unable to save the rest of sector (%ld)\n",
+				up_data);
+			goto done;
+		}
+		memcpy(saved_data,
+			(void *)((long)flash_addr + CONFIG_ENV_SIZE), up_data);
+		debug("Data (start 0x%lx, len 0x%lx) saved at 0x%lx\n",
+			(ulong)flash_addr + CONFIG_ENV_SIZE,
+			up_data,
+			(ulong)saved_data);
+	}
 #endif	/* CONFIG_ENV_SECT_SIZE */
 
-	end_addr = flash_sect_addr + len - 1;
+	debug("Protect off %08lX ... %08lX\n",
+		(ulong)flash_addr, end_addr);
 
-	debug ("Protect off %08lX ... %08lX\n",
-		(ulong)flash_sect_addr, end_addr);
+	if (flash_sect_protect(0, (long)flash_addr, end_addr))
+		goto done;
 
-	if (flash_sect_protect (0, flash_sect_addr, end_addr))
-		return 1;
+	res = (char *)&env_new.data;
+	len = hexport('\0', &res, ENV_SIZE);
+	if (len < 0) {
+		error("Cannot export environment: errno = %d\n", errno);
+		goto done;
+	}
+	env_new.crc = crc32(0, env_new.data, ENV_SIZE);
 
-	puts ("Erasing Flash...");
-	if (flash_sect_erase (flash_sect_addr, end_addr))
-		return 1;
+	puts("Erasing Flash...");
+	if (flash_sect_erase((long)flash_addr, end_addr))
+		goto done;
 
-	puts ("Writing to Flash... ");
-	rc = flash_write((char *)env_buffer, flash_sect_addr, len);
+	puts("Writing to Flash... ");
+	rc = flash_write((char *)&env_new, (long)flash_addr, CONFIG_ENV_SIZE);
 	if (rc != 0) {
-		flash_perror (rc);
-		rcode = 1;
-	} else {
-		puts ("done\n");
+		flash_perror(rc);
+		goto done;
 	}
-
+#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
+	if (up_data) {	/* restore the rest of sector */
+		debug("Restoring the rest of data to 0x%lx len 0x%lx\n",
+			(ulong)flash_addr + CONFIG_ENV_SIZE, up_data);
+		if (flash_write(saved_data,
+				(long)flash_addr + CONFIG_ENV_SIZE,
+				up_data)) {
+			flash_perror(rc);
+			goto done;
+		}
+	}
+#endif
+	puts("done\n");
+	rc = 0;
+done:
+	if (saved_data)
+		free(saved_data);
 	/* try to re-protect */
-	(void) flash_sect_protect (1, flash_sect_addr, end_addr);
-	return rcode;
+	(void) flash_sect_protect(1, (long)flash_addr, end_addr);
+	return rc;
 }
 
 #endif /* CMD_SAVEENV */
 
 #endif /* CONFIG_ENV_ADDR_REDUND */
 
-void env_relocate_spec (void)
+void env_relocate_spec(void)
 {
-#if !defined(ENV_IS_EMBEDDED) || defined(CONFIG_ENV_ADDR_REDUND)
 #ifdef CONFIG_ENV_ADDR_REDUND
 	if (gd->env_addr != (ulong)&(flash_addr->data)) {
-		env_t * etmp = flash_addr;
+		env_t *etmp = flash_addr;
 		ulong ltmp = end_addr;
 
 		flash_addr = flash_addr_new;
@@ -336,11 +355,11 @@ void env_relocate_spec (void)
 		char flag = OBSOLETE_FLAG;
 
 		gd->env_valid = 2;
-		flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new);
+		flash_sect_protect(0, (ulong)flash_addr_new, end_addr_new);
 		flash_write(&flag,
 			    (ulong)&(flash_addr_new->flags),
 			    sizeof(flash_addr_new->flags));
-		flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
+		flash_sect_protect(1, (ulong)flash_addr_new, end_addr_new);
 	}
 
 	if (flash_addr->flags != ACTIVE_FLAG &&
@@ -348,19 +367,17 @@ void env_relocate_spec (void)
 		char flag = ACTIVE_FLAG;
 
 		gd->env_valid = 2;
-		flash_sect_protect (0, (ulong)flash_addr, end_addr);
+		flash_sect_protect(0, (ulong)flash_addr, end_addr);
 		flash_write(&flag,
 			    (ulong)&(flash_addr->flags),
 			    sizeof(flash_addr->flags));
-		flash_sect_protect (1, (ulong)flash_addr, end_addr);
+		flash_sect_protect(1, (ulong)flash_addr, end_addr);
 	}
 
 	if (gd->env_valid == 2)
 		puts ("*** Warning - some problems detected "
 		      "reading environment; recovered successfully\n\n");
 #endif /* CONFIG_ENV_ADDR_REDUND */
-#ifdef CMD_SAVEENV
-	memcpy (env_ptr, (void*)flash_addr, CONFIG_ENV_SIZE);
-#endif
-#endif /* ! ENV_IS_EMBEDDED || CONFIG_ENV_ADDR_REDUND */
+
+	env_import((char *)flash_addr, 1);
 }
diff --git a/common/env_mgdisk.c b/common/env_mgdisk.c
index b9de1ed..a69923b 100644
--- a/common/env_mgdisk.c
+++ b/common/env_mgdisk.c
@@ -30,7 +30,7 @@
 /* references to names in env_common.c */
 extern uchar default_environment[];
 
-char * env_name_spec = "MG_DISK";
+char *env_name_spec = "MG_DISK";
 
 env_t *env_ptr = 0;
 
@@ -38,34 +38,27 @@ DECLARE_GLOBAL_DATA_PTR;
 
 uchar env_get_char_spec(int index)
 {
-	return (*((uchar *) (gd->env_addr + index)));
+	return (*((uchar *)(gd->env_addr + index)));
 }
 
 void env_relocate_spec(void)
 {
-	unsigned int err;
+	char buf[CONFIG_ENV_SIZE];
+	unsigned int err, rc;
 
 	err = mg_disk_init();
 	if (err) {
-		puts ("*** Warning - mg_disk_init error");
-		goto OUT;
-	}
-	err = mg_disk_read(CONFIG_ENV_ADDR, (u_char *)env_ptr, CONFIG_ENV_SIZE);
-	if (err) {
-		puts ("*** Warning - mg_disk_read error");
-		goto OUT;
+		set_default_env("!mg_disk_init error");
+		return;
 	}
 
-	if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc) {
-		puts ("*** Warning - CRC error");
-		goto OUT;
+	err = mg_disk_read(CONFIG_ENV_ADDR, buf, CONFIG_ENV_SIZE);
+	if (err) {
+		set_default_env("!mg_disk_read error");
+		return;
 	}
 
-	return;
-
-OUT:
-	printf (", using default environment\n\n");
-	set_default_env();
+	env_import(buf, 1);
 }
 
 int saveenv(void)
@@ -76,7 +69,7 @@ int saveenv(void)
 	err = mg_disk_write(CONFIG_ENV_ADDR, (u_char *)env_ptr,
 			CONFIG_ENV_SIZE);
 	if (err)
-		puts ("*** Warning - mg_disk_write error\n\n");
+		puts("*** Warning - mg_disk_write error\n\n");
 
 	return err;
 }
@@ -84,7 +77,7 @@ int saveenv(void)
 int env_init(void)
 {
 	/* use default */
-	gd->env_addr = (ulong) & default_environment[0];
+	gd->env_addr = (ulong)&default_environment[0];
 	gd->env_valid = 1;
 
 	return 0;
diff --git a/common/env_nand.c b/common/env_nand.c
index a5e1038..ab91594 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -1,16 +1,16 @@
 /*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
  * (C) Copyright 2008
  * Stuart Wood, Lab X Technologies <stuart.wood@labxtechnologies.com>
  *
  * (C) Copyright 2004
  * Jian Zhang, Texas Instruments, jzhang at ti.com.
-
- * (C) Copyright 2000-2006
- * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
  *
  * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  * Andreas Heppel <aheppel@sysgo.de>
-
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -30,7 +30,7 @@
  * MA 02111-1307 USA
  */
 
-/* #define DEBUG */
+#define DEBUG
 
 #include <common.h>
 #include <command.h>
@@ -38,7 +38,8 @@
 #include <linux/stddef.h>
 #include <malloc.h>
 #include <nand.h>
-#include <asm/errno.h>
+#include <search.h>
+#include <errno.h>
 
 #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)
 #define CMD_SAVEENV
@@ -57,7 +58,7 @@
 /* references to names in env_common.c */
 extern uchar default_environment[];
 
-char * env_name_spec = "NAND";
+char *env_name_spec = "NAND";
 
 
 #if defined(ENV_IS_EMBEDDED)
@@ -69,12 +70,6 @@ env_t *env_ptr = (env_t *)CONFIG_NAND_ENV_DST;
 env_t *env_ptr = 0;
 #endif /* ENV_IS_EMBEDDED */
 
-
-/* local functions */
-#if !defined(ENV_IS_EMBEDDED)
-static void use_default(void);
-#endif
-
 DECLARE_GLOBAL_DATA_PTR;
 
 uchar env_get_char_spec (int index)
@@ -82,17 +77,17 @@ uchar env_get_char_spec (int index)
 	return ( *((uchar *)(gd->env_addr + index)) );
 }
 
-
-/* this is called before nand_init()
- * so we can't read Nand to validate env data.
- * Mark it OK for now. env_relocate() in env_common.c
- * will call our relocate function which does the real
- * validation.
+/*
+ * This is called before nand_init() so we can't read NAND to
+ * validate env data.
+ *
+ * Mark it OK for now. env_relocate() in env_common.c will call our
+ * relocate function which does the real validation.
  *
  * When using a NAND boot image (like sequoia_nand), the environment
- * can be embedded or attached to the U-Boot image in NAND flash. This way
- * the SPL loads not only the U-Boot image from NAND but also the
- * environment.
+ * can be embedded or attached to the U-Boot image in NAND flash.
+ * This way the SPL loads not only the U-Boot image from NAND but
+ * also the environment.
  */
 int env_init(void)
 {
@@ -189,11 +184,12 @@ int writeenv(size_t offset, u_char *buf)
 #ifdef CONFIG_ENV_OFFSET_REDUND
 int saveenv(void)
 {
-	int ret = 0;
+	env_t	env_new;
+	ssize_t	len;
+	char	*res;
+	int	ret = 0;
 	nand_erase_options_t nand_erase_options;
 
-	env_ptr->flags++;
-
 	nand_erase_options.length = CONFIG_ENV_RANGE;
 	nand_erase_options.quiet = 0;
 	nand_erase_options.jffs2 = 0;
@@ -201,36 +197,53 @@ int saveenv(void)
 
 	if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
 		return 1;
+
+	res = (char *)&env_new.data;
+	len = hexport('\0', &res, ENV_SIZE);
+	if (len < 0) {
+		error("Cannot export environment: errno = %d\n", errno);
+		return 1;
+	}
+	env_new.crc   = crc32(0, env_new.data, ENV_SIZE);
+	env_new.flags = ACTIVE_FLAG;
+
 	if(gd->env_valid == 1) {
-		puts ("Erasing redundant Nand...\n");
+		puts("Erasing redundant NAND...\n");
 		nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND;
 		if (nand_erase_opts(&nand_info[0], &nand_erase_options))
 			return 1;
 
-		puts ("Writing to redundant Nand... ");
-		ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) env_ptr);
+		puts("Writing to redundant NAND... ");
+		ret = writeenv(CONFIG_ENV_OFFSET_REDUND,
+			(u_char *)&env_new);
 	} else {
-		puts ("Erasing Nand...\n");
+		puts("Erasing NAND...\n");
 		nand_erase_options.offset = CONFIG_ENV_OFFSET;
 		if (nand_erase_opts(&nand_info[0], &nand_erase_options))
 			return 1;
 
-		puts ("Writing to Nand... ");
-		ret = writeenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);
+		puts("Writing to NAND... ");
+		ret = writeenv(CONFIG_ENV_OFFSET,
+			(u_char *)&env_new);
 	}
 	if (ret) {
 		puts("FAILED!\n");
 		return 1;
 	}
 
-	puts ("done\n");
+	puts("done\n");
+
 	gd->env_valid = (gd->env_valid == 2 ? 1 : 2);
+
 	return ret;
 }
 #else /* ! CONFIG_ENV_OFFSET_REDUND */
 int saveenv(void)
 {
 	int ret = 0;
+	env_t	env_new;
+	ssize_t	len;
+	char	*res;
 	nand_erase_options_t nand_erase_options;
 
 	nand_erase_options.length = CONFIG_ENV_RANGE;
@@ -241,23 +254,32 @@ int saveenv(void)
 
 	if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
 		return 1;
-	puts ("Erasing Nand...\n");
+
+	res = (char *)&env_new.data;
+	len = hexport('\0', &res, ENV_SIZE);
+	if (len < 0) {
+		error("Cannot export environment: errno = %d\n", errno);
+		return 1;
+	}
+	env_new.crc   = crc32(0, env_new.data, ENV_SIZE);
+
+	puts("Erasing Nand...\n");
 	if (nand_erase_opts(&nand_info[0], &nand_erase_options))
 		return 1;
 
-	puts ("Writing to Nand... ");
-	if (writeenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr)) {
+	puts("Writing to Nand... ");
+	if (writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new)) {
 		puts("FAILED!\n");
 		return 1;
 	}
 
-	puts ("done\n");
+	puts("done\n");
 	return ret;
 }
 #endif /* CONFIG_ENV_OFFSET_REDUND */
 #endif /* CMD_SAVEENV */
 
-int readenv (size_t offset, u_char * buf)
+int readenv(size_t offset, u_char * buf)
 {
 	size_t end = offset + CONFIG_ENV_RANGE;
 	size_t amount_loaded = 0;
@@ -318,47 +340,50 @@ int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
 #endif
 
 #ifdef CONFIG_ENV_OFFSET_REDUND
-void env_relocate_spec (void)
+void env_relocate_spec(void)
 {
 #if !defined(ENV_IS_EMBEDDED)
 	int crc1_ok = 0, crc2_ok = 0;
-	env_t *tmp_env1, *tmp_env2;
+	env_t *ep, *tmp_env1, *tmp_env2;
 
-	tmp_env1 = (env_t *) malloc(CONFIG_ENV_SIZE);
-	tmp_env2 = (env_t *) malloc(CONFIG_ENV_SIZE);
+	tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
+	tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
 
 	if ((tmp_env1 == NULL) || (tmp_env2 == NULL)) {
 		puts("Can't allocate buffers for environment\n");
-		free (tmp_env1);
-		free (tmp_env2);
-		return use_default();
+		free(tmp_env1);
+		free(tmp_env2);
+		set_default_env("!malloc() failed");
+		return;
 	}
 
 	if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1))
-		puts("No Valid Environment Area Found\n");
+		puts("No Valid Environment Area found\n");
+
 	if (readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2))
-		puts("No Valid Reundant Environment Area Found\n");
+		puts("No Valid Redundant Environment Area found\n");
 
 	crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
 	crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
 
-	if(!crc1_ok && !crc2_ok) {
+	if (!crc1_ok && !crc2_ok) {
 		free(tmp_env1);
 		free(tmp_env2);
-		return use_default();
-	} else if(crc1_ok && !crc2_ok)
+		set_default_env("!bad CRC");
+		return;
+	} else if (crc1_ok && !crc2_ok) {
 		gd->env_valid = 1;
-	else if(!crc1_ok && crc2_ok)
+	} else if (!crc1_ok && crc2_ok) {
 		gd->env_valid = 2;
-	else {
+	} else {
 		/* both ok - check serial */
-		if(tmp_env1->flags == 255 && tmp_env2->flags == 0)
+		if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
 			gd->env_valid = 2;
-		else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)
+		else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
 			gd->env_valid = 1;
-		else if(tmp_env1->flags > tmp_env2->flags)
+		else if (tmp_env1->flags > tmp_env2->flags)
 			gd->env_valid = 1;
-		else if(tmp_env2->flags > tmp_env1->flags)
+		else if (tmp_env2->flags > tmp_env1->flags)
 			gd->env_valid = 2;
 		else /* flags are equal - almost impossible */
 			gd->env_valid = 1;
@@ -366,51 +391,52 @@ void env_relocate_spec (void)
 	}
 
 	free(env_ptr);
-	if(gd->env_valid == 1) {
-		env_ptr = tmp_env1;
-		free(tmp_env2);
-	} else {
-		env_ptr = tmp_env2;
-		free(tmp_env1);
-	}
+
+	if (gd->env_valid == 1)
+		ep = tmp_env1;
+	else
+		ep = tmp_env2;
+
+	env_import((char *)ep, 0);
+
+	free(tmp_env1);
+	free(tmp_env2);
 
 #endif /* ! ENV_IS_EMBEDDED */
 }
 #else /* ! CONFIG_ENV_OFFSET_REDUND */
 /*
- * The legacy NAND code saved the environment in the first NAND device i.e.,
- * nand_dev_desc + 0. This is also the behaviour using the new NAND code.
+ * The legacy NAND code saved the environment in the first NAND
+ * device i.e., nand_dev_desc + 0. This is also the behaviour using
+ * the new NAND code.
  */
 void env_relocate_spec (void)
 {
 #if !defined(ENV_IS_EMBEDDED)
 	int ret;
+	char buf[CONFIG_ENV_SIZE];
 
 #if defined(CONFIG_ENV_OFFSET_OOB)
 	ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
-	/* If unable to read environment offset from NAND OOB then fall through
+	/*
+	 * If unable to read environment offset from NAND OOB then fall through
 	 * to the normal environment reading code below
 	 */
-	if (!ret)
+	if (!ret) {
 		printf("Found Environment offset in OOB..\n");
-	else
-		return use_default();
+	} else {
+		set_default_env("!no env offset in OOB");
+		return;
+	}
 #endif
 
-	ret = readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);
-	if (ret)
-		return use_default();
+	ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
+	if (ret) {
+		set_default_env("!readenv() failed");
+		return;
+	}
 
-	if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
-		return use_default();
+	env_import(buf, 1);
 #endif /* ! ENV_IS_EMBEDDED */
 }
 #endif /* CONFIG_ENV_OFFSET_REDUND */
-
-#if !defined(ENV_IS_EMBEDDED)
-static void use_default()
-{
-	puts ("*** Warning - bad CRC or NAND, using default environment\n\n");
-	set_default_env();
-}
-#endif
diff --git a/common/env_nowhere.c b/common/env_nowhere.c
index ccc068b..75ef78d 100644
--- a/common/env_nowhere.c
+++ b/common/env_nowhere.c
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2000-2002
+ * (C) Copyright 2000-2010
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
  *
  * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
@@ -35,22 +35,21 @@ env_t *env_ptr = NULL;
 
 extern uchar default_environment[];
 
-
-void env_relocate_spec (void)
+void env_relocate_spec(void)
 {
 }
 
-uchar env_get_char_spec (int index)
+uchar env_get_char_spec(int index)
 {
 	return ( *((uchar *)(gd->env_addr + index)) );
 }
 
-/************************************************************************
+/*
  * Initialize Environment use
  *
  * We are still running from ROM, so data use is limited
  */
-int  env_init(void)
+int env_init(void)
 {
 	gd->env_addr  = (ulong)&default_environment[0];
 	gd->env_valid = 0;
diff --git a/common/env_nvram.c b/common/env_nvram.c
index 7c7cf98..6e90f2b 100644
--- a/common/env_nvram.c
+++ b/common/env_nvram.c
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2000-2002
+ * (C) Copyright 2000-2010
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
  *
  * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
@@ -44,6 +44,8 @@
 #include <command.h>
 #include <environment.h>
 #include <linux/stddef.h>
+#include <search.h>
+#include <errno.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -59,7 +61,7 @@ char * env_name_spec = "NVRAM";
 
 extern uchar default_environment[];
 
-uchar env_get_char_spec (int index)
+uchar env_get_char_spec(int index)
 {
 #ifdef CONFIG_SYS_NVRAM_ACCESS_ROUTINE
 	uchar c;
@@ -72,40 +74,56 @@ uchar env_get_char_spec (int index)
 #endif
 }
 
-void env_relocate_spec (void)
+void env_relocate_spec(void)
 {
+	char buf[CONFIG_ENV_SIZE];
+
 #if defined(CONFIG_SYS_NVRAM_ACCESS_ROUTINE)
-	nvram_read(env_ptr, CONFIG_ENV_ADDR, CONFIG_ENV_SIZE);
+	nvram_read(buf, CONFIG_ENV_ADDR, CONFIG_ENV_SIZE);
 #else
-	memcpy (env_ptr, (void*)CONFIG_ENV_ADDR, CONFIG_ENV_SIZE);
+	memcpy(buf, (void*)CONFIG_ENV_ADDR, CONFIG_ENV_SIZE);
 #endif
+	env_import(buf, 1);
 }
 
-int saveenv (void)
+int saveenv(void)
 {
-	int rcode = 0;
+	env_t	env_new;
+	ssize_t	len;
+	char	*res;
+	int	rcode = 0;
+
+	res = (char *)&env_new.data;
+	len = hexport('\0', &res, ENV_SIZE);
+	if (len < 0) {
+		error("Cannot export environment: errno = %d\n", errno);
+		return 1;
+	}
+	env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+
 #ifdef CONFIG_SYS_NVRAM_ACCESS_ROUTINE
-	nvram_write(CONFIG_ENV_ADDR, env_ptr, CONFIG_ENV_SIZE);
+	nvram_write(CONFIG_ENV_ADDR, &env_new, CONFIG_ENV_SIZE);
 #else
-	if (memcpy ((char *)CONFIG_ENV_ADDR, env_ptr, CONFIG_ENV_SIZE) == NULL)
-		    rcode = 1 ;
+	if (memcpy((char *)CONFIG_ENV_ADDR, &env_new, CONFIG_ENV_SIZE) == NULL)
+		rcode = 1;
 #endif
 	return rcode;
 }
 
 
-/************************************************************************
+/*
  * Initialize Environment use
  *
  * We are still running from ROM, so data use is limited
  */
-int env_init (void)
+int env_init(void)
 {
 #if defined(CONFIG_SYS_NVRAM_ACCESS_ROUTINE)
 	ulong crc;
 	uchar data[ENV_SIZE];
-	nvram_read (&crc, CONFIG_ENV_ADDR, sizeof(ulong));
-	nvram_read (data, CONFIG_ENV_ADDR+sizeof(ulong), ENV_SIZE);
+
+	nvram_read(&crc, CONFIG_ENV_ADDR, sizeof(ulong));
+	nvram_read(data, CONFIG_ENV_ADDR+sizeof(ulong), ENV_SIZE);
 
 	if (crc32(0, data, ENV_SIZE) == crc) {
 		gd->env_addr  = (ulong)CONFIG_ENV_ADDR + sizeof(long);
diff --git a/common/env_onenand.c b/common/env_onenand.c
index cf997bf..02cb535 100644
--- a/common/env_onenand.c
+++ b/common/env_onenand.c
@@ -1,4 +1,7 @@
 /*
+ * (C) Copyright 2010 DENX Software Engineering
+ * Wolfgang Denk <wd@denx.de>
+ *
  * (C) Copyright 2005-2009 Samsung Electronics
  * Kyungmin Park <kyungmin.park@samsung.com>
  *
@@ -26,6 +29,8 @@
 #include <environment.h>
 #include <linux/stddef.h>
 #include <malloc.h>
+#include <search.h>
+#include <errno.h>
 
 #include <linux/mtd/compat.h>
 #include <linux/mtd/mtd.h>
@@ -44,17 +49,13 @@ char *env_name_spec = "OneNAND";
 
 #ifdef ENV_IS_EMBEDDED
 extern uchar environment[];
-env_t *env_ptr = (env_t *) (&environment[0]);
-#else /* ! ENV_IS_EMBEDDED */
-static unsigned char onenand_env[ONENAND_MAX_ENV_SIZE];
-env_t *env_ptr = (env_t *) onenand_env;
 #endif /* ENV_IS_EMBEDDED */
 
 DECLARE_GLOBAL_DATA_PTR;
 
 uchar env_get_char_spec(int index)
 {
-	return (*((uchar *) (gd->env_addr + index)));
+	return (*((uchar *)(gd->env_addr + index)));
 }
 
 void env_relocate_spec(void)
@@ -63,48 +64,57 @@ void env_relocate_spec(void)
 #ifdef CONFIG_ENV_ADDR_FLEX
 	struct onenand_chip *this = &onenand_chip;
 #endif
-	loff_t env_addr;
-	int use_default = 0;
+	int rc;
 	size_t retlen;
+#ifdef ENV_IS_EMBEDDED
+	char *buf = (char *)&environment[0];
+#else
+	loff_t env_addr = CONFIG_ENV_ADDR;
+	char onenand_env[ONENAND_MAX_ENV_SIZE];
+	char *buf = (char *)&onenand_env[0];
+#endif /* ENV_IS_EMBEDDED */
 
-	env_addr = CONFIG_ENV_ADDR;
-#ifdef CONFIG_ENV_ADDR_FLEX
+#ifndef ENV_IS_EMBEDDED
+# ifdef CONFIG_ENV_ADDR_FLEX
 	if (FLEXONENAND(this))
 		env_addr = CONFIG_ENV_ADDR_FLEX;
-#endif
+# endif
 	/* Check OneNAND exist */
 	if (mtd->writesize)
 		/* Ignore read fail */
 		mtd->read(mtd, env_addr, ONENAND_MAX_ENV_SIZE,
-			     &retlen, (u_char *) env_ptr);
+			     &retlen, (u_char *)buf);
 	else
 		mtd->writesize = MAX_ONENAND_PAGESIZE;
+#endif /* !ENV_IS_EMBEDDED */
 
-	if (crc32(0, env_ptr->data, ONENAND_ENV_SIZE(mtd)) != env_ptr->crc)
-		use_default = 1;
-
-	if (use_default) {
-		memcpy(env_ptr->data, default_environment,
-		       ONENAND_ENV_SIZE(mtd));
-		env_ptr->crc =
-		    crc32(0, env_ptr->data, ONENAND_ENV_SIZE(mtd));
-	}
-
-	gd->env_addr = (ulong) & env_ptr->data;
-	gd->env_valid = 1;
+	rc = env_import(buf, 1);
+	if (rc)
+		gd->env_valid = 1;
 }
 
 int saveenv(void)
 {
+	env_t	env_new;
+	ssize_t	len;
+	char	*res;
 	struct mtd_info *mtd = &onenand_mtd;
 #ifdef CONFIG_ENV_ADDR_FLEX
 	struct onenand_chip *this = &onenand_chip;
 #endif
-	loff_t env_addr = CONFIG_ENV_ADDR;
+	loff_t	env_addr = CONFIG_ENV_ADDR;
+	size_t	retlen;
 	struct erase_info instr = {
 		.callback	= NULL,
 	};
-	size_t retlen;
+
+	res = (char *)&env_new.data;
+	len = hexport('\0', &res, ENV_SIZE);
+	if (len < 0) {
+		error("Cannot export environment: errno = %d\n", errno);
+		return 1;
+	}
+	env_new.crc = crc32(0, env_new.data, ENV_SIZE);
 
 	instr.len = CONFIG_ENV_SIZE;
 #ifdef CONFIG_ENV_ADDR_FLEX
@@ -122,11 +132,8 @@ int saveenv(void)
 		return 1;
 	}
 
-	/* update crc */
-	env_ptr->crc = crc32(0, env_ptr->data, ONENAND_ENV_SIZE(mtd));
-
 	if (mtd->write(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen,
-	     (u_char *) env_ptr)) {
+	     (u_char *)&env_new)) {
 		printf("OneNAND: write failed at 0x%llx\n", instr.addr);
 		return 2;
 	}
diff --git a/common/env_sf.c b/common/env_sf.c
index 4391d61..fb0c39b 100644
--- a/common/env_sf.c
+++ b/common/env_sf.c
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2000-2002
+ * (C) Copyright 2000-2010
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
  *
  * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
@@ -29,6 +29,8 @@
 #include <environment.h>
 #include <malloc.h>
 #include <spi_flash.h>
+#include <search.h>
+#include <errno.h>
 
 #ifndef CONFIG_ENV_SPI_BUS
 # define CONFIG_ENV_SPI_BUS	0
@@ -77,17 +79,29 @@ void swap_env(void)
 
 int saveenv(void)
 {
-	u32 saved_size, saved_offset;
-	char *saved_buffer = NULL;
-	u32 sector = 1;
-	int ret;
-	char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
+	env_t	env_new;
+	ssize_t	len;
+	char	*res;
+	u32	saved_size, saved_offset;
+	char	*saved_buffer = NULL;
+	u32	sector = 1;
+	int	ret;
+	char	flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
 
 	if (!env_flash) {
 		puts("Environment SPI flash not initialized\n");
 		return 1;
 	}
 
+	res = (char *)&env_new.data;
+	len = hexport('\0', &res, ENV_SIZE);
+	if (len < 0) {
+		error("Cannot export environment: errno = %d\n", errno);
+		return 1;
+	}
+	env_new.crc   = crc32(0, env_new.data, ENV_SIZE);
+	env_new.flags = ACTIVE_FLAG;
+
 	/* Is the sector larger than the env (i.e. embedded) */
 	if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
 		saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE;
@@ -118,25 +132,25 @@ int saveenv(void)
 	puts("Writing to SPI flash...");
 	ret = spi_flash_write(env_flash,
 		env_new_offset + offsetof(env_t, data),
-		sizeof(env_ptr->data), env_ptr->data);
+		sizeof(env_new.data), env_new.data);
 	if (ret)
 		goto done;
 
 	ret = spi_flash_write(env_flash,
 		env_new_offset + offsetof(env_t, crc),
-		sizeof(env_ptr->crc), &env_ptr->crc);
+		sizeof(env_new.crc), &env_new.crc);
 	if (ret)
 		goto done;
 
 	ret = spi_flash_write(env_flash,
 		env_offset + offsetof(env_t, flags),
-		sizeof(env_ptr->flags), &flag);
+		sizeof(env_new.flags), &flag);
 	if (ret)
 		goto done;
 
 	ret = spi_flash_write(env_flash,
 		env_new_offset + offsetof(env_t, flags),
-		sizeof(env_ptr->flags), &new_flag);
+		sizeof(env_new.flags), &new_flag);
 	if (ret)
 		goto done;
 
@@ -164,33 +178,34 @@ void env_relocate_spec(void)
 	int crc1_ok = 0, crc2_ok = 0;
 	env_t *tmp_env1 = NULL;
 	env_t *tmp_env2 = NULL;
+	env_t ep;
 	uchar flag1, flag2;
 	/* current_env is set only in case both areas are valid! */
 	int current_env = 0;
 
 	tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
-	if (!tmp_env1) {
-		puts("*** Warning: could not init environment,"
-			" using defaults\n\n");
-		goto out;
-	}
-
 	tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
-	if (!tmp_env2) {
-		puts("*** Warning: could not init environment,"
-			" using defaults\n\n");
-		goto out;
+
+	if (!tmp_env1 || !tmp_env2) {
+		free(tmp_env1);
+		free(tmp_env2);
+		set_default_env("!malloc() failed");
+		return;
 	}
 
 	env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
 			CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
-	if (!env_flash)
-		goto err_probe;
+	if (!env_flash) {
+		set_default_env("!spi_flash_probe() failed");
+		return;
+	}
 
 	ret = spi_flash_read(env_flash, CONFIG_ENV_OFFSET,
 				CONFIG_ENV_SIZE, tmp_env1);
-	if (ret)
+	if (ret) {
+		set_default_env("!spi_flash_read() failed");
 		goto err_read;
+	}
 
 	if (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc)
 		crc1_ok = 1;
@@ -208,25 +223,25 @@ void env_relocate_spec(void)
 		goto err_crc;
 	else if (crc1_ok && !crc2_ok) {
 		gd->env_valid = 1;
-		memcpy(env_ptr, tmp_env1, CONFIG_ENV_SIZE);
+		ep = tmp_env1;
 	} else if (!crc1_ok && crc2_ok) {
 		gd->env_valid = 1;
-		memcpy(env_ptr, tmp_env2, CONFIG_ENV_SIZE);
+		ep = tmp_env2;
 		swap_env();
 	} else if (flag1 == ACTIVE_FLAG && flag2 == OBSOLETE_FLAG) {
 		gd->env_valid = 1;
-		memcpy(env_ptr, tmp_env1, CONFIG_ENV_SIZE);
+		ep = tmp_env1;
 	} else if (flag1 == OBSOLETE_FLAG && flag2 == ACTIVE_FLAG) {
 		gd->env_valid = 1;
-		memcpy(env_ptr, tmp_env2, CONFIG_ENV_SIZE);
+		ep = tmp_env2;
 		swap_env();
 	} else if (flag1 == flag2) {
 		gd->env_valid = 2;
-		memcpy(env_ptr, tmp_env1, CONFIG_ENV_SIZE);
+		ep = tmp_env1;
 		current_env = 1;
 	} else if (flag1 == 0xFF) {
 		gd->env_valid = 2;
-		memcpy(env_ptr, tmp_env1, CONFIG_ENV_SIZE);
+		ep = tmp_env1;
 		current_env = 1;
 	} else {
 		/*
@@ -234,35 +249,42 @@ void env_relocate_spec(void)
 		 * default path is desirable.
 		 */
 		gd->env_valid = 2;
-		memcpy(env_ptr, tmp_env2, CONFIG_ENV_SIZE);
+		ep = tmp_env2;
 		swap_env();
 		current_env = 2;
 	}
+
+	rc = env_import((char *)ep, 0);
+	if (!rc) {
+		error("Cannot import environment: errno = %d\n", errno);
+		goto out;
+	}
+
 	if (current_env == 1) {
 		if (flag2 != OBSOLETE_FLAG) {
 			flag2 = OBSOLETE_FLAG;
 			spi_flash_write(env_flash,
 				env_new_offset + offsetof(env_t, flags),
-				sizeof(env_ptr->flags), &flag2);
+				sizeof(env_new.flags), &flag2);
 		}
 		if (flag1 != ACTIVE_FLAG) {
 			flag1 = ACTIVE_FLAG;
 			spi_flash_write(env_flash,
 				env_offset + offsetof(env_t, flags),
-				sizeof(env_ptr->flags), &flag1);
+				sizeof(env_new.flags), &flag1);
 		}
 	} else if (current_env == 2) {
 		if (flag1 != OBSOLETE_FLAG) {
 			flag1 = OBSOLETE_FLAG;
 			spi_flash_write(env_flash,
 				env_new_offset + offsetof(env_t, flags),
-				sizeof(env_ptr->flags), &flag1);
+				sizeof(env_new.flags), &flag1);
 		}
 		if (flag2 != ACTIVE_FLAG) {
 			flag2 = ACTIVE_FLAG;
 			spi_flash_write(env_flash,
 				env_offset + offsetof(env_t, flags),
-				sizeof(env_ptr->flags), &flag2);
+				sizeof(env_new.flags), &flag2);
 		}
 	}
 	if (gd->env_valid == 2) {
@@ -278,15 +300,9 @@ void env_relocate_spec(void)
 err_read:
 	spi_flash_free(env_flash);
 	env_flash = NULL;
-err_probe:
-err_crc:
-	puts("*** Warning - bad CRC, using default environment\n\n");
 out:
-	if (tmp_env1)
-		free(tmp_env1);
-	if (tmp_env2)
-		free(tmp_env2);
-	set_default_env();
+	free(tmp_env1);
+	free(tmp_env2);
 }
 #else
 int saveenv(void)
@@ -348,32 +364,30 @@ int saveenv(void)
 
 void env_relocate_spec(void)
 {
+	char buf[CONFIG_ENV_SIZE];
 	int ret;
 
 	env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
 			CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
-	if (!env_flash)
-		goto err_probe;
-
-	ret = spi_flash_read(env_flash, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, env_ptr);
-	if (ret)
-		goto err_read;
-
-	if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
-		goto err_crc;
+	if (!env_flash) {
+		set_default_env("!spi_flash_probe() failed");
+		return;
+	}
 
-	gd->env_valid = 1;
+	ret = spi_flash_read(env_flash,
+		CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, buf);
+	if (ret) {
+		set_default_env("!spi_flash_read() failed");
+		goto out;
+	}
 
-	return;
+	ret = env_import(buf, 1);
 
-err_read:
+	if (ret)
+		gd->env_valid = 1;
+out:
 	spi_flash_free(env_flash);
 	env_flash = NULL;
-err_probe:
-err_crc:
-	puts("*** Warning - bad CRC, using default environment\n\n");
-
-	set_default_env();
 }
 #endif
 
diff --git a/common/exports.c b/common/exports.c
index bde52a6..3dff735 100644
--- a/common/exports.c
+++ b/common/exports.c
@@ -6,7 +6,6 @@ DECLARE_GLOBAL_DATA_PTR;
 __attribute__((unused)) static void dummy(void)
 {
 }
-#endif
 
 unsigned long get_version(void)
 {
diff --git a/include/environment.h b/include/environment.h
index fbccf6a..bedbc54 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -160,6 +160,9 @@ unsigned char env_get_char_memory (int index);
 void env_crc_update (void);
 
 /* [re]set to the default environment */
-void set_default_env(void);
+void set_default_env(const char *s);
+
+/* Import from binary representation into hash table */
+int env_import(const char *buf, int check);
 
 #endif	/* _ENVIRONMENT_H_ */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 2f3b5c8..c573992 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -45,6 +45,10 @@
 # include <linux/string.h>
 #endif
 
+#ifndef	CONFIG_ENV_MAX_ENTRIES	/* maximum number of entries */
+#define	CONFIG_ENV_MAX_ENTRIES 512
+#endif
+
 #include "search.h"
 
 /*
@@ -636,15 +640,23 @@ int himport_r(struct hsearch_data *htab,
 	 * table size is based on heuristics: in a sample of some 70+
 	 * existing systems we found an average size of 39+ bytes per entry
 	 * in the environment (for the whole key=value pair). Assuming a
-	 * size of 7 per entry (= safety factor of >5) should provide enough
-	 * safety margin for any existing environment definitons and still
+	 * size of 8 per entry (= safety factor of ~5) should provide enough
+	 * safety margin for any existing environment definitions and still
 	 * allow for more than enough dynamic additions. Note that the
 	 * "size" argument is supposed to give the maximum enviroment size
-	 * (CONFIG_ENV_SIZE).
+	 * (CONFIG_ENV_SIZE).  This heuristics will result in
+	 * unreasonably large numbers (and thus memory footprint) for
+	 * big flash environments (>8,000 entries for 64 KB
+	 * envrionment size), so we clip it to a reasonable value
+	 * (which can be overwritten in the board config file if
+	 * needed).
 	 */
 
 	if (!htab->table) {
-		int nent = size / 7;
+		int nent = size / 8;
+		
+		if (nent > CONFIG_ENV_MAX_ENTRIES)
+			nent = CONFIG_ENV_MAX_ENTRIES;
 
 		debug("Create Hash Table: N=%d\n", nent);
 
@@ -705,17 +717,19 @@ int himport_r(struct hsearch_data *htab,
 
 		hsearch_r(e, ENTER, &rv, htab);
 		if (rv == NULL) {
-			printf("himport_r: can't insert \"%s=%s\" into hash table\n", name, value);
+			printf("himport_r: can't insert \"%s=%s\" into hash table\n",
+				name, value);
 			return 0;
 		}
 
-		debug("INSERT: %p ==> name=\"%s\" value=\"%s\"\n", rv, name,
-		       value);
-		debug("        table = %p, size = %d, filled = %d\n", htab,
-		       htab->size, htab->filled);
+		debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n",
+			htab, htab->filled, htab->size,
+			rv, name, value);
 	} while ((dp < data + size) && *dp);	/* size check needed for text */
 						/* without '\0' termination */
+	debug("INSERT: free(data = %p)\n", data);
 	free(data);
 
+	debug("INSERT: done\n");
 	return 1;		/* everything OK */
 }
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-07-17 19:45 [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
                   ` (4 preceding siblings ...)
  2010-07-17 19:45 ` [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables Wolfgang Denk
@ 2010-07-17 19:49 ` Wolfgang Denk
  2010-07-17 20:56 ` Reinhard Meyer
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-17 19:49 UTC (permalink / raw)
  To: u-boot

In message <1279395948-25864-1-git-send-email-wd@denx.de> you wrote:
> The following patch series adds some utilities (qsort and hash table
> based database functions) and uses these to reimplement the code used
> for the internal handling of environment variables.

Note: the patches are also available for easier testing as branch
"hashtable" in the u-boot-testing repository, see
git://git.denx.de/u-boot-testing.git

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"It is easier to port a shell than a shell script."      - Larry Wall

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-07-17 19:45 [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
                   ` (5 preceding siblings ...)
  2010-07-17 19:49 ` [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
@ 2010-07-17 20:56 ` Reinhard Meyer
  2010-07-17 21:28   ` Mike Frysinger
  2010-07-17 21:31   ` Wolfgang Denk
  2010-07-17 21:55 ` Wolfgang Denk
                   ` (2 subsequent siblings)
  9 siblings, 2 replies; 53+ messages in thread
From: Reinhard Meyer @ 2010-07-17 20:56 UTC (permalink / raw)
  To: u-boot

Wolfgang Denk wrote:
> The following patch series adds some utilities (qsort and hash table
> based database functions) and uses these to reimplement the code used
> for the internal handling of environment variables.
>
>
> Motivation:
>
> * Old environment code used a pessimizing implementation:
>   - variable lookup used linear search => slow
>   - changed/added variables were added at the end, i. e. most
>     frequently used variables had the slowest access times => slow
>   - each setenv() would calculate the CRC32 checksum over the whole
>     environment block => slow
>   
Hello Wolfgang,

how many users are out there that have such huge environments that speed 
is of any concern?
The "grepenv" idea however seems to indicate some might have huge 
environments...

I see the advantages offered, but

> Disadvantages:
>
> - Image size grows by typically 5...7 KiB (might shrink a bit again on
>   systems with redundant environment with a following patch series)
>   
Looking at the patches I can't really see where that large increase in 
image size comes from;
but if its really true, it seems to be a very high price to pay for 
those who get along with the
environment as it is.
I would at least recommend that all new UI commands are optional; as basics
"setenv", "printenv", "saveenv" should do as until now. "export" and 
"import" must be adding
a lot to the code.

Best Regards,
Reinhard

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 1/5] Add basic errno support.
  2010-07-17 19:45 ` [U-Boot] [PATCH 1/5] Add basic errno support Wolfgang Denk
@ 2010-07-17 21:17   ` Mike Frysinger
  2010-07-17 21:34     ` Wolfgang Denk
  2010-07-18 12:51     ` Jerry Van Baren
  2010-09-12 19:16   ` Wolfgang Denk
  1 sibling, 2 replies; 53+ messages in thread
From: Mike Frysinger @ 2010-07-17 21:17 UTC (permalink / raw)
  To: u-boot

On Saturday, July 17, 2010 15:45:44 Wolfgang Denk wrote:
> --- /dev/null
> +++ b/lib/errno.c
> @@ -0,0 +1 @@
> +int errno = 0;

drop the "= 0" so that errno ends up in the bss ?
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20100717/d5508909/attachment.pgp 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-07-17 20:56 ` Reinhard Meyer
@ 2010-07-17 21:28   ` Mike Frysinger
  2010-07-17 21:41     ` Wolfgang Denk
  2010-07-17 21:31   ` Wolfgang Denk
  1 sibling, 1 reply; 53+ messages in thread
From: Mike Frysinger @ 2010-07-17 21:28 UTC (permalink / raw)
  To: u-boot

On Saturday, July 17, 2010 16:56:43 Reinhard Meyer wrote:
> Wolfgang Denk wrote:
> > Disadvantages:
> > 
> > - Image size grows by typically 5...7 KiB (might shrink a bit again on
> > 
> >   systems with redundant environment with a following patch series)
> 
> Looking at the patches I can't really see where that large increase in
> image size comes from;
> but if its really true, it seems to be a very high price to pay for
> those who get along with the environment as it is.

i wonder if we could #ifdef the sorting/hashing.  i tend to agree with 
Reinhard that it is very common for boards to be deployed with a small env, so 
i wonder if the normal runtime experience is actually faster, or if the 
difference is about the same as system noise: boot u-boot, load env with ~20 
entries, read a few env vars, boot OS.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20100717/f2dfacfc/attachment.pgp 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-07-17 20:56 ` Reinhard Meyer
  2010-07-17 21:28   ` Mike Frysinger
@ 2010-07-17 21:31   ` Wolfgang Denk
  1 sibling, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-17 21:31 UTC (permalink / raw)
  To: u-boot

Dear Reinhard Meyer,

In message <4C42190B.8060102@emk-elektronik.de> you wrote:
>
> how many users are out there that have such huge environments that speed 
> is of any concern?

This is not so much a question of huge environments. Even with small
environments (say, 2 kb) speed may quickly become an issue - see for
example here:
http://www.denx.de/wiki/DULG/AN2004_11_BootTimeOptimization (Step 2)

Even worse is the fact that the old code recomputes the CRC over the
whole environment for each and every "setenv" - and for example a
network download will run 4 (or more) "setenv" commands internally...

Or remember the tricks that were necessary to get netconsole and
serial console work in parallel...

And so on... the deeper you look, the more issues you will find with
the old code.  It has been designed to be simple to implement, but we
added a lot of usage modes since, and while I still think it's a
pretty efficient format for external storage, we need more efficient
ways when internally accessing the environment files.

> The "grepenv" idea however seems to indicate some might have huge 
> environments...
> 
> I see the advantages offered, but
> 
> > Disadvantages:
> >
> > - Image size grows by typically 5...7 KiB (might shrink a bit again on
> >   systems with redundant environment with a following patch series)

Yes, it's some 2...3% on many systems...

> Looking at the patches I can't really see where that large increase in 
> image size comes from;

Well, the hashtable code itself adds some 3 kB, a few hundret bytes
are needed for qsort, etc.

> but if its really true, it seems to be a very high price to pay for 
> those who get along with the
> environment as it is.

I hear you.

> I would at least recommend that all new UI commands are optional; as basics
> "setenv", "printenv", "saveenv" should do as until now. "export" and 
> "import" must be adding
> a lot to the code.

Actually it's not that much, and the code is needed anyway as it is
used to read (import) the environment as stored in flash / nand /
whatever into the hash table when booting, and to export it again
when running "saveenv". The remaining UI commands are tiny; they
don't consume any significant space.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
A Freudian slip is when you say one thing but mean your mother.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 1/5] Add basic errno support.
  2010-07-17 21:17   ` Mike Frysinger
@ 2010-07-17 21:34     ` Wolfgang Denk
  2010-07-18 12:51     ` Jerry Van Baren
  1 sibling, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-17 21:34 UTC (permalink / raw)
  To: u-boot

Dear Mike Frysinger,

In message <201007171717.27154.vapier@gentoo.org> you wrote:
>
> > +++ b/lib/errno.c
> > @@ -0,0 +1 @@
> > +int errno = 0;
> 
> drop the "= 0" so that errno ends up in the bss ?

This does not make any difference; the tools are clever enough to
figure that out:

	-> nm lib/errno.o
	00000000 S errno

S = "The symbol is in an uninitialized data section for small objects."

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
A quarrel is quickly settled when deserted by one party; there is  no
battle unless there be two.                                  - Seneca

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-07-17 21:28   ` Mike Frysinger
@ 2010-07-17 21:41     ` Wolfgang Denk
  2010-07-18  2:18       ` Mike Frysinger
  0 siblings, 1 reply; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-17 21:41 UTC (permalink / raw)
  To: u-boot

Dear Mike Frysinger,

In message <201007171728.27716.vapier@gentoo.org> you wrote:
>
> i wonder if we could #ifdef the sorting/hashing.  i tend to agree with 

The sorting does not take much:

	-> size lib/qsort.o  
	   text    data     bss     dec     hex filename
	    264       0       0     264     108 lib/qsort.o

The hashing on the other hand might be replacable.

> Reinhard that it is very common for boards to be deployed with a small env, so 
> i wonder if the normal runtime experience is actually faster, or if the 
> difference is about the same as system noise: boot u-boot, load env with ~20 
> entries, read a few env vars, boot OS.

Yes, this is one common use case.

But then, I see also systems that are running pretty complex shell
scripts to implement features like reliable software updates etc., and
there we see an improvment.


Also, speed is just one aspect - for me the capability of having
several "profiles" is much, much more important.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
It is more rational to sacrifice one life than six.
	-- Spock, "The Galileo Seven", stardate 2822.3

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-07-17 19:45 [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
                   ` (6 preceding siblings ...)
  2010-07-17 20:56 ` Reinhard Meyer
@ 2010-07-17 21:55 ` Wolfgang Denk
  2010-07-18  5:32   ` Reinhard Meyer
  2010-10-20  8:08 ` Mike Frysinger
  2010-12-08  9:56 ` Mike Frysinger
  9 siblings, 1 reply; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-17 21:55 UTC (permalink / raw)
  To: u-boot

In message <1279395948-25864-1-git-send-email-wd@denx.de> I wrote:
>
> The following patch series adds some utilities (qsort and hash table
> based database functions) and uses these to reimplement the code used
> for the internal handling of environment variables.
> 
> 
> Motivation:
> 
> * Old environment code used a pessimizing implementation:
>   - variable lookup used linear search => slow
>   - changed/added variables were added at the end, i. e. most
>     frequently used variables had the slowest access times => slow
>   - each setenv() would calculate the CRC32 checksum over the whole
>     environment block => slow

Just to give a datapoint for speed:

measured on TQM5200 (MPC5200 at 400 MHz, environment size 16 kB):

OLD implementation:

	=> sete ttt 'date;for i in 0 1 2 3 4 5 6 7 8 9 ; do for j in 0 1 2 3 4 5 6 7 8 9 ; do for k in 0 1 2 3 4 5 6 7 8 9 ; do run tt ; done ; done ; done;date'
	=> sete tt 'sete var1 xxx;sete var2 ${var1};sete var1 ${var2};sete var1;sete var2'
	=> run tt
	=> run ttt
	Date: 1910-07-17 (unknown day)    Time: 22:02:31
	Date: 1910-07-17 (unknown day)    Time: 22:03:27

New implementation:

	=> run ttt
	Date: 1910-07-17 (unknown day)    Time: 20:45:51
	Date: 1910-07-17 (unknown day)    Time: 20:45:53



I. e. we have 56 versus 2 seconds.

I haven't run intensive tests, but in general I think we can see that
scripts referncing environment variables will typically run faster by
a factor of 10, or more.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Time is an illusion perpetrated by the manufacturers of space.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 4/5] Remove support for CONFIG_HAS_UID and "forceenv" command
  2010-07-17 19:45 ` [U-Boot] [PATCH 4/5] Remove support for CONFIG_HAS_UID and "forceenv" command Wolfgang Denk
@ 2010-07-17 22:12   ` Sergey Kubushyn
  2010-09-12 19:18   ` Wolfgang Denk
  1 sibling, 0 replies; 53+ messages in thread
From: Sergey Kubushyn @ 2010-07-17 22:12 UTC (permalink / raw)
  To: u-boot

On Sat, 17 Jul 2010, Wolfgang Denk wrote:

Ack by: Sergey Kubushyn <ksi@koi8.net>
---

> This (undocumented) concept was only in use for the MVSMR and
> davinci_schmoogie Sergey Kubushyn <ksi@koi8.net> boards.
> Drop it for now.  If really needed, it should be reimplemented
> later in the context of the new environment command set.
>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Cc: Andre Schwarz <andre.schwarz@matrix-vision.de>
> Cc: Sergey Kubushyn <ksi@koi8.net>
> ---
> common/cmd_nvedit.c                 |   13 -------------
> common/exports.c                    |    3 ---
> include/_exports.h                  |    1 -
> include/common.h                    |    3 ---
> include/configs/MVSMR.h             |    1 -
> include/configs/davinci_schmoogie.h |    1 -
> include/exports.h                   |    3 ---
> 7 files changed, 0 insertions(+), 25 deletions(-)
>
> diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
> index 13325bc..8c86f15 100644
> --- a/common/cmd_nvedit.c
> +++ b/common/cmd_nvedit.c
> @@ -247,12 +247,7 @@ int _do_setenv (int flag, int argc, char * const argv[])
> 		 * ver is readonly.
> 		 */
> 		if (
> -#ifdef CONFIG_HAS_UID
> -		/* Allow serial# forced overwrite with 0xdeaf4add flag */
> -		    ((strcmp (name, "serial#") == 0) && (flag != 0xdeaf4add)) ||
> -#else
> 		    (strcmp (name, "serial#") == 0) ||
> -#endif
> 		    ((strcmp (name, "ethaddr") == 0)
> #if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
> 		     && (strcmp ((char *)env_get_addr(oldval),MK_STR(CONFIG_ETHADDR)) != 0)
> @@ -397,14 +392,6 @@ int setenv (char *varname, char *varvalue)
> 		return _do_setenv (0, 3, argv);
> }
>
> -#ifdef CONFIG_HAS_UID
> -void forceenv (char *varname, char *varvalue)
> -{
> -	char * const argv[4] = { "forceenv", varname, varvalue, NULL };
> -	_do_setenv (0xdeaf4add, 3, argv);
> -}
> -#endif
> -
> int do_setenv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> {
> 	if (argc < 2) {
> diff --git a/common/exports.c b/common/exports.c
> index cefe6f6..bde52a6 100644
> --- a/common/exports.c
> +++ b/common/exports.c
> @@ -35,9 +35,6 @@ unsigned long get_version(void)
> # define spi_release_bus   dummy
> # define spi_xfer          dummy
> #endif
> -#ifndef CONFIG_HAS_UID
> -# define forceenv          dummy
> -#endif
>
> void jumptable_init(void)
> {
> diff --git a/include/_exports.h b/include/_exports.h
> index f3df568..d89b65b 100644
> --- a/include/_exports.h
> +++ b/include/_exports.h
> @@ -18,7 +18,6 @@ EXPORT_FUNC(vprintf)
> EXPORT_FUNC(do_reset)
> EXPORT_FUNC(getenv)
> EXPORT_FUNC(setenv)
> -EXPORT_FUNC(forceenv)
> EXPORT_FUNC(simple_strtoul)
> EXPORT_FUNC(simple_strtol)
> EXPORT_FUNC(strcmp)
> diff --git a/include/common.h b/include/common.h
> index e4b4ec0..5eef9c7 100644
> --- a/include/common.h
> +++ b/include/common.h
> @@ -262,9 +262,6 @@ int	saveenv	     (void);
> int inline setenv   (char *, char *);
> #else
> int	setenv	     (char *, char *);
> -#ifdef CONFIG_HAS_UID
> -void	forceenv     (char *, char *);
> -#endif
> #endif /* CONFIG_PPC */
> #ifdef CONFIG_ARM
> # include <asm/mach-types.h>
> diff --git a/include/configs/MVSMR.h b/include/configs/MVSMR.h
> index 6492068..000c4c6 100644
> --- a/include/configs/MVSMR.h
> +++ b/include/configs/MVSMR.h
> @@ -185,7 +185,6 @@
>  */
> #define CONFIG_ENV_IS_IN_FLASH
> #undef	CONFIG_SYS_FLASH_PROTECTION
> -#define CONFIG_HAS_UID
> #define	CONFIG_OVERWRITE_ETHADDR_ONCE
>
> #define CONFIG_ENV_OFFSET	0x8000
> diff --git a/include/configs/davinci_schmoogie.h b/include/configs/davinci_schmoogie.h
> index 875dda4..04cdc21 100644
> --- a/include/configs/davinci_schmoogie.h
> +++ b/include/configs/davinci_schmoogie.h
> @@ -99,7 +99,6 @@
> /*=====================*/
> #define CONFIG_RTC_DS1307		/* RTC chip on SCHMOOGIE */
> #define CONFIG_SYS_I2C_RTC_ADDR	0x6f	/* RTC chip I2C address */
> -#define CONFIG_HAS_UID
> #define CONFIG_UID_DS28CM00		/* Unique ID on SCHMOOGIE */
> #define CONFIG_SYS_UID_ADDR		0x50	/* UID chip I2C address */
> /*==============================*/
> diff --git a/include/exports.h b/include/exports.h
> index 1d79a31..7404a7c 100644
> --- a/include/exports.h
> +++ b/include/exports.h
> @@ -26,9 +26,6 @@ int setenv (char *varname, char *varvalue);
> long simple_strtol(const char *cp,char **endp,unsigned int base);
> int strcmp(const char * cs,const char * ct);
> int ustrtoul(const char *cp, char **endp, unsigned int base);
> -#ifdef CONFIG_HAS_UID
> -void forceenv (char *varname, char *varvalue);
> -#endif
> #if defined(CONFIG_CMD_I2C)
> int i2c_write (uchar, uint, int , uchar* , int);
> int i2c_read (uchar, uint, int , uchar* , int);
> -- 
> 1.7.1.1
>

---
******************************************************************
*  KSI at home    KOI8 Net  < >  The impossible we do immediately.  *
*  Las Vegas   NV, USA   < >  Miracles require 24-hour notice.   *
******************************************************************

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH] new env: fix off-by-one error in setenv command
  2010-07-17 19:45 ` [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables Wolfgang Denk
@ 2010-07-17 22:48   ` Wolfgang Denk
  2010-07-20  0:38   ` [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables Kim Phillips
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-17 22:48 UTC (permalink / raw)
  To: u-boot

Fix an off-by-one error in the string concatenation for the setevn
command which would write over the end of the allocated area,
resulting eventually in a crash due to corruption of the malloc
metadata.

Signed-off-by: Wolfgang Denk <wd@denx.de>
---
Posted as incremental patch here to provide quick fix to testers (also
pushed to "hashtable" branch in u-boot-testing repo. Will be squashed
into new env code patch when resubmitting.

 common/cmd_nvedit.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 976a30b..010d003 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -273,7 +273,7 @@ int _do_env_set (int flag, int argc, char * const argv[])
 	/*
 	 * Insert / replace new value
 	 */
-	for (i=2,len=1; i<argc; ++i) {
+	for (i=2,len=0; i<argc; ++i) {
 		len += strlen(argv[i]) + 1;
 	}
 	if ((value = malloc(len)) == NULL) {
@@ -285,7 +285,7 @@ int _do_env_set (int flag, int argc, char * const argv[])
 
 		while ((*s++ = *v++) != '\0')
 			;
-		*s++ = ' ';
+		*(s-1) = ' ';
 	}
 	if (s != value)
 		*--s = '\0';
-- 
1.7.1.1

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-07-17 21:41     ` Wolfgang Denk
@ 2010-07-18  2:18       ` Mike Frysinger
  0 siblings, 0 replies; 53+ messages in thread
From: Mike Frysinger @ 2010-07-18  2:18 UTC (permalink / raw)
  To: u-boot

On Saturday, July 17, 2010 17:41:57 Wolfgang Denk wrote:
> Mike Frysinger wrote:
> > Reinhard that it is very common for boards to be deployed with a small
> > env, so i wonder if the normal runtime experience is actually faster, or
> > if the difference is about the same as system noise: boot u-boot, load
> > env with ~20 entries, read a few env vars, boot OS.
> 
> Yes, this is one common use case.
> 
> But then, I see also systems that are running pretty complex shell
> scripts to implement features like reliable software updates etc., and
> there we see an improvment.
> 
> 
> Also, speed is just one aspect - for me the capability of having
> several "profiles" is much, much more important.

which is why i suggested an ifdef.  i didnt say the features you're 
introducing arent useful to many people, just that they are not necessary to 
many others.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20100717/39a90e9f/attachment.pgp 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-07-17 21:55 ` Wolfgang Denk
@ 2010-07-18  5:32   ` Reinhard Meyer
  2010-07-18 10:26     ` Wolfgang Denk
  0 siblings, 1 reply; 53+ messages in thread
From: Reinhard Meyer @ 2010-07-18  5:32 UTC (permalink / raw)
  To: u-boot

Wolfgang Denk wrote:
> Just to give a datapoint for speed:
>
> measured on TQM5200 (MPC5200 at 400 MHz, environment size 16 kB):
>
> OLD implementation:
>
> 	=> sete ttt 'date;for i in 0 1 2 3 4 5 6 7 8 9 ; do for j in 0 1 2 3 4 5 6 7 8 9 ; do for k in 0 1 2 3 4 5 6 7 8 9 ; do run tt ; done ; done ; done;date'
> 	=> sete tt 'sete var1 xxx;sete var2 ${var1};sete var1 ${var2};sete var1;sete var2'
> 	=> run tt
> 	=> run ttt
> 	Date: 1910-07-17 (unknown day)    Time: 22:02:31
> 	Date: 1910-07-17 (unknown day)    Time: 22:03:27
>
> New implementation:
>
> 	=> run ttt
> 	Date: 1910-07-17 (unknown day)    Time: 20:45:51
> 	Date: 1910-07-17 (unknown day)    Time: 20:45:53
>
>   
<joke>I'd propose a contest for the most hilarious use of a 
BOOTLOADER.....</joke>

But, how does the timing look in the current implementation when the CRC 
calculation
is done only in the saveenv command?

Best Regards,
Reinhard

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-07-18  5:32   ` Reinhard Meyer
@ 2010-07-18 10:26     ` Wolfgang Denk
  0 siblings, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-18 10:26 UTC (permalink / raw)
  To: u-boot

Dear Reinhard Meyer,

In message <4C4291EE.5060102@emk-elektronik.de> you wrote:
>
> But, how does the timing look in the current implementation when the CRC 
> calculation
> is done only in the saveenv command?

I don't know. Much better for the old code, obviously. But you still
have the efforts for the linear search, usually way to the end of the
environment.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Save yourself!  Reboot in 5 seconds!

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 1/5] Add basic errno support.
  2010-07-17 21:17   ` Mike Frysinger
  2010-07-17 21:34     ` Wolfgang Denk
@ 2010-07-18 12:51     ` Jerry Van Baren
  2010-07-18 13:03       ` Wolfgang Denk
  1 sibling, 1 reply; 53+ messages in thread
From: Jerry Van Baren @ 2010-07-18 12:51 UTC (permalink / raw)
  To: u-boot

On 07/17/2010 05:17 PM, Mike Frysinger wrote:
> On Saturday, July 17, 2010 15:45:44 Wolfgang Denk wrote:
>> --- /dev/null
>> +++ b/lib/errno.c
>> @@ -0,0 +1 @@
>> +int errno = 0;
>
> drop the "= 0" so that errno ends up in the bss ?
> -mike

Is this going to be a problem during early startup (pre-relocation) vs. 
normal running?  Pre-relocation, we only have a temporary stack and RAM 
is not set up initially.

I have not looked at when RAM gets initialized vs. when env. variables 
get used.  It is probably OK.  Wolfgang?

Best regards,
gvb

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 1/5] Add basic errno support.
  2010-07-18 12:51     ` Jerry Van Baren
@ 2010-07-18 13:03       ` Wolfgang Denk
  0 siblings, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-18 13:03 UTC (permalink / raw)
  To: u-boot

Dear Jerry Van Baren,

In message <4C42F8DE.5040009@gmail.com> you wrote:
>
> > drop the "= 0" so that errno ends up in the bss ?
> > -mike
> 
> Is this going to be a problem during early startup (pre-relocation) vs. 
> normal running?  Pre-relocation, we only have a temporary stack and RAM 
> is not set up initially.
> 
> I have not looked at when RAM gets initialized vs. when env. variables 
> get used.  It is probably OK.  Wolfgang?

AFAICT the relevant code runs all only after relocation to RAM, i. e.
the use of errno (whether in BSS or not) should be no problem.

But you are right - using it before relocation will not work as is. We
could make it a global data entry, if needed.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"Free markets select for winning solutions."        - Eric S. Raymond

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-17 19:45 ` [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables Wolfgang Denk
  2010-07-17 22:48   ` [U-Boot] [PATCH] new env: fix off-by-one error in setenv command Wolfgang Denk
@ 2010-07-20  0:38   ` Kim Phillips
  2010-07-20  9:40     ` Wolfgang Denk
  2010-07-26 14:52   ` Matthias Fuchs
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 53+ messages in thread
From: Kim Phillips @ 2010-07-20  0:38 UTC (permalink / raw)
  To: u-boot

On Sat, 17 Jul 2010 21:45:48 +0200
Wolfgang Denk <wd@denx.de> wrote:

> - It would be nice if we could add wildcard support for environment
>   variables; this is needed for variable name auto-completion,
>   but it would also be nice to be able to say "printenv ip*" or
>   "printenv *addr*"

you were right - a grepenv/findenv/'env search' substring
implementation on top of this looks to be at least as expensive as a
full export operation :/

>  int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
>  {
> +#if 0 /* need to reimplement */

ouch - this is u-boot's most useful feature :)

It would be good to know boot time overhead the initial import function
makes, esp. in terms of number of boot-time accesses to the
environment...

Kim

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-20  0:38   ` [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables Kim Phillips
@ 2010-07-20  9:40     ` Wolfgang Denk
  2010-07-20 18:36       ` Kim Phillips
  0 siblings, 1 reply; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-20  9:40 UTC (permalink / raw)
  To: u-boot

Dear Kim Phillips,

In message <20100719193825.120ebf29.kim.phillips@freescale.com> you wrote:
>
> > - It would be nice if we could add wildcard support for environment
> >   variables; this is needed for variable name auto-completion,
> >   but it would also be nice to be able to say "printenv ip*" or
> >   "printenv *addr*"
> 
> you were right - a grepenv/findenv/'env search' substring
> implementation on top of this looks to be at least as expensive as a
> full export operation :/

Expensive in terms of what?  Code size? Probably not. It all boils
down to running strstr() over all entries...

> >  int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
> >  {
> > +#if 0 /* need to reimplement */
> 
> ouch - this is u-boot's most useful feature :)

He. We should probably run a poll for UMUF :-)

> It would be good to know boot time overhead the initial import function
> makes, esp. in terms of number of boot-time accesses to the
> environment...

I don't see any significant changes on the systems I tested...

Example TQM5200:

MPC5200 at 400 MHz, 16 KiB environment size, ~2 KiB used:

relevant env settings:

nfsargs=setenv bootargs root=/dev/nfs rw nfsroot=${serverip}:${rootpath}  
addip=setenv bootargs ${bootargs} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off panic=1  
addcons=setenv bootargs ${bootargs} console=${console},${baudrate}  
net_nfs=tftp ${kernel_addr_r} ${bootfile}; tftp ${fdt_addr_r} ${fdt_file}; run nfsargs addip addcons; bootm ${kernel_addr_r} - ${fdt_addr_r}  
bootcmd=run net_nfs  

old: U-Boot 2010.03-00167-g6e5fb4e (Apr 27 2010 - 15:37:15)
new: U-Boot 2010.06-00208-g7151bce-dirty (Jul 18 2010 - 00:36:48)

   old   new
 0.000   0.000 U-Boot 2010.03-00167-g6e5fb4e (Apr 27 2010 - 15:37:15)   
 0.000   0.000  
 0.000   0.000 CPU:   MPC5200B v2.2, Core v1.4 at 396 MHz  
 0.000   0.000        Bus 132 MHz, IPB 132 MHz, PCI 66 MHz  
 0.040   0.040 Board: TQM5200S (TQ-Components GmbH)  
 0.040   0.040        on a STK52xx carrier board  
 0.040   0.040 I2C:   85 kHz, ready  
 0.040   0.040 DRAM:  64 MB  
 0.080   0.080 FLASH: 32 MB  
 0.120   0.130 In:    serial  
 0.120   0.130 Out:   serial  
 0.120   0.130 Err:   serial  
 0.160   0.130 Net:   FEC ETHERNET  
 0.420   0.400 POST i2c PASSED  
 0.440   0.440 POST cpu PASSED  
 0.920   0.920 IDE:   Bus 0: OK   
 0.920   0.920   Device 0: Model: HITACHI_DK23DA-20 Firm: 00J2A0A1 Ser#: 12Y0MN  
 0.920   0.920             Type: Hard Disk  
 0.920   0.920             Capacity: 19077.1 MB = 18.6 GB (39070080 x 512)  
 2.840   2.871   Device 1: not available  
 2.840   2.871 SRAM:  512 kB  
 4.840   4.860 PS/2:  No device found  
 5.840   5.880 Kbd:   reset failed, no ACK  
 5.880   5.880
 5.880   5.880 Type run flash_nfs to mount root filesystem over NFS   
 5.880   5.880
10.880  10.880 Hit any key to stop autoboot:  0   
12.520  12.480 Using FEC ETHERNET device  
...
13.480  13.361 Bytes transferred = 7275 (1c6b hex)  
13.640  13.400 ## Booting kernel from Legacy Image at 00400000 ...  
13.640  13.400    Image Name:   Linux-2.6.32-rc5-01449-g2c33dca  
...
13.960  13.720 ## Flattened Device Tree blob at 00600000  
13.960  13.720    Booting using the fdt blob at 0x600000  
14.960  13.720    Uncompressing Kernel Image ... OK  
15.040  14.760 [    0.000000] Using mpc5200-simple-platform machine description  
15.040  14.760 [    0.000000] Linux version 2.6.32-rc5-01449-g2c33dca (wd at pollux.denx.de) (gcc version 4.2.2) #1 Mon Nov 2 09:31:00 CET 2009  
...

As you can see, there are stages where the new code is a bit slower
(20...40 milliseconds, which is close to the resolution of the
measurement), but in this specific test we win some 280 milliseconds;
if you exclude the 5 seconds boot delay that's some 2.7%. I don't
think it's worth mentioning, but at least it's not worse than the old
code.


I haven't tested many boards, especially not for timing. If you have
additional input it will be welcome.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"If you own a machine, you are in turn owned by it,  and  spend  your
time serving it..."    - Marion Zimmer Bradley, _The Forbidden Tower_

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-20  9:40     ` Wolfgang Denk
@ 2010-07-20 18:36       ` Kim Phillips
  2010-07-20 19:01         ` Wolfgang Denk
  2010-07-20 19:11         ` Wolfgang Denk
  0 siblings, 2 replies; 53+ messages in thread
From: Kim Phillips @ 2010-07-20 18:36 UTC (permalink / raw)
  To: u-boot

On Tue, 20 Jul 2010 11:40:23 +0200
Wolfgang Denk <wd@denx.de> wrote:

> Dear Kim Phillips,
> 
> In message <20100719193825.120ebf29.kim.phillips@freescale.com> you wrote:
> >
> > > - It would be nice if we could add wildcard support for environment
> > >   variables; this is needed for variable name auto-completion,
> > >   but it would also be nice to be able to say "printenv ip*" or
> > >   "printenv *addr*"
> > 
> > you were right - a grepenv/findenv/'env search' substring
> > implementation on top of this looks to be at least as expensive as a
> > full export operation :/
> 
> Expensive in terms of what?  Code size? Probably not. It all boils
> down to running strstr() over all entries...

time I thought, but ok, I'll look into it when I have time.

> As you can see, there are stages where the new code is a bit slower
> (20...40 milliseconds, which is close to the resolution of the
> measurement), but in this specific test we win some 280 milliseconds;
> if you exclude the 5 seconds boot delay that's some 2.7%. I don't
> think it's worth mentioning, but at least it's not worse than the old
> code.

excellent, thank you.

> I haven't tested many boards, especially not for timing. If you have
> additional input it will be welcome.

I would, however u-boot-testing.git/hashtable currently fails to boot
on an 8572:

U-Boot 2010.06-02552-g9895ea5 (Jul 19 2010 - 18:39:19)

CPU0:  8572E, Version: 1.1, (0x80e80011)
Core:  E500, Version: 3.0, (0x80210030)
Clock Configuration:
       CPU0:1499.985 MHz, CPU1:1499.985 MHz, 
       CCB:599.994 MHz,
       DDR:399.996 MHz (799.992 MT/s data rate) (Asynchronous), LBC:37.500 MHz
L1:    D-cache 32 kB enabled
       I-cache 32 kB enabled
Board: MPC8572DS Sys ID: 0x14, Sys Ver: 0x30, FPGA Ver: 0x10, vBank: 0
I2C:   ready
DRAM:  Initializing....

I presume it's related to the issue brought up in this thread?:

http://lists.denx.de/pipermail/u-boot/2010-July/074151.html

Cheers,

Kim

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-20 18:36       ` Kim Phillips
@ 2010-07-20 19:01         ` Wolfgang Denk
  2010-07-20 20:09           ` Wolfgang Denk
  2010-07-20 19:11         ` Wolfgang Denk
  1 sibling, 1 reply; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-20 19:01 UTC (permalink / raw)
  To: u-boot

Dear Kim Phillips,

In message <20100720133648.cbb95a9f.kim.phillips@freescale.com> you wrote:
>
> I would, however u-boot-testing.git/hashtable currently fails to boot
> on an 8572:

Hm... one of the boards I don't have access to; can you please help
debug the problem?

> U-Boot 2010.06-02552-g9895ea5 (Jul 19 2010 - 18:39:19)
> 
> CPU0:  8572E, Version: 1.1, (0x80e80011)
> Core:  E500, Version: 3.0, (0x80210030)
> Clock Configuration:
>        CPU0:1499.985 MHz, CPU1:1499.985 MHz, 
>        CCB:599.994 MHz,
>        DDR:399.996 MHz (799.992 MT/s data rate) (Asynchronous), LBC:37.500 MHz
> L1:    D-cache 32 kB enabled
>        I-cache 32 kB enabled
> Board: MPC8572DS Sys ID: 0x14, Sys Ver: 0x30, FPGA Ver: 0x10, vBank: 0
> I2C:   ready
> DRAM:  Initializing....
> 
> I presume it's related to the issue brought up in this thread?:
> 
> http://lists.denx.de/pipermail/u-boot/2010-July/074151.html

Hm... I don't think so, but as it's failing there must be some bug
somewhere... My thinking is that all the relevant environment handling
that actually uses errno is related to the hash table handling, and
all this runs definitely only after relocation to RAM, so this should
not be the problem.

What we see here is in the pre-relocation phase, where we are still
parsing the original, in-flash copy of the stringified environment.
What is strange is that this seems to have worked when accessing
"baudrate" (either because the environment was found, or because the
default environment was used), but is stopping here.

Can you attach a debugger and check?

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"The net result is a system that is not only binary  compatible  with
4.3  BSD, but is even bug for bug compatible in almost all features."
- Avadit  Tevanian,  Jr.,  "Architecture-Independent  Virtual  Memory
Management  for  Parallel  and  Distributed  Environments:  The  Mach
Approach"

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-20 18:36       ` Kim Phillips
  2010-07-20 19:01         ` Wolfgang Denk
@ 2010-07-20 19:11         ` Wolfgang Denk
  1 sibling, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-20 19:11 UTC (permalink / raw)
  To: u-boot

Dear Kim Phillips,

In message <20100720133648.cbb95a9f.kim.phillips@freescale.com> you wrote:
>
> I would, however u-boot-testing.git/hashtable currently fails to boot
> on an 8572:
...
> I presume it's related to the issue brought up in this thread?:
> 
> http://lists.denx.de/pipermail/u-boot/2010-July/074151.html

I smell a wumpus.  Don't spend time on debugging this, let me track
down an idea first, please.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
What the gods would destroy they first submit to  an  IEEE  standards
committee.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-20 19:01         ` Wolfgang Denk
@ 2010-07-20 20:09           ` Wolfgang Denk
       [not found]             ` <1279658019.5685.125.camel@thunk>
  2010-07-20 21:08             ` Kim Phillips
  0 siblings, 2 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-20 20:09 UTC (permalink / raw)
  To: u-boot

Dear Kim,

In message <20100720190112.3F435153A7F@gemini.denx.de> I wrote:
> 
> What we see here is in the pre-relocation phase, where we are still
> parsing the original, in-flash copy of the stringified environment.
> What is strange is that this seems to have worked when accessing
> "baudrate" (either because the environment was found, or because the
> default environment was used), but is stopping here.

I think the problem is that before relocation we have to use
getenv_r(), which is done for example to read the baudrate, see
arch/powerpc/lib/board.c: init_baudrate()

However, some boards also use getenv() before relocation. I just found
for example that the Sequoia board does this (before relocation):

"board/amcc/sequoia/sequoia.c":

330 int checkboard(void)
331 {
332         char *s = getenv("serial#");
333         u8 rev;
334         u32 clock = get_async_pci_freq();
335
336 #ifdef CONFIG_440EPX
337         printf("Board: Sequoia - AMCC PPC440EPx Evaluation Board");
338 #else
339         printf("Board: Rainier - AMCC PPC440GRx Evaluation Board");
340 #endif
...

and as one can expect the board crashes before printing the board
information.

I'm considering a way to eliminate getenv_r() (at the cost of
providing some static buffer in the global data area?).

[Comments? Ideas?]


However, I cannot see any gentenv() use before relocation for your
board, so the problem there is still unclear. I think I need your
help to debug this...



Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Human beings were created by water to transport it uphill.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
       [not found]             ` <1279658019.5685.125.camel@thunk>
@ 2010-07-20 20:35               ` Wolfgang Denk
  0 siblings, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-20 20:35 UTC (permalink / raw)
  To: u-boot

Dear Peter,

In message <1279658019.5685.125.camel@thunk> you wrote:
> 
> > I think the problem is that before relocation we have to use
> > getenv_r(), which is done for example to read the baudrate, see
> > arch/powerpc/lib/board.c: init_baudrate()
> 
> How hard is it to detect this case and generate a stackdump if someone
> calls getenv() before relocation is complete?  That would help to spot
> places where people are breaking the rules...

It's trivial to check - all we need to addd to getenv() is something
like

	if (!(gd->flags & GD_FLG_RELOC))
		bail_out();

But then, we could as well try to be friendly and eliminate
getenv_r(). We would just need a static buffer for the result.



Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Reader, suppose you were an idiot. And suppose you were a  member  of
Congress. But I repeat myself.                           - Mark Twain

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-20 20:09           ` Wolfgang Denk
       [not found]             ` <1279658019.5685.125.camel@thunk>
@ 2010-07-20 21:08             ` Kim Phillips
  2010-07-20 21:43               ` Wolfgang Denk
  1 sibling, 1 reply; 53+ messages in thread
From: Kim Phillips @ 2010-07-20 21:08 UTC (permalink / raw)
  To: u-boot

On Tue, 20 Jul 2010 22:09:08 +0200
Wolfgang Denk <wd@denx.de> wrote:

> However, I cannot see any gentenv() use before relocation for your
> board, so the problem there is still unclear. I think I need your
> help to debug this...

looks like arch/powerpc/cpu/mpc8xxx/ddr/options.c gets memory
interleaving configuration from the environment, using getenv().

Kim

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-20 21:08             ` Kim Phillips
@ 2010-07-20 21:43               ` Wolfgang Denk
  2010-07-20 22:00                 ` Kim Phillips
  0 siblings, 1 reply; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-20 21:43 UTC (permalink / raw)
  To: u-boot

Dear Kim,

In message <20100720160808.b7ecf34c.kim.phillips@freescale.com> you wrote:
> 
> > However, I cannot see any gentenv() use before relocation for your
> > board, so the problem there is still unclear. I think I need your
> > help to debug this...
> 
> looks like arch/powerpc/cpu/mpc8xxx/ddr/options.c gets memory
> interleaving configuration from the environment, using getenv().

Ah! Can you please try the following patch - it's not intended to be a
fix, just to verify my hypothesis. Thanks in advance.

diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
index 46731c8..0b9cb1d 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
@@ -24,6 +24,7 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
 {
 	unsigned int i;
 	const char *p;
+	char tmp[64];
 
 	/* Chip select options. */
 
@@ -221,7 +222,8 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
 	 * should be a subset of the requested configuration.
 	 */
 #if (CONFIG_NUM_DDR_CONTROLLERS > 1)
-	if ((p = getenv("memctl_intlv_ctl")) != NULL) {
+	i = getenv_r("memctl_intlv_ctl", tmp, sizeof (tmp));
+	if (i > 0) {
 		if (pdimm[0].n_ranks == 0) {
 			printf("There is no rank on CS0. Because only rank on "
 				"CS0 and ranks chip-select interleaved with CS0"
@@ -230,37 +232,38 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
 			popts->memctl_interleaving = 0;
 		} else {
 			popts->memctl_interleaving = 1;
-			if (strcmp(p, "cacheline") == 0)
+			if (strcmp(tmp, "cacheline") == 0)
 				popts->memctl_interleaving_mode =
 					FSL_DDR_CACHE_LINE_INTERLEAVING;
-			else if (strcmp(p, "page") == 0)
+			else if (strcmp(tmp, "page") == 0)
 				popts->memctl_interleaving_mode =
 					FSL_DDR_PAGE_INTERLEAVING;
-			else if (strcmp(p, "bank") == 0)
+			else if (strcmp(tmp, "bank") == 0)
 				popts->memctl_interleaving_mode =
 					FSL_DDR_BANK_INTERLEAVING;
-			else if (strcmp(p, "superbank") == 0)
+			else if (strcmp(tmp, "superbank") == 0)
 				popts->memctl_interleaving_mode =
 					FSL_DDR_SUPERBANK_INTERLEAVING;
 			else
 				popts->memctl_interleaving_mode =
-						simple_strtoul(p, NULL, 0);
+						simple_strtoul(tmp, NULL, 0);
 		}
 	}
 #endif
 
-	if( ((p = getenv("ba_intlv_ctl")) != NULL) &&
+	i = getenv_r("ba_intlv_ctl", tmp, sizeof (tmp));
+	if (i > 0) && (CONFIG_CHIP_SELECTS_PER_CTRL > 1)) {
 		(CONFIG_CHIP_SELECTS_PER_CTRL > 1)) {
-		if (strcmp(p, "cs0_cs1") == 0)
+		if (strcmp(tmp, "cs0_cs1") == 0)
 			popts->ba_intlv_ctl = FSL_DDR_CS0_CS1;
-		else if (strcmp(p, "cs2_cs3") == 0)
+		else if (strcmp(tmp, "cs2_cs3") == 0)
 			popts->ba_intlv_ctl = FSL_DDR_CS2_CS3;
-		else if (strcmp(p, "cs0_cs1_and_cs2_cs3") == 0)
+		else if (strcmp(tmp, "cs0_cs1_and_cs2_cs3") == 0)
 			popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_AND_CS2_CS3;
-		else if (strcmp(p, "cs0_cs1_cs2_cs3") == 0)
+		else if (strcmp(tmp, "cs0_cs1_cs2_cs3") == 0)
 			popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_CS2_CS3;
 		else
-			popts->ba_intlv_ctl = simple_strtoul(p, NULL, 0);
+			popts->ba_intlv_ctl = simple_strtoul(tmp, NULL, 0);
 
 		switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) {
 		case FSL_DDR_CS0_CS1_CS2_CS3:


Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"In Christianity neither morality nor religion come into contact with
reality at any point."                          - Friedrich Nietzsche

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-20 21:43               ` Wolfgang Denk
@ 2010-07-20 22:00                 ` Kim Phillips
  2010-07-25 21:45                   ` Wolfgang Denk
  0 siblings, 1 reply; 53+ messages in thread
From: Kim Phillips @ 2010-07-20 22:00 UTC (permalink / raw)
  To: u-boot

On Tue, 20 Jul 2010 23:43:14 +0200
Wolfgang Denk <wd@denx.de> wrote:

> Dear Kim,
> 
> In message <20100720160808.b7ecf34c.kim.phillips@freescale.com> you wrote:
> > 
> > > However, I cannot see any gentenv() use before relocation for your
> > > board, so the problem there is still unclear. I think I need your
> > > help to debug this...
> > 
> > looks like arch/powerpc/cpu/mpc8xxx/ddr/options.c gets memory
> > interleaving configuration from the environment, using getenv().
> 
> Ah! Can you please try the following patch - it's not intended to be a
> fix, just to verify my hypothesis. Thanks in advance.

indeed, your patch plus the following makes the 8572 boot properly
again.

diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
index 0b9cb1d..692669f 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
@@ -252,8 +252,7 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
 #endif
 
 	i = getenv_r("ba_intlv_ctl", tmp, sizeof (tmp));
-	if (i > 0) && (CONFIG_CHIP_SELECTS_PER_CTRL > 1)) {
-		(CONFIG_CHIP_SELECTS_PER_CTRL > 1)) {
+	if ((i > 0) && (CONFIG_CHIP_SELECTS_PER_CTRL > 1)) {
 		if (strcmp(tmp, "cs0_cs1") == 0)
 			popts->ba_intlv_ctl = FSL_DDR_CS0_CS1;
 		else if (strcmp(tmp, "cs2_cs3") == 0)

Kim

^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-20 22:00                 ` Kim Phillips
@ 2010-07-25 21:45                   ` Wolfgang Denk
  2010-07-26 23:18                     ` Kim Phillips
  0 siblings, 1 reply; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-25 21:45 UTC (permalink / raw)
  To: u-boot

Dear Kim,

In message <20100720170026.fee7f593.kim.phillips@freescale.com> you wrote:
>
> > Ah! Can you please try the following patch - it's not intended to be a
> > fix, just to verify my hypothesis. Thanks in advance.
> 
> indeed, your patch plus the following makes the 8572 boot properly
> again.

Thanks for testing.

Could you please also test the code from the current (rebased) version
in the "hashtable" branch of the git://git.denx.de/u-boot-testing.git
repo?

I have adresses the problem of early environment accesses, and at
least on the boards I've tested so far it appears to be working.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
I will not say that women have no character;  rather, they have a new
one every day.                                               -- Heine

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-17 19:45 ` [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables Wolfgang Denk
  2010-07-17 22:48   ` [U-Boot] [PATCH] new env: fix off-by-one error in setenv command Wolfgang Denk
  2010-07-20  0:38   ` [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables Kim Phillips
@ 2010-07-26 14:52   ` Matthias Fuchs
  2010-07-28 21:17     ` Wolfgang Denk
  2010-09-12 19:19   ` Wolfgang Denk
  2010-12-30  1:53   ` [U-Boot] env_flash.c:saveenv() broken when env is smaller than a sector Mike Frysinger
  4 siblings, 1 reply; 53+ messages in thread
From: Matthias Fuchs @ 2010-07-26 14:52 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

I could think of some situations where the new env command
is helpful. But more during development than for production systems.

Switching between environment profiles would be cool. And a "env default -f"
behavior that keeps MAC addresses and serial# is also on my wishlist.

I did some testing on our PMC440 with environment in EEPROM.
Please see some comments below.

On Saturday 17 July 2010 21:45, Wolfgang Denk wrote:
> diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
> index 8c86f15..976a30b 100644
> --- a/common/cmd_nvedit.c
> +++ b/common/cmd_nvedit.c
...
> +/*
> + * env export [-t | -b | -c] addr [size]
> + *	-t:	export as text format; if size is given, data will be
> + *		padded with '\0' bytes; if not, one terminating '\0'
> + *		will be added (which is included in the "filesize"
> + *		setting so you can for exmple copy this to flash and
> + *		keep the termination).
> + *	-b:	export as binary format (name=value pairs separated by
> + *		'\0', list end marked by double "\0\0")
> + *	-c:	export as checksum protected environment format as
> + *		used for example by "saveenv" command
> + *	addr:	memory address where environment gets stored
> + *	size:	size of output buffer
> + *
...
> +static int do_env_export(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +	char	buf[32];
> +	char	*addr, *cmd, *res;
> +	size_t	size;
> +	ssize_t	len;
> +	env_t	*envp = (env_t *)addr;
addr is uninitialized. declaration is enough here.
> +	char	sep = '\n';
> +	int	chk = 0;
> +	int	fmt = 0;
> +
> +	cmd = *argv;
> +
> +	while (--argc > 0 && **++argv == '-') {
I'd like some more braces for readability.

> +		char *arg = *argv;
> +		while (*++arg) {
> +			switch (*arg) {
> +			case 'b':		/* raw binary format */
> +				if (fmt++)
> +					goto sep_err;
> +				sep = '\0';
> +				break;
> +			case 'c':		/* external checksum format */
> +				if (fmt++)
> +					goto sep_err;
> +				sep = '\0';
> +				chk = 1;
> +				break;
> +			case 't':		/* text format */
> +				if (fmt++)
> +					goto sep_err;
> +				sep = '\n';
> +				break;
> +			default:
> +				cmd_usage(cmdtp);
> +				return 1;
> +			}
> +		}
> +	}
>  
> -/**************************************************/
> +	if (argc < 1) {
> +		cmd_usage(cmdtp);
> +		return 1;
> +	}
> +
> +	addr = (char *)simple_strtoul(argv[0], NULL, 16);
> +
> +	if (argc == 2) {
> +		size = simple_strtoul(argv[1], NULL, 16);
> +		memset(addr, '\0', size);
> +	} else {
> +		size = 0;
> +	}
> +
> +	if (sep) {		/* export as text file */
> +		len = hexport(sep, &addr, size);
> +		if (len < 0) {
> +			error("Cannot export environment: errno = %d\n",
> +				errno);
> +			return 1;
> +		}
> +		sprintf(buf, "%zX", len);
> +		setenv("filesize", buf);
> +
> +		return 0;
> +	}
> +
> +	if (chk) {		/* export as checksum protected block */
Add:
		envp = (env_t *)addr;
> +		res = (char *)&envp->data;
> +	} else {		/* export as raw binary data */
> +		res = (char *)&addr;
Should'n this be 
		res = addr;

> +	}
> +
> +	len = hexport('\0', &res, ENV_SIZE);
> +	if (len < 0) {
> +		error("Cannot export environment: errno = %d\n",
> +			errno);
> +		return 1;
> +	}
> +
> +	if (chk) {
> +		envp->crc   = crc32(0, envp->data, ENV_SIZE);
> +#ifdef CONFIG_ENV_ADDR_REDUND
> +		envp->flags = ACTIVE_FLAG;
> +#endif
> +	}
> +	sprintf(buf, "%zX", len + offsetof(env_t,data));
> +	setenv("filesize", buf);
> +
> +	return 0;
> +
> +sep_err:
> +	printf("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",
> +		cmd);
> +	return 1;
> +}
> +
...


Fixes for non-building board (AR405, CANBT, PMC440) will come up shortly.

Matthias

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-25 21:45                   ` Wolfgang Denk
@ 2010-07-26 23:18                     ` Kim Phillips
  0 siblings, 0 replies; 53+ messages in thread
From: Kim Phillips @ 2010-07-26 23:18 UTC (permalink / raw)
  To: u-boot

On Sun, 25 Jul 2010 23:45:02 +0200
Wolfgang Denk <wd@denx.de> wrote:

> Could you please also test the code from the current (rebased) version
> in the "hashtable" branch of the git://git.denx.de/u-boot-testing.git
> repo?
> 
> I have adresses the problem of early environment accesses, and at
> least on the boards I've tested so far it appears to be working.

U-Boot 2010.06-02590-g38045a3 ("4xx: Make sequoia board build with new
environment code") runs beautifully on the 8572.

Thanks,

Kim

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-26 14:52   ` Matthias Fuchs
@ 2010-07-28 21:17     ` Wolfgang Denk
  2010-07-29  9:16       ` Matthias Fuchs
  0 siblings, 1 reply; 53+ messages in thread
From: Wolfgang Denk @ 2010-07-28 21:17 UTC (permalink / raw)
  To: u-boot

Dear Matthias Fuchs,

In message <201007261652.39368.matthias.fuchs@esd-electronics.com> you wrote:
> 
> I could think of some situations where the new env command
> is helpful. But more during development than for production systems.

It depends. "Reset to factory defaults" is a not so uncommon request.
And acceleration of scripts is not so uncommon either.

> Switching between environment profiles would be cool. And a "env default -f"
> behavior that keeps MAC addresses and serial# is also on my wishlist.

Actually neither MAC addresses nor  serial# are part of the default
environment.

> I did some testing on our PMC440 with environment in EEPROM.
> Please see some comments below.

Thanks.

> > +static int do_env_export(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> > +{
> > +	char	buf[32];
> > +	char	*addr, *cmd, *res;
> > +	size_t	size;
> > +	ssize_t	len;
> > +	env_t	*envp = (env_t *)addr;
> addr is uninitialized. declaration is enough here.

Will check this.

...
> > +	if (chk) {		/* export as checksum protected block */
> Add:
> 		envp = (env_t *)addr;
> > +		res = (char *)&envp->data;
> > +	} else {		/* export as raw binary data */
> > +		res = (char *)&addr;
> Should'n this be 
> 		res = addr;

No. We need the address of the pointer variable, so the function can
store the result pointer there.

...
> Fixes for non-building board (AR405, CANBT, PMC440) will come up shortly.

Thanks a lot.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-28 21:17     ` Wolfgang Denk
@ 2010-07-29  9:16       ` Matthias Fuchs
  2010-08-03 22:48         ` Wolfgang Denk
  0 siblings, 1 reply; 53+ messages in thread
From: Matthias Fuchs @ 2010-07-29  9:16 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Wednesday 28 July 2010 23:17, Wolfgang Denk wrote:
> Dear Matthias Fuchs,
> 
> In message <201007261652.39368.matthias.fuchs@esd-electronics.com> you wrote:
> > 
> > I could think of some situations where the new env command
> > is helpful. But more during development than for production systems.
> 
> It depends. "Reset to factory defaults" is a not so uncommon request.
> And acceleration of scripts is not so uncommon either.
> 
> > Switching between environment profiles would be cool. And a "env default -f"
> > behavior that keeps MAC addresses and serial# is also on my wishlist.
> 
> Actually neither MAC addresses nor  serial# are part of the default
> environment.
Right. But, I'd like to have that described feature in any case. Let's call it different,
but the functionality would be helpful. What about a further option like '-p' for keep
_p_rotected. 
> 
> > I did some testing on our PMC440 with environment in EEPROM.
> > Please see some comments below.
> 
> Thanks.
> 
> > > +static int do_env_export(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> > > +{
> > > +	char	buf[32];
> > > +	char	*addr, *cmd, *res;
> > > +	size_t	size;
> > > +	ssize_t	len;
> > > +	env_t	*envp = (env_t *)addr;
> > addr is uninitialized. declaration is enough here.
> 
> Will check this.
> 
> ...
> > > +	if (chk) {		/* export as checksum protected block */
> > Add:
> > 		envp = (env_t *)addr;
> > > +		res = (char *)&envp->data;
> > > +	} else {		/* export as raw binary data */
> > > +		res = (char *)&addr;
> > Should'n this be 
> > 		res = addr;
> 
> No. We need the address of the pointer variable, so the function can
> store the result pointer there.
Nak. You added &-operator when calling: hexport('\0', &res, ENV_SIZE);
That's one to much. You can also remove the &-operator from this:
		res = (char *)&envp->data;

So the code will look like this:

	if (chk) {		/* export as checksum protected block */
		envp = (env_t *)addr;
		res = (char *)envp->data;
	} else {		/* export as raw binary data */
		res = addr;
	}

	len = hexport('\0', &res, ENV_SIZE);
...

Matthias

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-29  9:16       ` Matthias Fuchs
@ 2010-08-03 22:48         ` Wolfgang Denk
  0 siblings, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-08-03 22:48 UTC (permalink / raw)
  To: u-boot

Dear Matthias Fuchs,

In message <201007291116.15503.matthias.fuchs@esd-electronics.com> you wrote:
> 
> > Actually neither MAC addresses nor  serial# are part of the default
> > environment.
> Right. But, I'd like to have that described feature in any case. Let's call it different,
> but the functionality would be helpful. What about a further option like '-p' for keep
> _p_rotected. 

I see this a s part of a sub-sequent patch (series), which adds flags
to variables (like read-only, don't-save, etc.).

> > No. We need the address of the pointer variable, so the function can
> > store the result pointer there.
> Nak. You added &-operator when calling: hexport('\0', &res, ENV_SIZE);
> That's one to much. You can also remove the &-operator from this:
> 		res = (char *)&envp->data;
> 
> So the code will look like this:

Thanks, will re-check this when I have a little more time.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
The more complex the mind, the greater the need for the simplicity of
play.
	-- Kirk, "Shore Leave", stardate 3025.8

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 1/5] Add basic errno support.
  2010-07-17 19:45 ` [U-Boot] [PATCH 1/5] Add basic errno support Wolfgang Denk
  2010-07-17 21:17   ` Mike Frysinger
@ 2010-09-12 19:16   ` Wolfgang Denk
  1 sibling, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-09-12 19:16 UTC (permalink / raw)
  To: u-boot

Dear Wolfgang Denk,

In message <1279395948-25864-2-git-send-email-wd@denx.de> you wrote:
> Needed for hash table support; probably useful in a lot of other
> places as well.
> 
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> ---
>  include/errno.h |    9 +++++++++
>  lib/Makefile    |    1 +
>  lib/errno.c     |    1 +
>  3 files changed, 11 insertions(+), 0 deletions(-)
>  create mode 100644 include/errno.h
>  create mode 100644 lib/errno.c


Applied to "next" branch.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"Send lawyers, guns and money..."  - Lyrics from a Warren Zevon song

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 2/5] Add qsort - add support for sorting data arrays
  2010-07-17 19:45 ` [U-Boot] [PATCH 2/5] Add qsort - add support for sorting data arrays Wolfgang Denk
@ 2010-09-12 19:16   ` Wolfgang Denk
  0 siblings, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-09-12 19:16 UTC (permalink / raw)
  To: u-boot

Dear Wolfgang Denk,

In message <1279395948-25864-3-git-send-email-wd@denx.de> you wrote:
> Code adapted from uClibc-0.9.30.3
> 
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> ---
>  include/common.h |    4 +++
>  lib/Makefile     |    1 +
>  lib/qsort.c      |   69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 74 insertions(+), 0 deletions(-)
>  create mode 100644 lib/qsort.c


Applied to "next" branch.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
F u cn rd ths u cnt spl wrth a dm!

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 3/5] Add hash table support as base for new environment code
  2010-07-17 19:45 ` [U-Boot] [PATCH 3/5] Add hash table support as base for new environment code Wolfgang Denk
@ 2010-09-12 19:16   ` Wolfgang Denk
  2010-12-08  9:44   ` Mike Frysinger
  1 sibling, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-09-12 19:16 UTC (permalink / raw)
  To: u-boot

Dear Wolfgang Denk,

In message <1279395948-25864-4-git-send-email-wd@denx.de> you wrote:
> This implementation is based on code from uClibc-0.9.30.3 but was
> modified and extended for use within U-Boot.
> 
> Major modifications and extensions:
> 
> * hsearch() [modified / extended]:
>   - While the standard version does not make any assumptions about
>     the type of the stored data objects at all, this implementation
>     works with NUL terminated strings only.
>   - Instead of storing just pointers to the original objects, we
>     create local copies so the caller does not need to care about the
>     data any more.
>   - The standard implementation does not provide a way to update an
>     existing entry.  This version will create a new entry or update an
>     existing one when both "action == ENTER" and "item.data != NULL".
>   - hsearch_r(): Instead of returning 1 on success, we return the
>     index into the internal hash table, which is also guaranteed to be
>     positive.  This allows us direct access to the found hash table
>     slot for example for functions like hdelete().
> * hdelete() [added]:
>   - The standard implementation of hsearch(3) does not provide any way
>     to delete any entries from the hash table.  We extend the code to
>     do that.
> * hexport() [added]:
>   - Export the data stored in the hash table in linearized form:
>     Entries are exported as "name=value" strings, separated by an
>     arbitrary (non-NUL, of course) separator character. This allows to
>     use this function both when formatting the U-Boot environment for
>     external storage (using '\0' as separator), but also when using it
>     for the "printenv" command to print all variables, simply by using
>     as '\n" as separator. This can also be used for new features like
>     exporting the environment data as text file, including the option
>     for later re-import.
>   - The entries in the result list will be sorted by ascending key
>     values.
> * himport() [added]:
>   - Import linearized data into hash table.  This is the inverse
>     function to hexport(): it takes a linear list of "name=value"
>     pairs and creates hash table entries from it.
>   - Entries without "value", i. e. consisting of only "name" or
>     "name=", will cause this entry to be deleted from the hash table.
>   - The "flag" argument can be used to control the behaviour: when
>     the H_NOCLEAR bit is set, then an existing hash table will kept,
>     i. e. new data will be added to an existing hash table;
>     otherwise, old data will be discarded and a new hash table will
>     be created.
>   - The separator character for the "name=value" pairs can be
>     selected, so we both support importing from externally stored
>     environment data (separated by NUL characters) and from plain text
>     files (entries separated by newline characters).
>   - To allow for nicely formatted text input, leading white space
>     (sequences of SPACE and TAB chars) is ignored, and entries
>     starting (after removal of any leading white space) with a '#'
>     character are considered comments and ignored.
>   - NOTE: this means that a variable name cannot start with a '#'
>     character.
>   - When using a non-NUL separator character, backslash is used as
>     escape character in the value part, allowing for example fo
>     multi-line values.
>   - In theory, arbitrary separator characters can be used, but only
>     '\0' and '\n' have really been tested.
> 
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> ---
>  include/search.h |  106 ++++++++
>  lib/Makefile     |    1 +
>  lib/hashtable.c  |  721 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 828 insertions(+), 0 deletions(-)
>  create mode 100644 include/search.h
>  create mode 100644 lib/hashtable.c

Applied to "next" branch.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
It seems intuitively obvious to me, which  means  that  it  might  be
wrong.                                                 -- Chris Torek

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 4/5] Remove support for CONFIG_HAS_UID and "forceenv" command
  2010-07-17 19:45 ` [U-Boot] [PATCH 4/5] Remove support for CONFIG_HAS_UID and "forceenv" command Wolfgang Denk
  2010-07-17 22:12   ` Sergey Kubushyn
@ 2010-09-12 19:18   ` Wolfgang Denk
  1 sibling, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-09-12 19:18 UTC (permalink / raw)
  To: u-boot

Dear Wolfgang Denk,

In message <1279395948-25864-5-git-send-email-wd@denx.de> you wrote:
> This (undocumented) concept was only in use for the MVSMR and
> davinci_schmoogie Sergey Kubushyn <ksi@koi8.net> boards.
> Drop it for now.  If really needed, it should be reimplemented
> later in the context of the new environment command set.
> 
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Cc: Andre Schwarz <andre.schwarz@matrix-vision.de>
> Cc: Sergey Kubushyn <ksi@koi8.net>
> ---
>  common/cmd_nvedit.c                 |   13 -------------
>  common/exports.c                    |    3 ---
>  include/_exports.h                  |    1 -
>  include/common.h                    |    3 ---
>  include/configs/MVSMR.h             |    1 -
>  include/configs/davinci_schmoogie.h |    1 -
>  include/exports.h                   |    3 ---
>  7 files changed, 0 insertions(+), 25 deletions(-)

Applied to "next" branch.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
It may be that your whole purpose in life is simply  to  serve  as  a
warning to others.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables.
  2010-07-17 19:45 ` [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables Wolfgang Denk
                     ` (2 preceding siblings ...)
  2010-07-26 14:52   ` Matthias Fuchs
@ 2010-09-12 19:19   ` Wolfgang Denk
  2010-12-30  1:53   ` [U-Boot] env_flash.c:saveenv() broken when env is smaller than a sector Mike Frysinger
  4 siblings, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-09-12 19:19 UTC (permalink / raw)
  To: u-boot

Dear Wolfgang Denk,

In message <1279395948-25864-6-git-send-email-wd@denx.de> you wrote:
> Motivation:
> 
> * Old environment code used a pessimizing implementation:
>   - variable lookup used linear search => slow
>   - changed/added variables were added at the end, i. e. most
>     frequently used variables had the slowest access times => slow
>   - each setenv() would calculate the CRC32 checksum over the whole
>     environment block => slow
> * "redundant" envrionment was locked down to two copies
> * No easy way to implement features like "reset to factory defaults",
>   or to select one out of several pre-defined (previously saved) sets
>   of environment settings ("profiles")
> * No easy way to import or export environment settings
> 
> ======================================================================
> 
> API Changes:
> 
> - Variable names starting with '#' are no longer allowed
> 
>   I didn't find any such variable names being used; it is highly
>   recommended to follow standard conventions and start variable names
>   with an alphanumeric character
> 
> - "printenv" will now print a backslash at the end of all but the last
>   lines of a multi-line variable value.
> 
>   Multi-line variables have never been formally defined, allthough
>   there is no reason not to use them. Now we define rules how to deal
>   with them, allowing for import and export.
> 
> - Function forceenv() and the related code in saveenv() was removed.
>   At the moment this is causing build problems for the only user of
>   this code (schmoogie - which has no entry in MAINTAINERS); may be
>   fixed later by implementing the "env set -f" feature.
> 
> Inconsistencies:
> 
> - "printenv" will '\\'-escape the '\n' in multi-line variables, while
>   "printenv var" will not do that.
> 
> ======================================================================
> 
> Advantages:
> 
> - "printenv" output much better readable (sorted)
> - faster!
> - extendable (additional variable properties can be added)
> - new, powerful features like "factory reset" or easy switching
>   between several different environment settings ("profiles")
> 
> Disadvantages:
> 
> - Image size grows by typically 5...7 KiB (might shrink a bit again on
>   systems with redundant environment with a following patch series)
> 
> ======================================================================
> 
> Implemented:
> 
> - env command with subcommands:
> 
>   - env print [arg ...]
> 
>     same as "printenv": print environment
> 
>   - env set [-f] name [arg ...]
> 
>     same as "setenv": set (and delete) environment variables
> 
>     ["-f" - force setting even for read-only variables - not
>     implemented yet.]
> 
>   - end delete [-f] name
> 
>     not implemented yet
> 
>     ["-f" - force delete even for read-only variables]
> 
>   - env save
> 
>     same as "saveenv": save environment
> 
>   - env export [-t | -b | -c] addr [size]
> 
>     export internal representation (hash table) in formats usable for
>     persistent storage or processing:
> 
> 	-t:	export as text format; if size is given, data will be
> 		padded with '\0' bytes; if not, one terminating '\0'
> 		will be added (which is included in the "filesize"
> 		setting so you can for exmple copy this to flash and
> 		keep the termination).
> 	-b:	export as binary format (name=value pairs separated by
> 		'\0', list end marked by double "\0\0")
> 	-c:	export as checksum protected environment format as
> 		used for example by "saveenv" command
> 	addr:	memory address where environment gets stored
> 	size:	size of output buffer
> 
> 	With "-c" and size is NOT given, then the export command will
> 	format the data as currently used for the persistent storage,
> 	i. e. it will use CONFIG_ENV_SECT_SIZE as output block size and
> 	prepend a valid CRC32 checksum and, in case of resundant
> 	environment, a "current" redundancy flag. If size is given, this
> 	value will be used instead of CONFIG_ENV_SECT_SIZE; again, CRC32
> 	checksum and redundancy flag will be inserted.
> 
> 	With "-b" and "-t", always only the real data (including a
> 	terminating '\0' byte) will be written; here the optional size
> 	argument will be used to make sure not to overflow the user
> 	provided buffer; the command will abort if the size is not
> 	sufficient. Any remainign space will be '\0' padded.
> 
>         On successful return, the variable "filesize" will be set.
>         Note that filesize includes the trailing/terminating '\0'
>         byte(s).
> 
>         Usage szenario: create a text snapshot/backup of the current
> 	settings:
> 
> 		=> env export -t 100000
> 		=> era ${backup_addr} +${filesize}
> 		=> cp.b 100000 ${backup_addr} ${filesize}
> 
> 	Re-import this snapshot, deleting all other settings:
> 
> 		=> env import -d -t ${backup_addr}
> 
>   - env import [-d] [-t | -b | -c] addr [size]
> 
>     import external format (text or binary) into hash table,
>     optionally deleting existing values:
> 
> 	-d:	delete existing environment before importing;
> 		otherwise overwrite / append to existion definitions
> 	-t:	assume text format; either "size" must be given or the
> 		text data must be '\0' terminated
> 	-b:	assume binary format ('\0' separated, "\0\0" terminated)
> 	-c:	assume checksum protected environment format
> 	addr:	memory address to read from
> 	size:	length of input data; if missing, proper '\0'
> 		termination is mandatory
> 
>   - env default -f
> 
>     reset default environment: drop all environment settings and load
>     default environment
> 
>   - env ask name [message] [size]
> 
>     same as "askenv": ask for environment variable
> 
>   - env edit name
> 
>     same as "editenv": edit environment variable
> 
>   - env run
> 
>     same as "run": run commands in an environment variable
> 
> ======================================================================
> 
> TODO:
> 
> - drop default env as implemented now; provide a text file based
>   initialization instead (eventually using several text files to
>   incrementally build it from common blocks) and a tool to convert it
>   into a binary blob / object file.
> 
> - It would be nice if we could add wildcard support for environment
>   variables; this is needed for variable name auto-completion,
>   but it would also be nice to be able to say "printenv ip*" or
>   "printenv *addr*"
> 
> - Some boards don't link any more due to the grown code size:
>   AR405, CANBT, DU405, PMC440, canyonlands, sc3, sequoia, socrates.
> 
> 	=> cc: Matthias Fuchs <matthias.fuchs@esd-electronics.com>,
> 	       Stefan Roese <sr@denx.de>,
> 	       Heiko Schocher <hs@denx.de>
> 
> - Dropping forceenv() causes build problems on schmoogie
> 
> 	=> cc: Sergey Kubushyn <ksi@koi8.net>
> 
> - Build tested on PPC and ARM only; runtime tested with NOR and NAND
>   flash only => needs testing!!
> 
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Cc: Matthias Fuchs <matthias.fuchs@esd-electronics.com>,
> Cc: Stefan Roese <sr@denx.de>,
> Cc: Heiko Schocher <hs@denx.de>
> Cc: Sergey Kubushyn <ksi@koi8.net>
> ---
>  README                 |    8 +
>  board/zeus/zeus.c      |   25 +--
>  common/cmd_nvedit.c    |  655 +++++++++++++++++++++++++++++++++---------------
>  common/command.c       |    3 +-
>  common/dlmalloc.c      |   25 +-
>  common/env_common.c    |  125 +++++-----
>  common/env_dataflash.c |  114 ++++++----
>  common/env_eeprom.c    |   85 ++++---
>  common/env_flash.c     |  245 ++++++++++---------
>  common/env_mgdisk.c    |   33 +--
>  common/env_nand.c      |  188 ++++++++------
>  common/env_nowhere.c   |   11 +-
>  common/env_nvram.c     |   46 +++-
>  common/env_onenand.c   |   65 +++---
>  common/env_sf.c        |  132 ++++++-----
>  common/exports.c       |    1 -
>  include/environment.h  |    5 +-
>  lib/hashtable.c        |   32 ++-
>  18 files changed, 1094 insertions(+), 704 deletions(-)

Applied to "next" branch.

[With changes as suggested by Matthias Fuchs - thanks!]

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
What is tolerance? -- it is the consequence of humanity. We  are  all
formed  of frailty and error; let us pardon reciprocally each other's
folly -- that is the first law of nature.                  - Voltaire

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-07-17 19:45 [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
                   ` (7 preceding siblings ...)
  2010-07-17 21:55 ` Wolfgang Denk
@ 2010-10-20  8:08 ` Mike Frysinger
  2010-10-20  8:19   ` Wolfgang Denk
  2010-12-08  9:56 ` Mike Frysinger
  9 siblings, 1 reply; 53+ messages in thread
From: Mike Frysinger @ 2010-10-20  8:08 UTC (permalink / raw)
  To: u-boot

On Saturday, July 17, 2010 15:45:43 Wolfgang Denk wrote:
> The following patch series adds some utilities (qsort and hash table
> based database functions) and uses these to reimplement the code used
> for the internal handling of environment variables.

seems to break autocompletion CONFIG_AUTO_COMPLETE :(

if i checkout the previous commit (0fe247b973d9b8f7e2c04cc159fcdd2e64591e55), 
things work fine.  but checking out the env change and it no longer works.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20101020/efa120a3/attachment.pgp 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-10-20  8:08 ` Mike Frysinger
@ 2010-10-20  8:19   ` Wolfgang Denk
  0 siblings, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2010-10-20  8:19 UTC (permalink / raw)
  To: u-boot

Dear Mike Frysinger,

In message <201010200408.15020.vapier@gentoo.org> you wrote:
>
> > The following patch series adds some utilities (qsort and hash table
> > based database functions) and uses these to reimplement the code used
> > for the internal handling of environment variables.
> 
> seems to break autocompletion CONFIG_AUTO_COMPLETE :(

Yes, this was already noted and discussed before.

I'm still not sure how to (re-) add this optimally.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
It became apparent that one reason why the Ice Giants were  known  as
the  Ice  Giants  was  because they were, well, giants. The other was
that they were made of ice.              -Terry Pratchett, _Sourcery_

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 3/5] Add hash table support as base for new environment code
  2010-07-17 19:45 ` [U-Boot] [PATCH 3/5] Add hash table support as base for new environment code Wolfgang Denk
  2010-09-12 19:16   ` Wolfgang Denk
@ 2010-12-08  9:44   ` Mike Frysinger
  2010-12-08 10:02     ` Wolfgang Denk
  1 sibling, 1 reply; 53+ messages in thread
From: Mike Frysinger @ 2010-12-08  9:44 UTC (permalink / raw)
  To: u-boot

On Saturday, July 17, 2010 15:45:46 Wolfgang Denk wrote:
> This implementation is based on code from uClibc-0.9.30.3 but was
> modified and extended for use within U-Boot.

unless i'm missing something, the non-reentrant versions operate on a single 
shared hash table.  so while this works today because there is only one 
consumer (the env code), wont this cause problems as soon as someone else 
tries to use the non-reentrant hash table code ?  as such, wouldnt it make 
sense to punt all of the non-reentrant versions and thus force everyone to 
maintain their own "struct hsearch_data" instance ?
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20101208/3d9a27f3/attachment.pgp 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-07-17 19:45 [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
                   ` (8 preceding siblings ...)
  2010-10-20  8:08 ` Mike Frysinger
@ 2010-12-08  9:56 ` Mike Frysinger
  2010-12-08 10:04   ` Wolfgang Denk
  9 siblings, 1 reply; 53+ messages in thread
From: Mike Frysinger @ 2010-12-08  9:56 UTC (permalink / raw)
  To: u-boot

On Saturday, July 17, 2010 15:45:43 Wolfgang Denk wrote:
> TODO:
> 
> - drop default env as implemented now; provide a text file based
>   initialization instead (eventually using several text files to
>   incrementally build it from common blocks) and a tool to convert it
>   into a binary blob / object file.
> 
> - It would be nice if we could add wildcard support for environment
>   variables; this is needed for variable name auto-completion,
>   but it would also be nice to be able to say "printenv ip*" or
>   "printenv *addr*"
> 
> - Some boards don't link any more due to the grown code size:
>   AR405, CANBT, DU405, PMC440, canyonlands, sc3, sequoia, socrates.
> 
> 	=> cc: Matthias Fuchs <matthias.fuchs@esd-electronics.com>,
> 	       Stefan Roese <sr@denx.de>,
> 	       Heiko Schocher <hs@denx.de>
> 
> - Dropping forceenv() causes build problems on schmoogie
> 
> 	=> cc: Sergey Kubushyn <ksi@koi8.net>
> 
> - Build tested on PPC and ARM only; runtime tested with NOR and NAND
>   flash only => needs testing!!

seems that some todo items are missing, or not well implied.  for example, it 
seems that gd->env_addr needs to be punted, and these functions get a "_f" 
appended to their name since they only work on default_environment[] now:
	env_get_addr()
	env_get_char()
	env_get_char_memory()
	envmatch()
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20101208/1eb3dd09/attachment.pgp 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 3/5] Add hash table support as base for new environment code
  2010-12-08  9:44   ` Mike Frysinger
@ 2010-12-08 10:02     ` Wolfgang Denk
  2010-12-08 10:52       ` Mike Frysinger
  0 siblings, 1 reply; 53+ messages in thread
From: Wolfgang Denk @ 2010-12-08 10:02 UTC (permalink / raw)
  To: u-boot

Dear Mike Frysinger,

In message <201012080444.30675.vapier@gentoo.org> you wrote:
>
> unless i'm missing something, the non-reentrant versions operate on a single 
> shared hash table.  so while this works today because there is only one 

Correct.

> consumer (the env code), wont this cause problems as soon as someone else 
> tries to use the non-reentrant hash table code ?  as such, wouldnt it make
> sense to punt all of the non-reentrant versions and thus force everyone to
> maintain their own "struct hsearch_data" instance ?

This could be done, but I don't see an immediate need.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
I've already got a female to worry about. Her name is the Enterprise.
	-- Kirk, "The Corbomite Maneuver", stardate 1514.0

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-12-08  9:56 ` Mike Frysinger
@ 2010-12-08 10:04   ` Wolfgang Denk
  2010-12-08 10:19     ` Mike Frysinger
  0 siblings, 1 reply; 53+ messages in thread
From: Wolfgang Denk @ 2010-12-08 10:04 UTC (permalink / raw)
  To: u-boot

Dear Mike Frysinger,

In message <201012080456.41492.vapier@gentoo.org> you wrote:
>
> seems that some todo items are missing, or not well implied.  for example, it 
> seems that gd->env_addr needs to be punted, and these functions get a "_f"
> appended to their name since they only work on default_environment[] now:
> 	env_get_addr()
> 	env_get_char()
> 	env_get_char_memory()
> 	envmatch()

I'm not sure I understand what you mean.

These functions not NOT only operate on the default_environment[];
they are also used to access the normal environment before
relocation.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"If that makes any sense to you, you have a big problem."
                                  -- C. Durance, Computer Science 234

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 0/5] New environment code
  2010-12-08 10:04   ` Wolfgang Denk
@ 2010-12-08 10:19     ` Mike Frysinger
  0 siblings, 0 replies; 53+ messages in thread
From: Mike Frysinger @ 2010-12-08 10:19 UTC (permalink / raw)
  To: u-boot

On Wednesday, December 08, 2010 05:04:42 Wolfgang Denk wrote:
> Mike Frysinger wrote:
> > seems that some todo items are missing, or not well implied.  for
> > example, it seems that gd->env_addr needs to be punted, and these
> > functions get a "_f" appended to their name since they only work on
> > default_environment[] now:
> > 	env_get_addr()
> > 	env_get_char()
> > 	env_get_char_memory()
> > 	envmatch()
> 
> I'm not sure I understand what you mean.
> 
> These functions not NOT only operate on the default_environment[];
> they are also used to access the normal environment before
> relocation.

my point is that they cannot be used after relocation and once the env is 
moved into the hash table.  currently, they dont return any errors if someone 
attempts to do so and while it might seem like the funcs are working, they 
only parse the default env.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20101208/71915c79/attachment.pgp 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] [PATCH 3/5] Add hash table support as base for new environment code
  2010-12-08 10:02     ` Wolfgang Denk
@ 2010-12-08 10:52       ` Mike Frysinger
  0 siblings, 0 replies; 53+ messages in thread
From: Mike Frysinger @ 2010-12-08 10:52 UTC (permalink / raw)
  To: u-boot

On Wednesday, December 08, 2010 05:02:38 Wolfgang Denk wrote:
> Mike Frysinger wrote:
> > unless i'm missing something, the non-reentrant versions operate on a
> > single shared hash table.  so while this works today because there is
> > only one
> 
> Correct.
> 
> > consumer (the env code), wont this cause problems as soon as someone else
> > tries to use the non-reentrant hash table code ?  as such, wouldnt it
> > make sense to punt all of the non-reentrant versions and thus force
> > everyone to maintain their own "struct hsearch_data" instance ?
> 
> This could be done, but I don't see an immediate need.

off the top of my head:
 - it isnt obvious to people today that this issue exists, so anyone 
attempting to use the fun new hashtable code could conceivably use it without 
running into a problem (as long as their keys dont happen to collide with env 
names).  so people could possibly waste quite a bit of their time trying to 
track down bugs that only crop up when certain env vars are set.
 - i imagine a bit of space is being wasted here.
 - i re-implemented env-autocomplete, but i need access to the hashtable 
structure where everything is stored.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20101208/f9f23b19/attachment.pgp 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] env_flash.c:saveenv() broken when env is smaller than a sector
  2010-07-17 19:45 ` [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables Wolfgang Denk
                     ` (3 preceding siblings ...)
  2010-09-12 19:19   ` Wolfgang Denk
@ 2010-12-30  1:53   ` Mike Frysinger
  2010-12-30  2:39     ` Mike Frysinger
  4 siblings, 1 reply; 53+ messages in thread
From: Mike Frysinger @ 2010-12-30  1:53 UTC (permalink / raw)
  To: u-boot

On Saturday, July 17, 2010 15:45:48 Wolfgang Denk wrote:
> --- a/common/env_flash.c
> +++ b/common/env_flash.c
>  #ifdef CMD_SAVEENV
>  int saveenv(void)
>  {
> -	char *saved_data = NULL;
> -	int rc = 1;
> -	char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
> +	env_t	env_new;
> +	ssize_t	len;
> +	char	*saved_data = NULL;
> +	char	*res;
> +	int	rc = 1;
> +	char	flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
>  #if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
> -	ulong up_data = 0;
> +	ulong	up_data = 0;
>  #endif
> 
> -	debug ("Protect off %08lX ... %08lX\n",
> +	debug("Protect off %08lX ... %08lX\n",
>  		(ulong)flash_addr, end_addr);
> 
> -	if (flash_sect_protect (0, (ulong)flash_addr, end_addr)) {
> -		goto Done;
> +	if (flash_sect_protect(0, (ulong)flash_addr, end_addr)) {
> +		goto done;
>  	}
> 
> -	debug ("Protect off %08lX ... %08lX\n",
> +	debug("Protect off %08lX ... %08lX\n",
>  		(ulong)flash_addr_new, end_addr_new);
> 
> -	if (flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new)) {
> -		goto Done;
> +	if (flash_sect_protect(0, (ulong)flash_addr_new, end_addr_new)) {
> +		goto done;
> +	}
> +
> +	res = (char *)&env_new.data;
> +	len = hexport('\0', &res, ENV_SIZE);
> +	if (len < 0) {
> +		error("Cannot export environment: errno = %d\n", errno);
> +		goto done;
>  	}
> +	env_new.crc   = crc32(0, env_new.data, ENV_SIZE);
> +	env_new.flags = new_flag;
> 
>  #if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
>  	up_data = (end_addr_new + 1 - ((long)flash_addr_new + CONFIG_ENV_SIZE));
> -	debug ("Data to save 0x%x\n", up_data);
> +	debug("Data to save 0x%lX\n", up_data);
>  	if (up_data) {
>  		if ((saved_data = malloc(up_data)) == NULL) {
>  			printf("Unable to save the rest of sector (%ld)\n",
>  				up_data);
> -			goto Done;
> +			goto done;
>  		}
>  		memcpy(saved_data,
>  			(void *)((long)flash_addr_new + CONFIG_ENV_SIZE), up_data);
> -		debug ("Data (start 0x%x, len 0x%x) saved at 0x%x\n",
> -			   (long)flash_addr_new + CONFIG_ENV_SIZE,
> -				up_data, saved_data);
> +		debug("Data (start 0x%lX, len 0x%lX) saved at 0x%p\n",
> +			(long)flash_addr_new + CONFIG_ENV_SIZE,
> +			up_data, saved_data);
>  	}
>  #endif
> -	puts ("Erasing Flash...");
> -	debug (" %08lX ... %08lX ...",
> +	puts("Erasing Flash...");
> +	debug(" %08lX ... %08lX ...",
>  		(ulong)flash_addr_new, end_addr_new);
> 
> -	if (flash_sect_erase ((ulong)flash_addr_new, end_addr_new)) {
> -		goto Done;
> +	if (flash_sect_erase((ulong)flash_addr_new, end_addr_new)) {
> +		goto done;
>  	}
> 
> -	puts ("Writing to Flash... ");
> -	debug (" %08lX ... %08lX ...",
> +	puts("Writing to Flash... ");
> +	debug(" %08lX ... %08lX ...",
>  		(ulong)&(flash_addr_new->data),
>  		sizeof(env_ptr->data)+(ulong)&(flash_addr_new->data));
> -	if ((rc = flash_write((char *)env_ptr->data,
> -			(ulong)&(flash_addr_new->data),
> -			sizeof(env_ptr->data))) ||
> -	    (rc = flash_write((char *)&(env_ptr->crc),
> -			(ulong)&(flash_addr_new->crc),
> -			sizeof(env_ptr->crc))) ||
> +	if ((rc = flash_write((char *)&env_new,
> +			(ulong)flash_addr_new,
> +			sizeof(env_new))) ||
>  	    (rc = flash_write(&flag,
>  			(ulong)&(flash_addr->flags),
> -			sizeof(flash_addr->flags))) ||
> -	    (rc = flash_write(&new_flag,
> -			(ulong)&(flash_addr_new->flags),
> -			sizeof(flash_addr_new->flags))))
> -	{
> -		flash_perror (rc);
> -		goto Done;
> +			sizeof(flash_addr->flags))) ) {
> +		flash_perror(rc);
> +		goto done;
>  	}
> -	puts ("done\n");
> 
>  #if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
>  	if (up_data) { /* restore the rest of sector */
> -		debug ("Restoring the rest of data to 0x%x len 0x%x\n",
> -			   (long)flash_addr_new + CONFIG_ENV_SIZE, up_data);
> +		debug("Restoring the rest of data to 0x%lX len 0x%lX\n",
> +			(long)flash_addr_new + CONFIG_ENV_SIZE, up_data);
>  		if (flash_write(saved_data,
>  				(long)flash_addr_new + CONFIG_ENV_SIZE,
>  				up_data)) {
>  			flash_perror(rc);
> -			goto Done;
> +			goto done;
>  		}
>  	}
>  #endif
> +	puts("done\n");
> +
>  	{
>  		env_t * etmp = flash_addr;
>  		ulong ltmp = end_addr;
> @@ -220,13 +230,12 @@ int saveenv(void)
>  	}
> 
>  	rc = 0;
> -Done:
> -
> +done:
>  	if (saved_data)
> -		free (saved_data);
> +		free(saved_data);
>  	/* try to re-protect */
> -	(void) flash_sect_protect (1, (ulong)flash_addr, end_addr);
> -	(void) flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
> +	(void) flash_sect_protect(1, (ulong)flash_addr, end_addr);
> +	(void) flash_sect_protect(1, (ulong)flash_addr_new, end_addr_new);
> 
>  	return rc;
>  }
> @@ -244,83 +253,93 @@ int  env_init(void)
> 
>  	gd->env_addr  = (ulong)&default_environment[0];
>  	gd->env_valid = 0;
> -	return (0);
> +	return 0;
>  }
> 
>  #ifdef CMD_SAVEENV
> 
>  int saveenv(void)
>  {
> -	int	len, rc;
> -	ulong	end_addr;
> -	ulong	flash_sect_addr;
> -#if defined(CONFIG_ENV_SECT_SIZE) && (CONFIG_ENV_SECT_SIZE >
> CONFIG_ENV_SIZE) -	ulong	flash_offset;
> -	uchar	env_buffer[CONFIG_ENV_SECT_SIZE];
> -#else
> -	uchar *env_buffer = (uchar *)env_ptr;
> -#endif	/* CONFIG_ENV_SECT_SIZE */
> -	int rcode = 0;
> -
> -#if defined(CONFIG_ENV_SECT_SIZE) && (CONFIG_ENV_SECT_SIZE >
> CONFIG_ENV_SIZE) -
> -	flash_offset    = ((ulong)flash_addr) & (CONFIG_ENV_SECT_SIZE-1);
> -	flash_sect_addr = ((ulong)flash_addr) & ~(CONFIG_ENV_SECT_SIZE-1);
> -
> -	debug ( "copy old content: "
> -		"sect_addr: %08lX  env_addr: %08lX  offset: %08lX\n",
> -		flash_sect_addr, (ulong)flash_addr, flash_offset);
> -
> -	/* copy old contents to temporary buffer */
> -	memcpy (env_buffer, (void *)flash_sect_addr, CONFIG_ENV_SECT_SIZE);
> -
> -	/* copy current environment to temporary buffer */
> -	memcpy ((uchar *)((unsigned long)env_buffer + flash_offset),
> -		env_ptr,
> -		CONFIG_ENV_SIZE);
> +	env_t	env_new;
> +	ssize_t	len;
> +	int	rc = 1;
> +	char	*res;
> +	char	*saved_data = NULL;
> +#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
> +	ulong	up_data = 0;
> 
> -	len	 = CONFIG_ENV_SECT_SIZE;
> -#else
> -	flash_sect_addr = (ulong)flash_addr;
> -	len	 = CONFIG_ENV_SIZE;
> +	up_data = (end_addr + 1 - ((long)flash_addr + CONFIG_ENV_SIZE));
> +	debug("Data to save 0x%lx\n", up_data);
> +	if (up_data) {
> +		if ((saved_data = malloc(up_data)) == NULL) {
> +			printf("Unable to save the rest of sector (%ld)\n",
> +				up_data);
> +			goto done;
> +		}
> +		memcpy(saved_data,
> +			(void *)((long)flash_addr + CONFIG_ENV_SIZE), up_data);
> +		debug("Data (start 0x%lx, len 0x%lx) saved at 0x%lx\n",
> +			(ulong)flash_addr + CONFIG_ENV_SIZE,
> +			up_data,
> +			(ulong)saved_data);
> +	}
>  #endif	/* CONFIG_ENV_SECT_SIZE */
> 
> -	end_addr = flash_sect_addr + len - 1;
> +	debug("Protect off %08lX ... %08lX\n",
> +		(ulong)flash_addr, end_addr);
> 
> -	debug ("Protect off %08lX ... %08lX\n",
> -		(ulong)flash_sect_addr, end_addr);
> +	if (flash_sect_protect(0, (long)flash_addr, end_addr))
> +		goto done;
> 
> -	if (flash_sect_protect (0, flash_sect_addr, end_addr))
> -		return 1;
> +	res = (char *)&env_new.data;
> +	len = hexport('\0', &res, ENV_SIZE);
> +	if (len < 0) {
> +		error("Cannot export environment: errno = %d\n", errno);
> +		goto done;
> +	}
> +	env_new.crc = crc32(0, env_new.data, ENV_SIZE);
> 
> -	puts ("Erasing Flash...");
> -	if (flash_sect_erase (flash_sect_addr, end_addr))
> -		return 1;
> +	puts("Erasing Flash...");
> +	if (flash_sect_erase((long)flash_addr, end_addr))
> +		goto done;
> 
> -	puts ("Writing to Flash... ");
> -	rc = flash_write((char *)env_buffer, flash_sect_addr, len);
> +	puts("Writing to Flash... ");
> +	rc = flash_write((char *)&env_new, (long)flash_addr, CONFIG_ENV_SIZE);
>  	if (rc != 0) {
> -		flash_perror (rc);
> -		rcode = 1;
> -	} else {
> -		puts ("done\n");
> +		flash_perror(rc);
> +		goto done;
>  	}
> -
> +#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
> +	if (up_data) {	/* restore the rest of sector */
> +		debug("Restoring the rest of data to 0x%lx len 0x%lx\n",
> +			(ulong)flash_addr + CONFIG_ENV_SIZE, up_data);
> +		if (flash_write(saved_data,
> +				(long)flash_addr + CONFIG_ENV_SIZE,
> +				up_data)) {
> +			flash_perror(rc);
> +			goto done;
> +		}
> +	}
> +#endif
> +	puts("done\n");
> +	rc = 0;
> +done:
> +	if (saved_data)
> +		free(saved_data);
>  	/* try to re-protect */
> -	(void) flash_sect_protect (1, flash_sect_addr, end_addr);
> -	return rcode;
> +	(void) flash_sect_protect(1, (long)flash_addr, end_addr);
> +	return rc;
>  }

it would seem that somewhere nestled in this rewrite, support for embedded env 
was broken (CONFIG_ENV_SIZE < CONFIG_ENV_SECT_SIZE).  on a bf548-ezkit for 
example, i see this behavior:

(v2010.09 / before this commit):
bfin> save
Saving Environment to Flash...
. done
Un-Protected 1 sectors
Erasing Flash...
. done
Erased 1 sectors
Writing to Flash... done
. done
Protected 1 sectors

(after this commit / v2010.12):
bfin> save
Saving Environment to Flash...
Error: start address not on sector boundary
Error: start address not on sector boundary

not sure if anyone has noticed/fixed this yet and would save me from the 
trouble of finding/fixing the problem ...
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20101229/14330289/attachment.pgp 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] env_flash.c:saveenv() broken when env is smaller than a sector
  2010-12-30  1:53   ` [U-Boot] env_flash.c:saveenv() broken when env is smaller than a sector Mike Frysinger
@ 2010-12-30  2:39     ` Mike Frysinger
  2011-01-17 20:23       ` Wolfgang Denk
  0 siblings, 1 reply; 53+ messages in thread
From: Mike Frysinger @ 2010-12-30  2:39 UTC (permalink / raw)
  To: u-boot

On Wednesday, December 29, 2010 20:53:17 Mike Frysinger wrote:
> On Saturday, July 17, 2010 15:45:48 Wolfgang Denk wrote:
> > --- a/common/env_flash.c
> > +++ b/common/env_flash.c
> >  int saveenv(void)
> >  {
> > 
> > -	int	len, rc;
> > -	ulong	end_addr;
> > -	ulong	flash_sect_addr;
> > -#if defined(CONFIG_ENV_SECT_SIZE) && (CONFIG_ENV_SECT_SIZE >
> > CONFIG_ENV_SIZE) -	ulong	flash_offset;
> > -	uchar	env_buffer[CONFIG_ENV_SECT_SIZE];
> > -#else
> > -	uchar *env_buffer = (uchar *)env_ptr;
> > -#endif	/* CONFIG_ENV_SECT_SIZE */
> > -	int rcode = 0;
> > -
> > -#if defined(CONFIG_ENV_SECT_SIZE) && (CONFIG_ENV_SECT_SIZE >
> > CONFIG_ENV_SIZE) -
> > -	flash_offset    = ((ulong)flash_addr) & (CONFIG_ENV_SECT_SIZE-1);
> > -	flash_sect_addr = ((ulong)flash_addr) & ~(CONFIG_ENV_SECT_SIZE-1);
> > -
> > -	debug ( "copy old content: "
> > -		"sect_addr: %08lX  env_addr: %08lX  offset: %08lX\n",
> > -		flash_sect_addr, (ulong)flash_addr, flash_offset);
> > -
> > -	/* copy old contents to temporary buffer */
> > -	memcpy (env_buffer, (void *)flash_sect_addr, CONFIG_ENV_SECT_SIZE);
> > -
> > -	/* copy current environment to temporary buffer */
> > -	memcpy ((uchar *)((unsigned long)env_buffer + flash_offset),
> > -		env_ptr,
> > -		CONFIG_ENV_SIZE);
> > +	env_t	env_new;
> > +	ssize_t	len;
> > +	int	rc = 1;
> > +	char	*res;
> > +	char	*saved_data = NULL;
> > +#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
> > +	ulong	up_data = 0;
> > 
> > -	len	 = CONFIG_ENV_SECT_SIZE;
> > -#else
> > -	flash_sect_addr = (ulong)flash_addr;
> > -	len	 = CONFIG_ENV_SIZE;
> > +	up_data = (end_addr + 1 - ((long)flash_addr + CONFIG_ENV_SIZE));
> > +	debug("Data to save 0x%lx\n", up_data);
> > +	if (up_data) {
> > +		if ((saved_data = malloc(up_data)) == NULL) {
> > +			printf("Unable to save the rest of sector (%ld)\n",
> > +				up_data);
> > +			goto done;
> > +		}
> > +		memcpy(saved_data,
> > +			(void *)((long)flash_addr + CONFIG_ENV_SIZE), up_data);
> > +		debug("Data (start 0x%lx, len 0x%lx) saved at 0x%lx\n",
> > +			(ulong)flash_addr + CONFIG_ENV_SIZE,
> > +			up_data,
> > +			(ulong)saved_data);
> > +	}
> > 
> >  #endif	/* CONFIG_ENV_SECT_SIZE */
> 
> it would seem that somewhere nestled in this rewrite, support for embedded
> env was broken (CONFIG_ENV_SIZE < CONFIG_ENV_SECT_SIZE).  on a bf548-ezkit
> for example, i see this behavior:
> 
> (v2010.09 / before this commit):
> bfin> save
> Saving Environment to Flash...
> . done
> Un-Protected 1 sectors
> Erasing Flash...
> . done
> Erased 1 sectors
> Writing to Flash... done
> . done
> Protected 1 sectors
> 
> (after this commit / v2010.12):
> bfin> save
> Saving Environment to Flash...
> Error: start address not on sector boundary
> Error: start address not on sector boundary
> 
> not sure if anyone has noticed/fixed this yet and would save me from the
> trouble of finding/fixing the problem ...

seems the new saveenv code in the non-redund case has been rewritten 
completely and doesn't support the same feature set as it used to.

old behavior:
 - load up the entire sector
 - overlay new env into sector
 - round env start addr down to sector start
 - round env end addr up to sector end
 - protect/erase/save/protect whole sector

new behavior:
 - load up the sector data after the env
 - overlay new env into sector
 - set env end addr to start of env plus one sector
 - protect/erase/save/protect whole sector

so the difference is that the new code no longer supports envs which do not 
start on a sector boundary.  it does this so that it doesn't memcpy() as much 
data out of the flash at the expense of doing more CPU bound math operations 
(mostly bit twiddling).

so the question is whether the old behavior should be restored.  if it not, 
the documentation should be tweaked to note these requirements and some simple 
CPP checks added to environment.h so that this issue turns into a build 
failure.  after all, it's easy to detect an env offset that isnt at the start 
of the sector:
	#if (CONFIG_ENV_OFFSET & (CONFIG_ENV_SECT_SIZE - 1))
	# error env offset not sector aligned
	#endif
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20101229/e28b1c0f/attachment.pgp 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* [U-Boot] env_flash.c:saveenv() broken when env is smaller than a sector
  2010-12-30  2:39     ` Mike Frysinger
@ 2011-01-17 20:23       ` Wolfgang Denk
  0 siblings, 0 replies; 53+ messages in thread
From: Wolfgang Denk @ 2011-01-17 20:23 UTC (permalink / raw)
  To: u-boot

Dear Mike Frysinger,

In message <201012292139.05901.vapier@gentoo.org> you wrote:
>
> seems the new saveenv code in the non-redund case has been rewritten 
> completely and doesn't support the same feature set as it used to.
...
> so the difference is that the new code no longer supports envs which do not
> start on a sector boundary.  it does this so that it doesn't memcpy() as much 
> data out of the flash at the expense of doing more CPU bound math operations 
> (mostly bit twiddling).
> 
> so the question is whether the old behavior should be restored.  if it not,

The change was not intentional. Sorry.

I don't have a clear opinion if it's worth the effort to restore
the old behavior - it seems it has never been used much (OK, you did).

> the documentation should be tweaked to note these requirements and some simple 
> CPP checks added to environment.h so that this issue turns into a build 
> failure.  after all, it's easy to detect an env offset that isnt at the start 
> of the sector:
> 	#if (CONFIG_ENV_OFFSET & (CONFIG_ENV_SECT_SIZE - 1))
> 	# error env offset not sector aligned
> 	#endif

I agree that adding such a test would be a good thing - please submit
a patch.  Or one to restore the old behaviour, if you prefer.

Thanks.


Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
e-credibility: the non-guaranteeable likelihood that  the  electronic
data you're seeing is genuine rather than somebody's made-up crap.
- Karl Lehenbauer

^ permalink raw reply	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2011-01-17 20:23 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-17 19:45 [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
2010-07-17 19:45 ` [U-Boot] [PATCH 1/5] Add basic errno support Wolfgang Denk
2010-07-17 21:17   ` Mike Frysinger
2010-07-17 21:34     ` Wolfgang Denk
2010-07-18 12:51     ` Jerry Van Baren
2010-07-18 13:03       ` Wolfgang Denk
2010-09-12 19:16   ` Wolfgang Denk
2010-07-17 19:45 ` [U-Boot] [PATCH 2/5] Add qsort - add support for sorting data arrays Wolfgang Denk
2010-09-12 19:16   ` Wolfgang Denk
2010-07-17 19:45 ` [U-Boot] [PATCH 3/5] Add hash table support as base for new environment code Wolfgang Denk
2010-09-12 19:16   ` Wolfgang Denk
2010-12-08  9:44   ` Mike Frysinger
2010-12-08 10:02     ` Wolfgang Denk
2010-12-08 10:52       ` Mike Frysinger
2010-07-17 19:45 ` [U-Boot] [PATCH 4/5] Remove support for CONFIG_HAS_UID and "forceenv" command Wolfgang Denk
2010-07-17 22:12   ` Sergey Kubushyn
2010-09-12 19:18   ` Wolfgang Denk
2010-07-17 19:45 ` [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables Wolfgang Denk
2010-07-17 22:48   ` [U-Boot] [PATCH] new env: fix off-by-one error in setenv command Wolfgang Denk
2010-07-20  0:38   ` [U-Boot] [PATCH 5/5] New implementation for internal handling of environment variables Kim Phillips
2010-07-20  9:40     ` Wolfgang Denk
2010-07-20 18:36       ` Kim Phillips
2010-07-20 19:01         ` Wolfgang Denk
2010-07-20 20:09           ` Wolfgang Denk
     [not found]             ` <1279658019.5685.125.camel@thunk>
2010-07-20 20:35               ` Wolfgang Denk
2010-07-20 21:08             ` Kim Phillips
2010-07-20 21:43               ` Wolfgang Denk
2010-07-20 22:00                 ` Kim Phillips
2010-07-25 21:45                   ` Wolfgang Denk
2010-07-26 23:18                     ` Kim Phillips
2010-07-20 19:11         ` Wolfgang Denk
2010-07-26 14:52   ` Matthias Fuchs
2010-07-28 21:17     ` Wolfgang Denk
2010-07-29  9:16       ` Matthias Fuchs
2010-08-03 22:48         ` Wolfgang Denk
2010-09-12 19:19   ` Wolfgang Denk
2010-12-30  1:53   ` [U-Boot] env_flash.c:saveenv() broken when env is smaller than a sector Mike Frysinger
2010-12-30  2:39     ` Mike Frysinger
2011-01-17 20:23       ` Wolfgang Denk
2010-07-17 19:49 ` [U-Boot] [PATCH 0/5] New environment code Wolfgang Denk
2010-07-17 20:56 ` Reinhard Meyer
2010-07-17 21:28   ` Mike Frysinger
2010-07-17 21:41     ` Wolfgang Denk
2010-07-18  2:18       ` Mike Frysinger
2010-07-17 21:31   ` Wolfgang Denk
2010-07-17 21:55 ` Wolfgang Denk
2010-07-18  5:32   ` Reinhard Meyer
2010-07-18 10:26     ` Wolfgang Denk
2010-10-20  8:08 ` Mike Frysinger
2010-10-20  8:19   ` Wolfgang Denk
2010-12-08  9:56 ` Mike Frysinger
2010-12-08 10:04   ` Wolfgang Denk
2010-12-08 10:19     ` Mike Frysinger

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.