All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v4 00/13] Add PXE support
@ 2011-08-23 21:06 Jason Hobbs
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 01/13] Add generic, reusable menu code Jason Hobbs
                   ` (12 more replies)
  0 siblings, 13 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:06 UTC (permalink / raw)
  To: u-boot

This patch series adds PXE booting support to U-boot. It adds aseries
of DHCP options to allow U-boot DHCP requests to be compliant with RFC
4578, and a set of commands to provide PXELINUX like behavior.

The pxe commands provide a near subset of the functionality provided
by the PXELINUX boot loader. This allows U-boot based systems to be
controlled remotely using the same PXE based techniques that many non
U-boot based servers use.

As an example, support for the pxe commands is enabled for the
ca9x4_ct_vxp config.

Additional details for the pxe commands are available in the README.pxe
file added as part of this patch series.

This patch series adds support for RFC 4578 compliant DHCP request
options, which enhance the ability of DHCP servers to respond
differently to different clients.

As an example, the last patch in this series enables support for the PXE
DHCP options for the ca9x4_ct_vxp config.

v4 of the patch series combines the previously separate DHCP options
patches with the pxe options. It also renames the pxe commands to 'pxe'
from 'pxecfg', and includes various other improvements and bug fixes.
Special thanks to the Linaro and Ubuntu folks who tested the patches and
sent me bug reports and fixes.

Jason Hobbs (13):
  Add generic, reusable menu code
  common, menu: use abortboot for menu timeout
  common: add run_command2 for running simple or hush commands
  Add isblank
  cosmetic: remove unneeded curly braces
  Replace space and tab checks with isblank
  Add standard environment variables README
  lib: add uuid_str_to_bin for use with bootp and PXE uuid
  Add pxe command
  net: bootp: add PXE/RFC 4578 DHCP options support
  Convert ca9x4_ct_vxp to standard env variables
  arm: ca9x4_ct_vxp: enable pxe command support
  arm: ca9x4_ct_vxp: enable PXE BOOTP options support

 board/hymod/env.c                    |    9 +-
 common/Makefile                      |    2 +
 common/cmd_pxe.c                     | 1349 ++++++++++++++++++++++++++++++++++
 common/command.c                     |    9 +-
 common/hush.c                        |    2 +-
 common/main.c                        |   69 +-
 common/menu.c                        |  417 +++++++++++
 doc/README.menu                      |  119 +++
 doc/README.pxe                       |  240 ++++++
 doc/README.standard-env              |   92 +++
 drivers/bios_emulator/x86emu/debug.c |    7 +-
 examples/standalone/smc911x_eeprom.c |    5 +-
 include/common.h                     |   13 +
 include/configs/ca9x4_ct_vxp.h       |   19 +-
 include/hush.h                       |    2 +-
 include/linux/ctype.h                |    6 +
 include/menu.h                       |   30 +
 lib/Makefile                         |    1 +
 lib/hashtable.c                      |    4 +-
 lib/uuid.c                           |   85 +++
 net/bootp.c                          |   40 +
 21 files changed, 2463 insertions(+), 57 deletions(-)
 create mode 100644 common/cmd_pxe.c
 create mode 100644 common/menu.c
 create mode 100644 doc/README.menu
 create mode 100644 doc/README.pxe
 create mode 100644 doc/README.standard-env
 create mode 100644 include/menu.h
 create mode 100644 lib/uuid.c

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

* [U-Boot] [PATCH v4 01/13] Add generic, reusable menu code
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
@ 2011-08-23 21:06 ` Jason Hobbs
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 02/13] common, menu: use abortboot for menu timeout Jason Hobbs
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:06 UTC (permalink / raw)
  To: u-boot

This will be used first by the pxe code, but is intended to be
generic and reusable for other jobs in U-boot.

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
---
changes in v2:
 - new in v2

changes in v3:
 - move timeout support to later patch
 - fix NULL case bug in menu_item_key_match
 - consistently use 'item_key' instead of 'key'
 - move default/prompt logic into menu code
 - consistently return int for error propagation
 - change option setting functions to menu_create parameters
 - add README.menu

changes in v4:
 - change pxecfg to pxe in commit log
 - improve the menu documentation

 common/Makefile |    1 +
 common/menu.c   |  393 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 doc/README.menu |  119 +++++++++++++++++
 include/menu.h  |   30 ++++
 4 files changed, 543 insertions(+), 0 deletions(-)
 create mode 100644 common/menu.c
 create mode 100644 doc/README.menu
 create mode 100644 include/menu.h

diff --git a/common/Makefile b/common/Makefile
index d662468..ebe45b8 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -169,6 +169,7 @@ COBJS-$(CONFIG_CMD_KGDB) += kgdb.o kgdb_stubs.o
 COBJS-$(CONFIG_KALLSYMS) += kallsyms.o
 COBJS-$(CONFIG_LCD) += lcd.o
 COBJS-$(CONFIG_LYNXKDI) += lynxkdi.o
+COBJS-$(CONFIG_MENU) += menu.o
 COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o
 COBJS-$(CONFIG_UPDATE_TFTP) += update.o
 COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o
diff --git a/common/menu.c b/common/menu.c
new file mode 100644
index 0000000..5643937
--- /dev/null
+++ b/common/menu.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright 2010-2011 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <errno.h>
+#include <linux/list.h>
+
+#include "menu.h"
+
+/*
+ * Internally, each item in a menu is represented by a struct menu_item.
+ *
+ * These items will be alloc'd and initialized by menu_item_add and destroyed
+ * by menu_item_destroy, and the consumer of the interface never sees that
+ * this struct is used at all.
+ */
+struct menu_item {
+	char *key;
+	void *data;
+	struct list_head list;
+};
+
+/*
+ * The menu is composed of a list of items along with settings and callbacks
+ * provided by the user. An incomplete definition of this struct is available
+ * in menu.h, but the full definition is here to prevent consumers from
+ * relying on its contents.
+ */
+struct menu {
+	struct menu_item *default_item;
+	char *title;
+	int prompt;
+	void (*item_data_print)(void *);
+	struct list_head items;
+};
+
+/*
+ * An iterator function for menu items. callback will be called for each item
+ * in m, with m, a pointer to the item, and extra being passed to callback. If
+ * callback returns a value other than NULL, iteration stops and the value
+ * return by callback is returned from menu_items_iter.  This allows it to be
+ * used for search type operations. It is also safe for callback to remove the
+ * item from the list of items.
+ */
+static inline void *menu_items_iter(struct menu *m,
+		void *(*callback)(struct menu *, struct menu_item *, void *),
+		void *extra)
+{
+	struct list_head *pos, *n;
+	struct menu_item *item;
+	void *ret;
+
+	list_for_each_safe(pos, n, &m->items) {
+		item = list_entry(pos, struct menu_item, list);
+
+		ret = callback(m, item, extra);
+
+		if (ret)
+			return ret;
+	}
+
+	return NULL;
+}
+
+/*
+ * Print a menu_item. If the consumer provided an item_data_print function
+ * when creating the menu, call it with a pointer to the item's private data.
+ * Otherwise, print the key of the item.
+ */
+static inline void *menu_item_print(struct menu *m,
+				struct menu_item *item,
+				void *extra)
+{
+	if (!m->item_data_print)
+		printf("%s\n", item->key);
+	else
+		m->item_data_print(item->data);
+
+	return NULL;
+}
+
+/*
+ * Free the memory used by a menu item. This includes the memory used by its
+ * key.
+ */
+static inline void *menu_item_destroy(struct menu *m,
+				struct menu_item *item,
+				void *extra)
+{
+	if (item->key)
+		free(item->key);
+
+	free(item);
+
+	return NULL;
+}
+
+/*
+ * Display a menu so the user can make a choice of an item. First display its
+ * title, if any, and then each item in the menu.
+ */
+static inline void menu_display(struct menu *m)
+{
+	if (m->title)
+		printf("%s:\n", m->title);
+
+	menu_items_iter(m, menu_item_print, NULL);
+}
+
+/*
+ * Check if an item's key matches a provided string, pointed to by extra. If
+ * extra is NULL, an item with a NULL key will match. Otherwise, the item's
+ * key has to match according to strcmp.
+ *
+ * This is called via menu_items_iter, so it returns a pointer to the item if
+ * the key matches, and returns NULL otherwise.
+ */
+static inline void *menu_item_key_match(struct menu *m,
+			struct menu_item *item, void *extra)
+{
+	char *item_key = extra;
+
+	if (!item_key || !item->key) {
+		if (item_key == item->key)
+			return item;
+
+		return NULL;
+	}
+
+	if (strcmp(item->key, item_key) == 0)
+		return item;
+
+	return NULL;
+}
+
+/*
+ * Find the first item with a key matching item_key, if any exists.
+ */
+static inline struct menu_item *menu_item_by_key(struct menu *m,
+							char *item_key)
+{
+	return menu_items_iter(m, menu_item_key_match, item_key);
+}
+
+/*
+ * Checks whether or not the default menu item should be used without
+ * prompting for a user choice.  If the menu is set to always prompt, return
+ * 0. Otherwise, return 1 to indicate we should use the default menu item.
+ */
+static inline int menu_use_default(struct menu *m)
+{
+	return !m->prompt;
+}
+
+/*
+ * Set *choice to point to the default item's data, if any default item was
+ * set, and returns 1. If no default item was set, returns -ENOENT.
+ */
+static inline int menu_default_choice(struct menu *m, void **choice)
+{
+	if (m->default_item) {
+		*choice = m->default_item->data;
+		return 1;
+	}
+
+	return -ENOENT;
+}
+
+/*
+ * Displays the menu and asks the user to choose an item. *choice will point
+ * to the private data of the item the user chooses. The user makes a choice
+ * by inputting a string matching the key of an item. Invalid choices will
+ * cause the user to be prompted again, repeatedly, until the user makes a
+ * valid choice. The user can exit the menu without making a choice via ^c.
+ *
+ * Returns 1 if the user made a choice, or -EINTR if they bail via ^c.
+ */
+static inline int menu_interactive_choice(struct menu *m, void **choice)
+{
+	char cbuf[CONFIG_SYS_CBSIZE];
+	struct menu_item *choice_item = NULL;
+	int readret;
+
+	while (!choice_item) {
+		cbuf[0] = '\0';
+
+		menu_display(m);
+
+		readret = readline_into_buffer("Enter choice: ", cbuf);
+
+		if (readret >= 0) {
+			choice_item = menu_item_by_key(m, cbuf);
+
+			if (!choice_item)
+				printf("%s not found\n", cbuf);
+		} else {
+			printf("^C\n");
+			return -EINTR;
+		}
+	}
+
+	*choice = choice_item->data;
+
+	return 1;
+}
+
+/*
+ * menu_default_set() - Sets the default choice for the menu. This is safe to
+ * call more than once on a menu.
+ *
+ * m - Points to a menu created by menu_create().
+ *
+ * item_key - Points to a string that, when compared using strcmp, matches the
+ * key for an existing item in the menu.
+ *
+ * Returns 1 if successful, -EINVAL if m is NULL, or -ENOENT if no item with a
+ * key matching item_key is found.
+ */
+int menu_default_set(struct menu *m, char *item_key)
+{
+	struct menu_item *item;
+
+	if (!m)
+		return -EINVAL;
+
+	item = menu_item_by_key(m, item_key);
+
+	if (!item)
+		return -ENOENT;
+
+	m->default_item = item;
+
+	return 1;
+}
+
+/*
+ * menu_get_choice() - Returns the user's selected menu entry, or the default
+ * if the menu is set to not prompt. This is safe to call more than once.
+ *
+ * m - Points to a menu created by menu_create().
+ *
+ * choice - Points to a location that will store a pointer to the selected
+ * menu item. If no item is selected or there is an error, no value will be
+ * written at the location it points to.
+ *
+ * Returns 1 if successful, -EINVAL if m or choice is NULL, -ENOENT if no
+ * default has been set and the menu is set to not prompt, or -EINTR if the
+ * user exits the menu via ^c.
+ */
+int menu_get_choice(struct menu *m, void **choice)
+{
+	if (!m || !choice)
+		return -EINVAL;
+
+	if (menu_use_default(m))
+		return menu_default_choice(m, choice);
+
+	return menu_interactive_choice(m, choice);
+}
+
+/*
+ * menu_item_add() - Adds or replaces a menu item. Note that this replaces the
+ * data of an item if it already exists, but doesn't change the order of the
+ * item.
+ *
+ * m - Points to a menu created by menu_create().
+ *
+ * item_key - Points to a string that will uniquely identify the item.  The
+ * string will be copied to internal storage, and is safe to discard after
+ * passing to menu_item_add.
+ *
+ * item_data - An opaque pointer associated with an item. It is never
+ * dereferenced internally, but will be passed to the item_data_print, and
+ * will be returned from menu_get_choice if the menu item is selected.
+ *
+ * Returns 1 if successful, -EINVAL if m is NULL, or -ENOMEM if there is
+ * insufficient memory to add the menu item.
+ */
+int menu_item_add(struct menu *m, char *item_key, void *item_data)
+{
+	struct menu_item *item;
+
+	if (!m)
+		return -EINVAL;
+
+	item = menu_item_by_key(m, item_key);
+
+	if (item) {
+		item->data = item_data;
+		return 1;
+	}
+
+	item = malloc(sizeof *item);
+	if (!item)
+		return -ENOMEM;
+
+	item->key = strdup(item_key);
+
+	if (!item->key) {
+		free(item);
+		return -ENOMEM;
+	}
+
+	item->data = item_data;
+
+	list_add_tail(&item->list, &m->items);
+
+	return 1;
+}
+
+/*
+ * menu_create() - Creates a menu handle with default settings
+ *
+ * title - If not NULL, points to a string that will be displayed before the
+ * list of menu items. It will be copied to internal storage, and is safe to
+ * discard after passing to menu_create().
+ *
+ * prompt - If 0, don't ask for user input.
+ *
+ * item_data_print - If not NULL, will be called for each item when the menu
+ * is displayed, with the pointer to the item's data passed as the argument.
+ * If NULL, each item's key will be printed instead.  Since an item's key is
+ * what must be entered to select an item, the item_data_print function should
+ * make it obvious what the key for each entry is.
+ *
+ * Returns a pointer to the menu if successful, or NULL if there is
+ * insufficient memory available to create the menu.
+ */
+struct menu *menu_create(char *title, int prompt,
+				void (*item_data_print)(void *))
+{
+	struct menu *m;
+
+	m = malloc(sizeof *m);
+
+	if (!m)
+		return NULL;
+
+	m->default_item = NULL;
+	m->prompt = prompt;
+	m->item_data_print = item_data_print;
+
+	if (title) {
+		m->title = strdup(title);
+		if (!m->title) {
+			free(m);
+			return NULL;
+		}
+	} else
+		m->title = NULL;
+
+
+	INIT_LIST_HEAD(&m->items);
+
+	return m;
+}
+
+/*
+ * menu_destroy() - frees the memory used by a menu and its items.
+ *
+ * m - Points to a menu created by menu_create().
+ *
+ * Returns 1 if successful, or -EINVAL if m is NULL.
+ */
+int menu_destroy(struct menu *m)
+{
+	if (!m)
+		return -EINVAL;
+
+	menu_items_iter(m, menu_item_destroy, NULL);
+
+	if (m->title)
+		free(m->title);
+
+	free(m);
+
+	return 1;
+}
diff --git a/doc/README.menu b/doc/README.menu
new file mode 100644
index 0000000..f55eb80
--- /dev/null
+++ b/doc/README.menu
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2010-2011 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+U-boot provides a set of interfaces for creating and using simple, text
+based menus. Menus are displayed as lists of labeled entries on the
+console, and an entry can be selected by entering its label.
+
+To use the menu code, enable CONFIG_MENU, and include "menu.h" where
+the interfaces should be available.
+
+Menus are composed of items. Each item has a key used to identify it in
+the menu, and an opaque pointer to data controlled by the consumer.
+
+Interfaces
+----------
+#include "menu.h"
+
+/*
+ * Consumers of the menu interfaces will use a struct menu * as the
+ * handle for a menu. struct menu is only fully defined in menu.c,
+ * preventing consumers of the menu interfaces from accessing its
+ * contents directly.
+ */
+struct menu;
+
+/*
+ * NOTE: See comments in common/menu.c for more detailed documentation on
+ * these interfaces.
+ */
+
+/*
+ * menu_create() - Creates a menu handle with default settings
+ */
+struct menu *menu_create(char *title, int prompt,
+				void (*item_data_print)(void *));
+
+/*
+ * menu_item_add() - Adds or replaces a menu item
+ */
+int menu_item_add(struct menu *m, char *item_key, void *item_data);
+
+/*
+ * menu_default_set() - Sets the default choice for the menu
+ */
+int menu_default_set(struct menu *m, char *item_key);
+
+/*
+ * menu_get_choice() - Returns the user's selected menu entry, or the
+ * default if the menu is set to not prompt.
+ */
+int menu_get_choice(struct menu *m, void **choice);
+
+/*
+ * menu_destroy() - frees the memory used by a menu and its items.
+ */
+int menu_destroy(struct menu *m);
+
+
+Example Code
+------------
+This example creates a menu that always prompts, and allows the user
+to pick from a list of tools.  The item key and data are the same.
+
+#include "menu.h"
+
+char *tools[] = {
+	"Hammer",
+	"Screwdriver",
+	"Nail gun",
+	NULL
+};
+
+char *pick_a_tool(void)
+{
+	struct menu *m;
+	int i;
+	char *tool = NULL;
+
+	m = menu_create("Tools", 1, NULL);
+
+	for(i = 0; tools[i]; i++) {
+		if (menu_item_add(m, tools[i], tools[i]) != 1) {
+			printf("failed to add item!");
+			menu_destroy(m);
+			return NULL;
+                }
+	}
+
+	if (menu_get_choice(m, (void **)&tool) != 1)
+		printf("Problem picking tool!\n");
+
+	menu_destroy(m);
+
+	return tool;
+}
+
+void caller(void)
+{
+	char *tool = pick_a_tool();
+
+	if (tool) {
+		printf("picked a tool: %s\n", tool);
+		use_tool(tool);
+	}
+}
diff --git a/include/menu.h b/include/menu.h
new file mode 100644
index 0000000..d47e1a0
--- /dev/null
+++ b/include/menu.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010-2011 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MENU_H__
+#define __MENU_H__
+
+struct menu;
+
+struct menu *menu_create(char *title, int prompt,
+				void (*item_data_print)(void *));
+int menu_default_set(struct menu *m, char *item_key);
+int menu_get_choice(struct menu *m, void **choice);
+int menu_item_add(struct menu *m, char *item_key, void *item_data);
+int menu_destroy(struct menu *m);
+
+#endif /* __MENU_H__ */
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 02/13] common, menu: use abortboot for menu timeout
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 01/13] Add generic, reusable menu code Jason Hobbs
@ 2011-08-23 21:06 ` Jason Hobbs
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 03/13] common: add run_command2 for running simple or hush commands Jason Hobbs
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:06 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
---
changes in v2:
- expose abortboot externally instead of using a wrapper
- expose abortboot externally when CONFIG_MENU is set

changes in v3:
- simplify the conditional export of abortboot
- add timeout support for the menu in this patch
- add doc for timeout feature

changes in v4:
- added more comments to menu.c

 common/main.c    |   10 ++++++++--
 common/menu.c    |   40 ++++++++++++++++++++++++++++++++--------
 doc/README.menu  |    6 +++---
 include/common.h |    3 +++
 include/menu.h   |    2 +-
 5 files changed, 47 insertions(+), 14 deletions(-)

diff --git a/common/main.c b/common/main.c
index 3324d9d..b97d89e 100644
--- a/common/main.c
+++ b/common/main.c
@@ -88,7 +88,10 @@ extern void mdm_init(void); /* defined in board.c */
  */
 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
 # if defined(CONFIG_AUTOBOOT_KEYED)
-static inline int abortboot(int bootdelay)
+#ifndef CONFIG_MENU
+static inline
+#endif
+int abortboot(int bootdelay)
 {
 	int abort = 0;
 	uint64_t etime = endtick(bootdelay);
@@ -202,7 +205,10 @@ static inline int abortboot(int bootdelay)
 static int menukey = 0;
 #endif
 
-static inline int abortboot(int bootdelay)
+#ifndef CONFIG_MENU
+static inline
+#endif
+int abortboot(int bootdelay)
 {
 	int abort = 0;
 
diff --git a/common/menu.c b/common/menu.c
index 5643937..f004823 100644
--- a/common/menu.c
+++ b/common/menu.c
@@ -43,6 +43,7 @@ struct menu_item {
  */
 struct menu {
 	struct menu_item *default_item;
+	int timeout;
 	char *title;
 	int prompt;
 	void (*item_data_print)(void *);
@@ -158,13 +159,29 @@ static inline struct menu_item *menu_item_by_key(struct menu *m,
 }
 
 /*
+ * Wait for the user to hit a key according to the timeout set for the menu.
+ * Returns 1 if the user hit a key, or 0 if the timeout expired.
+ */
+static inline int menu_interrupted(struct menu *m)
+{
+	if (!m->timeout)
+		return 0;
+
+	if (abortboot(m->timeout/10))
+		return 1;
+
+	return 0;
+}
+
+/*
  * Checks whether or not the default menu item should be used without
- * prompting for a user choice.  If the menu is set to always prompt, return
- * 0. Otherwise, return 1 to indicate we should use the default menu item.
+ * prompting for a user choice. If the menu is set to always prompt, or the
+ * user hits a key during the timeout period, return 0. Otherwise, return 1 to
+ * indicate we should use the default menu item.
  */
 static inline int menu_use_default(struct menu *m)
 {
-	return !m->prompt;
+	return !m->prompt && !menu_interrupted(m);
 }
 
 /*
@@ -250,7 +267,8 @@ int menu_default_set(struct menu *m, char *item_key)
 
 /*
  * menu_get_choice() - Returns the user's selected menu entry, or the default
- * if the menu is set to not prompt. This is safe to call more than once.
+ * if the menu is set to not prompt or the timeout expires. This is safe to
+ * call more than once.
  *
  * m - Points to a menu created by menu_create().
  *
@@ -259,8 +277,8 @@ int menu_default_set(struct menu *m, char *item_key)
  * written at the location it points to.
  *
  * Returns 1 if successful, -EINVAL if m or choice is NULL, -ENOENT if no
- * default has been set and the menu is set to not prompt, or -EINTR if the
- * user exits the menu via ^c.
+ * default has been set and the menu is set to not prompt or the timeout
+ * expires, or -EINTR if the user exits the menu via ^c.
  */
 int menu_get_choice(struct menu *m, void **choice)
 {
@@ -330,7 +348,12 @@ int menu_item_add(struct menu *m, char *item_key, void *item_data)
  * list of menu items. It will be copied to internal storage, and is safe to
  * discard after passing to menu_create().
  *
- * prompt - If 0, don't ask for user input.
+ * timeout - A delay in seconds to wait for user input. If 0, timeout is
+ * disabled, and the default choice will be returned unless prompt is 1.
+ *
+ * prompt - If 0, don't ask for user input unless there is an interrupted
+ * timeout. If 1, the user will be prompted for input regardless of the value
+ * of timeout.
  *
  * item_data_print - If not NULL, will be called for each item when the menu
  * is displayed, with the pointer to the item's data passed as the argument.
@@ -341,7 +364,7 @@ int menu_item_add(struct menu *m, char *item_key, void *item_data)
  * Returns a pointer to the menu if successful, or NULL if there is
  * insufficient memory available to create the menu.
  */
-struct menu *menu_create(char *title, int prompt,
+struct menu *menu_create(char *title, int timeout, int prompt,
 				void (*item_data_print)(void *))
 {
 	struct menu *m;
@@ -353,6 +376,7 @@ struct menu *menu_create(char *title, int prompt,
 
 	m->default_item = NULL;
 	m->prompt = prompt;
+	m->timeout = timeout;
 	m->item_data_print = item_data_print;
 
 	if (title) {
diff --git a/doc/README.menu b/doc/README.menu
index f55eb80..1259c6a 100644
--- a/doc/README.menu
+++ b/doc/README.menu
@@ -45,7 +45,7 @@ struct menu;
 /*
  * menu_create() - Creates a menu handle with default settings
  */
-struct menu *menu_create(char *title, int prompt,
+struct menu *menu_create(char *title, int timeout, int prompt,
 				void (*item_data_print)(void *));
 
 /*
@@ -60,7 +60,7 @@ int menu_default_set(struct menu *m, char *item_key);
 
 /*
  * menu_get_choice() - Returns the user's selected menu entry, or the
- * default if the menu is set to not prompt.
+ * default if the menu is set to not prompt or the timeout expires.
  */
 int menu_get_choice(struct menu *m, void **choice);
 
@@ -90,7 +90,7 @@ char *pick_a_tool(void)
 	int i;
 	char *tool = NULL;
 
-	m = menu_create("Tools", 1, NULL);
+	m = menu_create("Tools", 0, 1, NULL);
 
 	for(i = 0; tools[i]; i++) {
 		if (menu_item_add(m, tools[i], tools[i]) != 1) {
diff --git a/include/common.h b/include/common.h
index 12a1074..3609acd 100644
--- a/include/common.h
+++ b/include/common.h
@@ -239,6 +239,9 @@ int	readline_into_buffer	(const char *const prompt, char * buffer);
 int	parse_line (char *, char *[]);
 void	init_cmd_timeout(void);
 void	reset_cmd_timeout(void);
+#ifdef CONFIG_MENU
+int	abortboot(int bootdelay);
+#endif
 
 /* arch/$(ARCH)/lib/board.c */
 void	board_init_f  (ulong) __attribute__ ((noreturn));
diff --git a/include/menu.h b/include/menu.h
index d47e1a0..cf14a9c 100644
--- a/include/menu.h
+++ b/include/menu.h
@@ -20,7 +20,7 @@
 
 struct menu;
 
-struct menu *menu_create(char *title, int prompt,
+struct menu *menu_create(char *title, int timeout, int prompt,
 				void (*item_data_print)(void *));
 int menu_default_set(struct menu *m, char *item_key);
 int menu_get_choice(struct menu *m, void **choice);
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 03/13] common: add run_command2 for running simple or hush commands
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 01/13] Add generic, reusable menu code Jason Hobbs
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 02/13] common, menu: use abortboot for menu timeout Jason Hobbs
@ 2011-08-23 21:06 ` Jason Hobbs
  2011-08-23 21:46   ` Mike Frysinger
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 04/13] Add isblank Jason Hobbs
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:06 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
---
changes in v2:
- whitespace correction

changes in v4:
- fix indention of a run_command2 line
- make run_command2 static inline

 common/hush.c  |    2 +-
 common/main.c  |   50 +++++++++++++++++++++-----------------------------
 include/hush.h |    2 +-
 3 files changed, 23 insertions(+), 31 deletions(-)

diff --git a/common/hush.c b/common/hush.c
index 85a6030..940889b 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -3217,7 +3217,7 @@ int parse_stream_outer(struct in_str *inp, int flag)
 #ifndef __U_BOOT__
 static int parse_string_outer(const char *s, int flag)
 #else
-int parse_string_outer(char *s, int flag)
+int parse_string_outer(const char *s, int flag)
 #endif	/* __U_BOOT__ */
 {
 	struct in_str input;
diff --git a/common/main.c b/common/main.c
index b97d89e..e9e8350 100644
--- a/common/main.c
+++ b/common/main.c
@@ -83,8 +83,7 @@ extern void mdm_init(void); /* defined in board.c */
 
 /***************************************************************************
  * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
- * returns: 0 -  no key string, allow autoboot
- *          1 - got key string, abort
+ * returns: 0 -  no key string, allow autoboot 1 - got key string, abort
  */
 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
 # if defined(CONFIG_AUTOBOOT_KEYED)
@@ -266,6 +265,20 @@ int abortboot(int bootdelay)
 # endif	/* CONFIG_AUTOBOOT_KEYED */
 #endif	/* CONFIG_BOOTDELAY >= 0  */
 
+static inline
+int run_command2(const char *cmd, int flag)
+{
+#ifndef CONFIG_SYS_HUSH_PARSER
+	if (run_command(cmd, flag) == -1)
+		return 1;
+#else
+	if (parse_string_outer(cmd,
+	    FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
+		return 1;
+#endif
+	return 0;
+}
+
 /****************************************************************************/
 
 void main_loop (void)
@@ -332,12 +345,7 @@ void main_loop (void)
 		int prev = disable_ctrlc(1);	/* disable Control C checking */
 # endif
 
-# ifndef CONFIG_SYS_HUSH_PARSER
-		run_command (p, 0);
-# else
-		parse_string_outer(p, FLAG_PARSE_SEMICOLON |
-				    FLAG_EXIT_FROM_LOOP);
-# endif
+		run_command2(p, 0);
 
 # ifdef CONFIG_AUTOBOOT_KEYED
 		disable_ctrlc(prev);	/* restore Control C checking */
@@ -382,12 +390,7 @@ void main_loop (void)
 		int prev = disable_ctrlc(1);	/* disable Control C checking */
 # endif
 
-# ifndef CONFIG_SYS_HUSH_PARSER
-		run_command (s, 0);
-# else
-		parse_string_outer(s, FLAG_PARSE_SEMICOLON |
-				    FLAG_EXIT_FROM_LOOP);
-# endif
+		run_command2(s, 0);
 
 # ifdef CONFIG_AUTOBOOT_KEYED
 		disable_ctrlc(prev);	/* restore Control C checking */
@@ -397,14 +400,8 @@ void main_loop (void)
 # ifdef CONFIG_MENUKEY
 	if (menukey == CONFIG_MENUKEY) {
 		s = getenv("menucmd");
-		if (s) {
-# ifndef CONFIG_SYS_HUSH_PARSER
-			run_command(s, 0);
-# else
-			parse_string_outer(s, FLAG_PARSE_SEMICOLON |
-						FLAG_EXIT_FROM_LOOP);
-# endif
-		}
+		if (s)
+			run_command2(s, 0);
 	}
 #endif /* CONFIG_MENUKEY */
 #endif /* CONFIG_BOOTDELAY */
@@ -1403,14 +1400,9 @@ int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 			printf ("## Error: \"%s\" not defined\n", argv[i]);
 			return 1;
 		}
-#ifndef CONFIG_SYS_HUSH_PARSER
-		if (run_command (arg, flag) == -1)
-			return 1;
-#else
-		if (parse_string_outer(arg,
-		    FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
+
+		if (run_command2(arg, flag) != 0)
 			return 1;
-#endif
 	}
 	return 0;
 }
diff --git a/include/hush.h b/include/hush.h
index 5c566cc..ecf9222 100644
--- a/include/hush.h
+++ b/include/hush.h
@@ -29,7 +29,7 @@
 #define FLAG_REPARSING       (1 << 2)	  /* >=2nd pass */
 
 extern int u_boot_hush_start(void);
-extern int parse_string_outer(char *, int);
+extern int parse_string_outer(const char *, int);
 extern int parse_file_outer(void);
 
 int set_local_var(const char *s, int flg_export);
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 04/13] Add isblank
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
                   ` (2 preceding siblings ...)
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 03/13] common: add run_command2 for running simple or hush commands Jason Hobbs
@ 2011-08-23 21:06 ` Jason Hobbs
  2011-08-23 21:40   ` Mike Frysinger
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 05/13] cosmetic: remove unneeded curly braces Jason Hobbs
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:06 UTC (permalink / raw)
  To: u-boot

Existing ctype checks are implemented using a 256 byte lookup table,
allowing each character to be in any of 8 character classes. Since there
are 8 existing character classes without the blank class, I implemented
isblank without using the lookup table.  Since there are only two blank
characters - tab and space - this is a more reasonable approach than
doubling the size of the lookup table to accommodate one more class.

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
---
new in v4

 include/linux/ctype.h |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/include/linux/ctype.h b/include/linux/ctype.h
index 6dec944..42f9305 100644
--- a/include/linux/ctype.h
+++ b/include/linux/ctype.h
@@ -31,6 +31,12 @@ extern const unsigned char _ctype[];
 #define isupper(c)	((__ismask(c)&(_U)) != 0)
 #define isxdigit(c)	((__ismask(c)&(_D|_X)) != 0)
 
+/*
+ * Rather than doubling the size of the _ctype lookup table to hold a 'blank'
+ * flag, just check for space or tab.
+ */
+#define isblank(c)	(c == ' ' || c == '\t')
+
 #define isascii(c) (((unsigned char)(c))<=0x7f)
 #define toascii(c) (((unsigned char)(c))&0x7f)
 
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 05/13] cosmetic: remove unneeded curly braces
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
                   ` (3 preceding siblings ...)
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 04/13] Add isblank Jason Hobbs
@ 2011-08-23 21:06 ` Jason Hobbs
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 06/13] Replace space and tab checks with isblank Jason Hobbs
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:06 UTC (permalink / raw)
  To: u-boot

This prevents a checkpatch warning in the patch to use isblank

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
---
new in v4

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

diff --git a/common/main.c b/common/main.c
index e9e8350..bf5ddca 100644
--- a/common/main.c
+++ b/common/main.c
@@ -1091,9 +1091,8 @@ int parse_line (char *line, char *argv[])
 	while (nargs < CONFIG_SYS_MAXARGS) {
 
 		/* skip any white space */
-		while ((*line == ' ') || (*line == '\t')) {
+		while ((*line == ' ') || (*line == '\t'))
 			++line;
-		}
 
 		if (*line == '\0') {	/* end of line, no more args	*/
 			argv[nargs] = NULL;
@@ -1106,9 +1105,8 @@ int parse_line (char *line, char *argv[])
 		argv[nargs++] = line;	/* begin of argument string	*/
 
 		/* find end of string */
-		while (*line && (*line != ' ') && (*line != '\t')) {
+		while (*line && (*line != ' ') && (*line != '\t'))
 			++line;
-		}
 
 		if (*line == '\0') {	/* end of line, no more args	*/
 			argv[nargs] = NULL;
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 06/13] Replace space and tab checks with isblank
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
                   ` (4 preceding siblings ...)
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 05/13] cosmetic: remove unneeded curly braces Jason Hobbs
@ 2011-08-23 21:06 ` Jason Hobbs
  2011-08-23 21:42   ` Mike Frysinger
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 07/13] Add standard environment variables README Jason Hobbs
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:06 UTC (permalink / raw)
  To: u-boot

These are various places I found that checked for conditions equivalent
to isblank.

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
---
new in v4

 board/hymod/env.c                    |    9 +++++----
 common/command.c                     |    9 +++++----
 common/main.c                        |    5 +++--
 drivers/bios_emulator/x86emu/debug.c |    7 ++++---
 examples/standalone/smc911x_eeprom.c |    5 +++--
 lib/hashtable.c                      |    4 +++-
 6 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/board/hymod/env.c b/board/hymod/env.c
index c0e2cd5..fde428d 100644
--- a/board/hymod/env.c
+++ b/board/hymod/env.c
@@ -22,6 +22,7 @@
  */
 
 #include <common.h>
+#include <linux/ctype.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -45,7 +46,7 @@ env_callback (uchar *name, uchar *value)
 		nn++;
 	}
 
-	while (*nn == ' ' || *nn == '\t')
+	while (isblank(*nn))
 		nn++;
 
 	if ((nnl = strlen (nn)) == 0) {
@@ -61,7 +62,7 @@ env_callback (uchar *name, uchar *value)
 		nn[--nnl] = '\0';
 	}
 
-	while (nnl > 0 && ((c = nn[nnl - 1]) == ' ' || c == '\t'))
+	while (nnl > 0 && isblank(nn[nnl - 1]))
 		nn[--nnl] = '\0';
 	if (nnl == 0) {
 		printf ("Empty name in global env file\n");
@@ -71,11 +72,11 @@ env_callback (uchar *name, uchar *value)
 	p = (char *)value;
 	q = nv;
 
-	while ((c = *p) == ' ' || c == '\t')
+	while (isblank(*p))
 		p++;
 
 	nvl = strlen (p);
-	while (nvl > 0 && ((c = p[nvl - 1]) == ' ' || c == '\t'))
+	while (nvl > 0 && isblank(p[nvl - 1]))
 		p[--nvl] = '\0';
 
 	while ((*q = *p++) != '\0') {
diff --git a/common/command.c b/common/command.c
index ddaed68..85b6424 100644
--- a/common/command.c
+++ b/common/command.c
@@ -27,6 +27,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <linux/ctype.h>
 
 /*
  * Use puts() instead of printf() to avoid printf buffer overflow
@@ -165,7 +166,7 @@ int var_complete(int argc, char * const argv[], char last_char, int maxv, char *
 	static char tmp_buf[512];
 	int space;
 
-	space = last_char == '\0' || last_char == ' ' || last_char == '\t';
+	space = last_char == '\0' || isblank(last_char);
 
 	if (space && argc == 1)
 		return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
@@ -206,7 +207,7 @@ static int complete_cmdv(int argc, char * const argv[], char last_char, int maxv
 	}
 
 	/* more than one arg or one but the start of the next */
-	if (argc > 1 || (last_char == '\0' || last_char == ' ' || last_char == '\t')) {
+	if (argc > 1 || (last_char == '\0' || isblank(last_char))) {
 		cmdtp = find_cmd(argv[0]);
 		if (cmdtp == NULL || cmdtp->complete == NULL) {
 			cmdv[0] = NULL;
@@ -257,7 +258,7 @@ static int make_argv(char *s, int argvsz, char *argv[])
 	while (argc < argvsz - 1) {
 
 		/* skip any white space */
-		while ((*s == ' ') || (*s == '\t'))
+		while (isblank(*s))
 			++s;
 
 		if (*s == '\0')	/* end of s, no more args	*/
@@ -266,7 +267,7 @@ static int make_argv(char *s, int argvsz, char *argv[])
 		argv[argc++] = s;	/* begin of argument string	*/
 
 		/* find end of string */
-		while (*s && (*s != ' ') && (*s != '\t'))
+		while (*s && !isblank(*s))
 			++s;
 
 		if (*s == '\0')		/* end of s, no more args	*/
diff --git a/common/main.c b/common/main.c
index bf5ddca..5a623d8 100644
--- a/common/main.c
+++ b/common/main.c
@@ -40,6 +40,7 @@
 #endif
 
 #include <post.h>
+#include <linux/ctype.h>
 
 #if defined(CONFIG_SILENT_CONSOLE) || defined(CONFIG_POST) || defined(CONFIG_CMDLINE_EDITING)
 DECLARE_GLOBAL_DATA_PTR;
@@ -1091,7 +1092,7 @@ int parse_line (char *line, char *argv[])
 	while (nargs < CONFIG_SYS_MAXARGS) {
 
 		/* skip any white space */
-		while ((*line == ' ') || (*line == '\t'))
+		while (isblank(*line))
 			++line;
 
 		if (*line == '\0') {	/* end of line, no more args	*/
@@ -1105,7 +1106,7 @@ int parse_line (char *line, char *argv[])
 		argv[nargs++] = line;	/* begin of argument string	*/
 
 		/* find end of string */
-		while (*line && (*line != ' ') && (*line != '\t'))
+		while (*line && !isblank(*line))
 			++line;
 
 		if (*line == '\0') {	/* end of line, no more args	*/
diff --git a/drivers/bios_emulator/x86emu/debug.c b/drivers/bios_emulator/x86emu/debug.c
index 241acf3..6417d09 100644
--- a/drivers/bios_emulator/x86emu/debug.c
+++ b/drivers/bios_emulator/x86emu/debug.c
@@ -39,6 +39,7 @@
 
 #include <stdarg.h>
 #include <common.h>
+#include <linux/ctype.h>
 #include "x86emu/x86emui.h"
 
 /*----------------------------- Implementation ----------------------------*/
@@ -333,7 +334,7 @@ static int x86emu_parse_line(char *s, int *ps, int *n)
 	int cmd;
 
 	*n = 0;
-	while (*s == ' ' || *s == '\t')
+	while (isblank(*s))
 		s++;
 	ps[*n] = *s;
 	switch (*s) {
@@ -346,13 +347,13 @@ static int x86emu_parse_line(char *s, int *ps, int *n)
 	}
 
 	while (1) {
-		while (*s != ' ' && *s != '\t' && *s != '\n')
+		while (!isblank(*s) && *s != '\n')
 			s++;
 
 		if (*s == '\n')
 			return cmd;
 
-		while (*s == ' ' || *s == '\t')
+		while (isblank(*s))
 			s++;
 
 		*n += 1;
diff --git a/examples/standalone/smc911x_eeprom.c b/examples/standalone/smc911x_eeprom.c
index 00e8266..6c79c5f 100644
--- a/examples/standalone/smc911x_eeprom.c
+++ b/examples/standalone/smc911x_eeprom.c
@@ -16,6 +16,7 @@
 
 #include <common.h>
 #include <exports.h>
+#include <linux/ctype.h>
 #include "../drivers/net/smc911x.h"
 
 /**
@@ -128,7 +129,7 @@ static int write_eeprom_reg(struct eth_device *dev, u8 value, u8 reg)
  */
 static char *skip_space(char *buf)
 {
-	while (buf[0] == ' ' || buf[0] == '\t')
+	while (isblank(buf[0]))
 		++buf;
 	return buf;
 }
@@ -357,7 +358,7 @@ int smc911x_eeprom(int argc, char * const argv[])
 			continue;
 
 		/* Only accept 1 letter commands */
-		if (line[0] && line[1] && line[1] != ' ' && line[1] != '\t')
+		if (line[0] && line[1] && !isblank(line[1]))
 			goto unknown_cmd;
 
 		/* Now parse the command */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 026dbca..6895550 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -32,6 +32,7 @@
 #ifdef USE_HOSTCC		/* HOST build */
 # include <string.h>
 # include <assert.h>
+# include <ctype.h>
 
 # ifndef debug
 #  ifdef DEBUG
@@ -43,6 +44,7 @@
 #else				/* U-Boot build */
 # include <common.h>
 # include <linux/string.h>
+# include <linux/ctype.h>
 #endif
 
 #ifndef	CONFIG_ENV_MIN_ENTRIES	/* minimum number of entries */
@@ -690,7 +692,7 @@ int himport_r(struct hsearch_data *htab,
 		ENTRY e, *rv;
 
 		/* skip leading white space */
-		while ((*dp == ' ') || (*dp == '\t'))
+		while (isblank(*dp))
 			++dp;
 
 		/* skip comment lines */
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 07/13] Add standard environment variables README
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
                   ` (5 preceding siblings ...)
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 06/13] Replace space and tab checks with isblank Jason Hobbs
@ 2011-08-23 21:06 ` Jason Hobbs
  2011-08-23 21:45   ` Mike Frysinger
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 08/13] lib: add uuid_str_to_bin for use with bootp and PXE uuid Jason Hobbs
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:06 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
---
new in v4

 doc/README.standard-env |   92 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 92 insertions(+), 0 deletions(-)
 create mode 100644 doc/README.standard-env

diff --git a/doc/README.standard-env b/doc/README.standard-env
new file mode 100644
index 0000000..cd6c545
--- /dev/null
+++ b/doc/README.standard-env
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2011, Calxeda Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+**********************************
+* Standard Environment Variables *
+**********************************
+
+The use of environment variables to hold addresses, file names, and
+other values used during booting is a common practice across U-boot
+platforms. Many platforms have variables that are used for the same
+common tasks, such as pointing to a kernel in memory, or naming a
+ramdisk file. Since these environment variables typically originate in
+board config files rather than common code, it's easy (and has been
+common) for different boards to use different environment variable
+names for the exact same purpose.
+
+Here, we provide a of standard environment variable names that should be
+used for any board that uses an environment variable that provides one
+of the values listed here. That doesn't mean each board must provide all
+of these variables - only that if it needs to describe one of the items
+listed here, it should use the standard variable for that. Failure to
+use the standard variable can result in loss of functionality when common
+code is used that expects variable names to follow the standard.
+
+WARNING: Unfortunately, it's not yet safe to assume that a variable with
+a name matching one of those below is used for the purpose listed in
+this README. There are currently board configs with variable names
+matching those listed below in name, but not purpose.
+
+TFTP Filenames
+==============
+Each of these variables contains the name of a file on a TFTP server.
+
+Variable			Contains
+--------			--------
+u-boot				U-boot binary image
+bootfile			Linux kernel image
+fdtfile				device tree blob
+ramdiskfile			ramdisk image
+
+Load Addresses
+==============
+Each of these variables contains an address in RAM at which the object
+is (or can be) loaded.
+
+Variable			Contains
+--------			--------
+u-boot_addr_r			U-boot binary image
+kernel_addr_r			Linux kernel image
+fdt_addr_r			device tree blob
+ramdisk_addr_r			ramdisk image
+
+Flash locations
+===============
+Each of these variables contains an address in NOR flash, or an offset in
+NAND flash, at which the object is stored.
+
+Variable			Contains
+--------			--------
+u-boot_addr			U-boot binary image
+kernel_addr			Linux kernel image
+fdt_addr			device tree blob
+ramdisk_addr			ramdisk image
+
+Other
+=====
+Miscellaneous
+
+Variable			Contains
+--------			--------
+bootargs			Command line arguments for the kernel
+loadaddr			Address in RAM to load a file to, from various
+				sources.
+serverip			The IP address of the TFTP server to use when
+				retrieving files.
+
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 08/13] lib: add uuid_str_to_bin for use with bootp and PXE uuid
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
                   ` (6 preceding siblings ...)
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 07/13] Add standard environment variables README Jason Hobbs
@ 2011-08-23 21:06 ` Jason Hobbs
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 09/13] Add pxe command Jason Hobbs
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:06 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
---
changes for v2:
- Move uuid_str_to_bin's prototype from uuid. to common.h
- Place uuid.o make rule in sorted order and conditionalize

changes for v3:
- check for NULL pointers in uuid conversion function

changes for v4:
- add a UUID string validator

 include/common.h |    4 ++
 lib/Makefile     |    1 +
 lib/uuid.c       |   85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+), 0 deletions(-)
 create mode 100644 lib/uuid.c

diff --git a/include/common.h b/include/common.h
index 3609acd..3a9d046 100644
--- a/include/common.h
+++ b/include/common.h
@@ -656,6 +656,10 @@ int strcmp_compar(const void *, const void *);
 /* lib/time.c */
 void	udelay        (unsigned long);
 
+/* lib/uuid.c */
+void uuid_str_to_bin(const char *uuid, unsigned char *out);
+int uuid_str_valid(const char *uuid);
+
 /* lib/vsprintf.c */
 ulong	simple_strtoul(const char *cp,char **endp,unsigned int base);
 int strict_strtoul(const char *cp, unsigned int base, unsigned long *res);
diff --git a/lib/Makefile b/lib/Makefile
index 884f64c..075bb8c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -55,6 +55,7 @@ COBJS-y += ctype.o
 COBJS-y += div64.o
 COBJS-y += string.o
 COBJS-y += time.o
+COBJS-$(CONFIG_BOOTP_PXE) += uuid.o
 COBJS-y += vsprintf.o
 
 COBJS	:= $(COBJS-y)
diff --git a/lib/uuid.c b/lib/uuid.c
new file mode 100644
index 0000000..10b022f
--- /dev/null
+++ b/lib/uuid.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011 Calxeda, Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <linux/ctype.h>
+#include "common.h"
+
+/*
+ * This is what a UUID string looks like.
+ *
+ * x is a hexadecimal character. fields are separated by '-'s. When converting
+ * to a binary UUID, le means the field should be converted to little endian,
+ * and be means it should be converted to big endian.
+ *
+ * 0        9    14   19   24
+ * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+ *    le     le   le   be       be
+ */
+
+int uuid_str_valid(const char *uuid)
+{
+	int i, valid;
+
+	if (uuid == NULL)
+		return 0;
+
+	for (i = 0, valid = 1; uuid[i] && valid; i++) {
+		switch (i) {
+		case 8: case 13: case 18: case 23:
+			valid = (uuid[i] == '-');
+			break;
+		default:
+			valid = isxdigit(uuid[i]);
+			break;
+		}
+	}
+
+	if (i != 36 || !valid)
+		return 0;
+
+	return 1;
+}
+
+void uuid_str_to_bin(const char *uuid, unsigned char *out)
+{
+	uint16_t tmp16;
+	uint32_t tmp32;
+	uint64_t tmp64;
+
+	if (!uuid || !out)
+		return;
+
+	tmp32 = cpu_to_le32(simple_strtoul(uuid, NULL, 16));
+	memcpy(out, &tmp32, 4);
+
+	tmp16 = cpu_to_le16(simple_strtoul(uuid + 9, NULL, 16));
+	memcpy(out + 4, &tmp16, 2);
+
+	tmp16 = cpu_to_le16(simple_strtoul(uuid + 14, NULL, 16));
+	memcpy(out + 6, &tmp16, 2);
+
+	tmp16 = cpu_to_be16(simple_strtoul(uuid + 19, NULL, 16));
+	memcpy(out + 8, &tmp16, 2);
+
+	tmp64 = cpu_to_be64(simple_strtoull(uuid + 24, NULL, 16));
+	memcpy(out + 10, (char *)&tmp64 + 2, 6);
+}
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 09/13] Add pxe command
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
                   ` (7 preceding siblings ...)
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 08/13] lib: add uuid_str_to_bin for use with bootp and PXE uuid Jason Hobbs
@ 2011-08-23 21:06 ` Jason Hobbs
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 10/13] net: bootp: add PXE/RFC 4578 DHCP options support Jason Hobbs
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:06 UTC (permalink / raw)
  To: u-boot

Add pxe command, which is intended to mimic PXELINUX functionality.
'pxe get' uses tftp to retrieve a file based on UUID, MAC address or IP
address. 'pxe boot' interprets the contents of PXELINUX config like file
to boot using a specific initrd, kernel and kernel command line.

This patch also adds a README.pxe file - see it for more details on the
pxe command.

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
---
changes in v2:
- call abortboot directly instead of via a wrapper
- change the license to GPLv2+
- cleanup brace usage in multiline statements, conditionals
- allow bootfile to not exist, or to be a standalone filename
- try to clarify what's going on with get_relfile
- try cfg paths one by one instead of building an array
- refactor getenv/printfs to a new from_env function
- use the new generic menu code instead of that being integrated
- drop the ifdef from do_tftp in common.h
- use a clearer comment wrt to localcmd dup
- default to no timeout

changes in v3:
- use GPLv2+ license for the readme
- parse and create menu in separate steps
- adapt to menu interface changes

changes in v4:
- rename pxecfg to pxe
- expose run_command2 externally when using pxe
- add more comments to common/cmd_pxe.c
- format_mac_pxe's outbuf is now allocated in its caller
- get_bootfile_path now takes bootfile_path from caller
- drop a redundant file not found message
- make printf messages more informative
- use sizeof(struct blah) instead of sizeof(*p)
- use memset to initialize some structs per wd's request
- use isblank to check for non EOL whitespace
- switch to standard subcommand handling
- fix regression where ctrl+c didn't return to command line
- check for filesize missing after a tftp get
- only call do_bootm with argc == 4 if fdtaddr != NULL (thanks Ricardo
  Salveti)
- use lowercase hex in formatted MAC string (thanks Lo?c Minier)
- prefix MAC strings with "01-" to indicate Ethernet hwtype (thanks Lo?c
  Minier)
- switch to the standard environment variables
- switch from simple to strict strtoul where possible

 common/Makefile  |    1 +
 common/cmd_pxe.c | 1349 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 common/main.c    |    2 +
 doc/README.pxe   |  240 ++++++++++
 include/common.h |    6 +
 5 files changed, 1598 insertions(+), 0 deletions(-)
 create mode 100644 common/cmd_pxe.c
 create mode 100644 doc/README.pxe

diff --git a/common/Makefile b/common/Makefile
index ebe45b8..feb8a46 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -135,6 +135,7 @@ COBJS-$(CONFIG_CMD_PCI) += cmd_pci.o
 endif
 COBJS-y += cmd_pcmcia.o
 COBJS-$(CONFIG_CMD_PORTIO) += cmd_portio.o
+COBJS-$(CONFIG_CMD_PXE) += cmd_pxe.o
 COBJS-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o
 COBJS-$(CONFIG_CMD_REISER) += cmd_reiser.o
 COBJS-$(CONFIG_CMD_SATA) += cmd_sata.o
diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c
new file mode 100644
index 0000000..ad11214
--- /dev/null
+++ b/common/cmd_pxe.c
@@ -0,0 +1,1349 @@
+/*
+ * Copyright 2010-2011 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <errno.h>
+#include <linux/list.h>
+
+#include "menu.h"
+
+#define MAX_TFTP_PATH_LEN 127
+
+
+/*
+ * Like getenv, but prints an error if envvar isn't defined in the
+ * environment.  It always returns what getenv does, so it can be used in
+ * place of getenv without changing error handling otherwise.
+ */
+static char *from_env(char *envvar)
+{
+	char *ret;
+
+	ret = getenv(envvar);
+
+	if (!ret)
+		printf("missing environment variable: %s\n", envvar);
+
+	return ret;
+}
+
+/*
+ * Convert an ethaddr from the environment to the format used by pxelinux
+ * filenames based on mac addresses. Convert's ':' to '-', and adds "01-" to
+ * the beginning of the ethernet address to indicate a hardware type of
+ * Ethernet. Also converts uppercase hex characters into lowercase, to match
+ * pxelinux's behavior.
+ *
+ * Returns 1 for success, -ENOENT if 'ethaddr' is undefined in the
+ * environment, or some other value < 0 on error.
+ */
+static int format_mac_pxe(char *outbuf, size_t outbuf_len)
+{
+	size_t ethaddr_len;
+	char *p, *ethaddr;
+
+	ethaddr = from_env("ethaddr");
+
+	if (!ethaddr)
+		return -ENOENT;
+
+	ethaddr_len = strlen(ethaddr);
+
+	/*
+	 * ethaddr_len + 4 gives room for "01-", ethaddr, and a NUL byte at
+	 * the end.
+	 */
+	if (outbuf_len < ethaddr_len + 4) {
+		printf("outbuf is too small (%d < %d)\n",
+				outbuf_len, ethaddr_len + 4);
+
+		return -EINVAL;
+	}
+
+	strcpy(outbuf, "01-");
+
+	for (p = outbuf + 3; *ethaddr; ethaddr++, p++) {
+		if (*ethaddr == ':')
+			*p = '-';
+		else
+			*p = tolower(*ethaddr);
+	}
+
+	*p = '\0';
+
+	return 1;
+}
+
+/*
+ * Returns the directory the file specified in the bootfile env variable is
+ * in. If bootfile isn't defined in the environment, return NULL, which should
+ * be interpreted as "don't prepend anything to paths".
+ */
+static int get_bootfile_path(char *bootfile_path, size_t bootfile_path_size)
+{
+	char *bootfile, *last_slash;
+	size_t path_len;
+
+	bootfile = from_env("bootfile");
+
+	if (!bootfile) {
+		bootfile_path[0] = '\0';
+		return 1;
+	}
+
+	last_slash = strrchr(bootfile, '/');
+
+	if (last_slash == NULL) {
+		bootfile_path[0] = '\0';
+		return 1;
+	}
+
+	path_len = (last_slash - bootfile) + 1;
+
+	if (bootfile_path_size < path_len) {
+		printf("bootfile_path too small. (%d < %d)\n",
+				bootfile_path_size, path_len);
+
+		return -1;
+	}
+
+	strncpy(bootfile_path, bootfile, path_len);
+
+	bootfile_path[path_len] = '\0';
+
+	return 1;
+}
+
+/*
+ * As in pxelinux, paths to files referenced from files we retrieve are
+ * relative to the location of bootfile. get_relfile takes such a path and
+ * joins it with the bootfile path to get the full path to the target file. If
+ * the bootfile path is NULL, we use file_path as is.
+ *
+ * Returns 1 for success, or < 0 on error.
+ */
+static int get_relfile(char *file_path, void *file_addr)
+{
+	size_t path_len;
+	char relfile[MAX_TFTP_PATH_LEN+1];
+	char addr_buf[10];
+	char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
+	int err;
+
+	err = get_bootfile_path(relfile, sizeof(relfile));
+
+	if (err < 0)
+		return err;
+
+	path_len = strlen(file_path);
+	path_len += strlen(relfile);
+
+	if (path_len > MAX_TFTP_PATH_LEN) {
+		printf("Base path too long (%s%s)\n",
+					relfile,
+					file_path);
+
+		return -ENAMETOOLONG;
+	}
+
+	strcat(relfile, file_path);
+
+	printf("Retrieving file: %s\n", relfile);
+
+	sprintf(addr_buf, "%p", file_addr);
+
+	tftp_argv[1] = addr_buf;
+	tftp_argv[2] = relfile;
+
+	if (do_tftpb(NULL, 0, 3, tftp_argv))
+		return -ENOENT;
+
+	return 1;
+}
+
+/*
+ * Retrieve the file at 'file_path' to the locate given by 'file_addr'. If
+ * 'bootfile' was specified in the environment, the path to bootfile will be
+ * prepended to 'file_path' and the resulting path will be used.
+ *
+ * Returns 1 on success, or < 0 for error.
+ */
+static int get_pxe_file(char *file_path, void *file_addr)
+{
+	unsigned long config_file_size;
+	char *tftp_filesize;
+	int err;
+
+	err = get_relfile(file_path, file_addr);
+
+	if (err < 0)
+		return err;
+
+	/*
+	 * the file comes without a NUL byte@the end, so find out its size
+	 * and add the NUL byte.
+	 */
+	tftp_filesize = from_env("filesize");
+
+	if (!tftp_filesize)
+		return -ENOENT;
+
+	if (strict_strtoul(tftp_filesize, 16, &config_file_size) < 0)
+		return -EINVAL;
+
+	*(char *)(file_addr + config_file_size) = '\0';
+
+	return 1;
+}
+
+#define PXELINUX_DIR "pxelinux.cfg/"
+
+/*
+ * Retrieves a file in the 'pxelinux.cfg' folder. Since this uses get_pxe_file
+ * to do the hard work, the location of the 'pxelinux.cfg' folder is generated
+ * from the bootfile path, as described above.
+ *
+ * Returns 1 on success or < 0 on error.
+ */
+static int get_pxelinux_path(char *file, void *pxefile_addr_r)
+{
+	size_t base_len = strlen(PXELINUX_DIR);
+	char path[MAX_TFTP_PATH_LEN+1];
+
+	if (base_len + strlen(file) > MAX_TFTP_PATH_LEN) {
+		printf("path (%s%s) too long, skipping\n",
+				PXELINUX_DIR, file);
+		return -ENAMETOOLONG;
+	}
+
+	sprintf(path, PXELINUX_DIR "%s", file);
+
+	return get_pxe_file(path, pxefile_addr_r);
+}
+
+/*
+ * Looks for a pxe file with a name based on the pxeuuid environment variable.
+ *
+ * Returns 1 on success or < 0 on error.
+ */
+static int pxe_uuid_path(void *pxefile_addr_r)
+{
+	char *uuid_str;
+
+	uuid_str = from_env("pxeuuid");
+
+	if (!uuid_str)
+		return -ENOENT;
+
+	return get_pxelinux_path(uuid_str, pxefile_addr_r);
+}
+
+/*
+ * Looks for a pxe file with a name based on the 'ethaddr' environment
+ * variable.
+ *
+ * Returns 1 on success or < 0 on error.
+ */
+static int pxe_mac_path(void *pxefile_addr_r)
+{
+	char mac_str[21];
+	int err;
+
+	err = format_mac_pxe(mac_str, sizeof(mac_str));
+
+	if (err < 0)
+		return err;
+
+	return get_pxelinux_path(mac_str, pxefile_addr_r);
+}
+
+/*
+ * Looks for pxe files with names based on our IP address. See pxelinux
+ * documentation for details on what these file names look like.  We match
+ * that exactly.
+ *
+ * Returns 1 on success or < 0 on error.
+ */
+static int pxe_ipaddr_paths(void *pxefile_addr_r)
+{
+	char ip_addr[9];
+	int mask_pos, err;
+
+	sprintf(ip_addr, "%08X", ntohl(NetOurIP));
+
+	for (mask_pos = 7; mask_pos >= 0;  mask_pos--) {
+		err = get_pxelinux_path(ip_addr, pxefile_addr_r);
+
+		if (err > 0)
+			return err;
+
+		ip_addr[mask_pos] = '\0';
+	}
+
+	return -ENOENT;
+}
+
+/*
+ * Entry point for the 'pxe get' command.
+ * This Follows pxelinux's rules to download a config file from a tftp server.
+ * The file is stored at the location given by the pxefile_addr_r environment
+ * variable, which must be set.
+ *
+ * UUID comes from pxeuuid env variable, if defined
+ * MAC addr comes from ethaddr env variable, if defined
+ * IP
+ *
+ * see http://syslinux.zytor.com/wiki/index.php/PXELINUX
+ *
+ * Returns 0 on success or 1 on error.
+ */
+static int
+do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	char *pxefile_addr_str;
+	void *pxefile_addr_r;
+	int err;
+
+	if (argc != 1)
+		return cmd_usage(cmdtp);
+
+
+	pxefile_addr_str = from_env("pxefile_addr_r");
+
+	if (!pxefile_addr_str)
+		return 1;
+
+	err = strict_strtoul(pxefile_addr_str, 16,
+				(unsigned long *)&pxefile_addr_r);
+	if (err < 0)
+		return 1;
+
+	/*
+	 * Keep trying paths until we successfully get a file we're looking
+	 * for.
+	 */
+	if (pxe_uuid_path(pxefile_addr_r) > 0
+		|| pxe_mac_path(pxefile_addr_r) > 0
+		|| pxe_ipaddr_paths(pxefile_addr_r) > 0
+		|| get_pxelinux_path("default", pxefile_addr_r) > 0) {
+
+		printf("Config file found\n");
+
+		return 0;
+	}
+
+	printf("Config file not found\n");
+
+	return 1;
+}
+
+/*
+ * Wrapper to make it easier to store the file at file_path in the location
+ * specified by envaddr_name. file_path will be joined to the bootfile path,
+ * if any is specified.
+ *
+ * Returns 1 on success or < 0 on error.
+ */
+static int get_relfile_envaddr(char *file_path, char *envaddr_name)
+{
+	void *file_addr;
+	char *envaddr;
+
+	envaddr = from_env(envaddr_name);
+
+	if (!envaddr)
+		return -ENOENT;
+
+	if (strict_strtoul(envaddr, 16, (unsigned long *)&file_addr) < 0)
+		return -EINVAL;
+
+	return get_relfile(file_path, file_addr);
+}
+
+/*
+ * A note on the pxe file parser.
+ *
+ * We're parsing files that use syslinux grammar, which has a few quirks.
+ * String literals must be recognized based on context - there is no
+ * quoting or escaping support. There's also nothing to explicitly indicate
+ * when a label section completes. We deal with that by ending a label
+ * section whenever we see a line that doesn't include.
+ *
+ * As with the syslinux family, this same file format could be reused in the
+ * future for non pxe purposes. The only action it takes during parsing that
+ * would throw this off is handling of include files. It assumes we're using
+ * pxe, and does a tftp download of a file listed as an include file in the
+ * middle of the parsing operation. That could be handled by refactoring it to
+ * take a 'include file getter' function.
+ */
+
+/*
+ * Describes a single label given in a pxe file.
+ *
+ * Create these with the 'label_create' function given below.
+ *
+ * name - the name of the menu as given on the 'menu label' line.
+ * kernel - the path to the kernel file to use for this label.
+ * append - kernel command line to use when booting this label
+ * initrd - path to the initrd to use for this label.
+ * attempted - 0 if we haven't tried to boot this label, 1 if we have.
+ * localboot - 1 if this label specified 'localboot', 0 otherwise.
+ * list - lets these form a list, which a pxe_menu struct will hold.
+ */
+struct pxe_label {
+	char *name;
+	char *kernel;
+	char *append;
+	char *initrd;
+	int attempted;
+	int localboot;
+	struct list_head list;
+};
+
+/*
+ * Describes a pxe menu as given via pxe files.
+ *
+ * title - the name of the menu as given by a 'menu title' line.
+ * default_label - the name of the default label, if any.
+ * timeout - time in tenths of a second to wait for a user key-press before
+ *           booting the default label.
+ * prompt - if 0, don't prompt for a choice unless the timeout period is
+ *          interrupted.  If 1, always prompt for a choice regardless of
+ *          timeout.
+ * labels - a list of labels defined for the menu.
+ */
+struct pxe_menu {
+	char *title;
+	char *default_label;
+	int timeout;
+	int prompt;
+	struct list_head labels;
+};
+
+/*
+ * Allocates memory for and initializes a pxe_label. This uses malloc, so the
+ * result must be free()'d to reclaim the memory.
+ *
+ * Returns NULL if malloc fails.
+ */
+static struct pxe_label *label_create(void)
+{
+	struct pxe_label *label;
+
+	label = malloc(sizeof(struct pxe_label));
+
+	if (!label)
+		return NULL;
+
+	memset(label, 0, sizeof(struct pxe_label));
+
+	return label;
+}
+
+/*
+ * Free the memory used by a pxe_label, including that used by its name,
+ * kernel, append and initrd members, if they're non NULL.
+ *
+ * So - be sure to only use dynamically allocated memory for the members of
+ * the pxe_label struct, unless you want to clean it up first. These are
+ * currently only created by the pxe file parsing code.
+ */
+static void label_destroy(struct pxe_label *label)
+{
+	if (label->name)
+		free(label->name);
+
+	if (label->kernel)
+		free(label->kernel);
+
+	if (label->append)
+		free(label->append);
+
+	if (label->initrd)
+		free(label->initrd);
+
+	free(label);
+}
+
+/*
+ * Print a label and its string members if they're defined.
+ *
+ * This is passed as a callback to the menu code for displaying each
+ * menu entry.
+ */
+static void label_print(void *data)
+{
+	struct pxe_label *label = data;
+
+	printf("Label: %s\n", label->name);
+
+	if (label->kernel)
+		printf("\tkernel: %s\n", label->kernel);
+
+	if (label->append)
+		printf("\tappend: %s\n", label->append);
+
+	if (label->initrd)
+		printf("\tinitrd: %s\n", label->initrd);
+}
+
+/*
+ * Boot a label that specified 'localboot'. This requires that the 'localcmd'
+ * environment variable is defined. Its contents will be executed as U-boot
+ * command.  If the label specified an 'append' line, its contents will be
+ * used to overwrite the contents of the 'bootargs' environment variable prior
+ * to running 'localcmd'.
+ *
+ * Returns 1 on success or < 0 on error.
+ */
+static int label_localboot(struct pxe_label *label)
+{
+	char *localcmd, *dupcmd;
+	int ret;
+
+	localcmd = from_env("localcmd");
+
+	if (!localcmd)
+		return -ENOENT;
+
+	/*
+	 * dup the command to avoid any issues with the version of it existing
+	 * in the environment changing during the execution of the command.
+	 */
+	dupcmd = strdup(localcmd);
+
+	if (!dupcmd)
+		return -ENOMEM;
+
+	if (label->append)
+		setenv("bootargs", label->append);
+
+	printf("running: %s\n", dupcmd);
+
+	ret = run_command2(dupcmd, 0);
+
+	free(dupcmd);
+
+	return ret;
+}
+
+/*
+ * Boot according to the contents of a pxe_label.
+ *
+ * If we can't boot for any reason, we return.  A successful boot never
+ * returns.
+ *
+ * The kernel will be stored in the location given by the 'kernel_addr_r'
+ * environment variable.
+ *
+ * If the label specifies an initrd file, it will be stored in the location
+ * given by the 'ramdisk_addr_r' environment variable.
+ *
+ * If the label specifies an 'append' line, its contents will overwrite that
+ * of the 'bootargs' environment variable.
+ */
+static void label_boot(struct pxe_label *label)
+{
+	char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
+	int bootm_argc = 3;
+
+	label_print(label);
+
+	label->attempted = 1;
+
+	if (label->localboot) {
+		label_localboot(label);
+		return;
+	}
+
+	if (label->kernel == NULL) {
+		printf("No kernel given, skipping %s\n",
+				label->name);
+		return;
+	}
+
+	if (label->initrd) {
+		if (get_relfile_envaddr(label->initrd, "ramdisk_addr_r") < 0) {
+			printf("Skipping %s for failure retrieving initrd\n",
+					label->name);
+			return;
+		}
+
+		bootm_argv[2] = getenv("ramdisk_addr_r");
+	} else {
+		bootm_argv[2] = "-";
+	}
+
+	if (get_relfile_envaddr(label->kernel, "kernel_addr_r") < 0) {
+		printf("Skipping %s for failure retrieving kernel\n",
+				label->name);
+		return;
+	}
+
+	if (label->append)
+		setenv("bootargs", label->append);
+
+	bootm_argv[1] = getenv("kernel_addr_r");
+
+	/*
+	 * fdt usage is optional.  If there is an fdt_addr specified, we will
+	 * pass it along to bootm, and adjust argc appropriately.
+	 */
+	bootm_argv[3] = getenv("fdt_addr");
+
+	if (bootm_argv[3])
+		bootm_argc = 4;
+
+	do_bootm(NULL, 0, bootm_argc, bootm_argv);
+}
+
+/*
+ * Tokens for the pxe file parser.
+ */
+enum token_type {
+	T_EOL,
+	T_STRING,
+	T_EOF,
+	T_MENU,
+	T_TITLE,
+	T_TIMEOUT,
+	T_LABEL,
+	T_KERNEL,
+	T_APPEND,
+	T_INITRD,
+	T_LOCALBOOT,
+	T_DEFAULT,
+	T_PROMPT,
+	T_INCLUDE,
+	T_INVALID
+};
+
+/*
+ * A token - given by a value and a type.
+ */
+struct token {
+	char *val;
+	enum token_type type;
+};
+
+/*
+ * Keywords recognized.
+ */
+static const struct token keywords[] = {
+	{"menu", T_MENU},
+	{"title", T_TITLE},
+	{"timeout", T_TIMEOUT},
+	{"default", T_DEFAULT},
+	{"prompt", T_PROMPT},
+	{"label", T_LABEL},
+	{"kernel", T_KERNEL},
+	{"localboot", T_LOCALBOOT},
+	{"append", T_APPEND},
+	{"initrd", T_INITRD},
+	{"include", T_INCLUDE},
+	{NULL, T_INVALID}
+};
+
+/*
+ * Since pxe(linux) files don't have a token to identify the start of a
+ * literal, we have to keep track of when we're in a state where a literal is
+ * expected vs when we're in a state a keyword is expected.
+ */
+enum lex_state {
+	L_NORMAL = 0,
+	L_KEYWORD,
+	L_SLITERAL
+};
+
+/*
+ * get_string retrieves a string from *p and stores it as a token in
+ * *t.
+ *
+ * get_string used for scanning both string literals and keywords.
+ *
+ * Characters from *p are copied into t-val until a character equal to
+ * delim is found, or a NUL byte is reached. If delim has the special value of
+ * ' ', any whitespace character will be used as a delimiter.
+ *
+ * If lower is unequal to 0, uppercase characters will be converted to
+ * lowercase in the result. This is useful to make keywords case
+ * insensitive.
+ *
+ * The location of *p is updated to point to the first character after the end
+ * of the token - the ending delimiter.
+ *
+ * On success, the new value of t->val is returned. Memory for t->val is
+ * allocated using malloc and must be free()'d to reclaim it.  If insufficient
+ * memory is available, NULL is returned.
+ */
+static char *get_string(char **p, struct token *t, char delim, int lower)
+{
+	char *b, *e;
+	size_t len, i;
+
+	/*
+	 * b and e both start at the beginning of the input stream.
+	 *
+	 * e is incremented until we find the ending delimiter, or a NUL byte
+	 * is reached. Then, we take e - b to find the length of the token.
+	 */
+	b = e = *p;
+
+	while (*e) {
+		if ((delim == ' ' && isspace(*e)) || delim == *e)
+			break;
+		e++;
+	}
+
+	len = e - b;
+
+	/*
+	 * Allocate memory to hold the string, and copy it in, converting
+	 * characters to lowercase if lower is != 0.
+	 */
+	t->val = malloc(len + 1);
+	if (!t->val)
+		return NULL;
+
+	for (i = 0; i < len; i++, b++) {
+		if (lower)
+			t->val[i] = tolower(*b);
+		else
+			t->val[i] = *b;
+	}
+
+	t->val[len] = '\0';
+
+	/*
+	 * Update *p so the caller knows where to continue scanning.
+	 */
+	*p = e;
+
+	t->type = T_STRING;
+
+	return t->val;
+}
+
+/*
+ * Populate a keyword token with a type and value.
+ */
+static void get_keyword(struct token *t)
+{
+	int i;
+
+	for (i = 0; keywords[i].val; i++) {
+		if (!strcmp(t->val, keywords[i].val)) {
+			t->type = keywords[i].type;
+			break;
+		}
+	}
+}
+
+/*
+ * Get the next token.  We have to keep track of which state we're in to know
+ * if we're looking to get a string literal or a keyword.
+ *
+ * *p is updated to point at the first character after the current token.
+ */
+static void get_token(char **p, struct token *t, enum lex_state state)
+{
+	char *c = *p;
+
+	t->type = T_INVALID;
+
+	/* eat non EOL whitespace */
+	while (isblank(*c))
+		c++;
+
+	/*
+	 * eat comments. note that string literals can't begin with #, but
+	 * can contain a # after their first character.
+	 */
+	if (*c == '#') {
+		while (*c && *c != '\n')
+			c++;
+	}
+
+	if (*c == '\n') {
+		t->type = T_EOL;
+		c++;
+	} else if (*c == '\0') {
+		t->type = T_EOF;
+		c++;
+	} else if (state == L_SLITERAL) {
+		get_string(&c, t, '\n', 0);
+	} else if (state == L_KEYWORD) {
+		/*
+		 * when we expect a keyword, we first get the next string
+		 * token delimited by whitespace, and then check if it
+		 * matches a keyword in our keyword list. if it does, it's
+		 * converted to a keyword token of the appropriate type, and
+		 * if not, it remains a string token.
+		 */
+		get_string(&c, t, ' ', 1);
+		get_keyword(t);
+	}
+
+	*p = c;
+}
+
+/*
+ * Increment *c until we get to the end of the current line, or EOF.
+ */
+static void eol_or_eof(char **c)
+{
+	while (**c && **c != '\n')
+		(*c)++;
+}
+
+/*
+ * All of these parse_* functions share some common behavior.
+ *
+ * They finish with *c pointing after the token they parse, and return 1 on
+ * success, or < 0 on error.
+ */
+
+/*
+ * Parse a string literal and store a pointer it at *dst. String literals
+ * terminate at the end of the line.
+ */
+static int parse_sliteral(char **c, char **dst)
+{
+	struct token t;
+	char *s = *c;
+
+	get_token(c, &t, L_SLITERAL);
+
+	if (t.type != T_STRING) {
+		printf("Expected string literal: %.*s\n", (int)(*c - s), s);
+		return -EINVAL;
+	}
+
+	*dst = t.val;
+
+	return 1;
+}
+
+/*
+ * Parse a base 10 (unsigned) integer and store it@*dst.
+ */
+static int parse_integer(char **c, int *dst)
+{
+	struct token t;
+	char *s = *c;
+
+	get_token(c, &t, L_SLITERAL);
+
+	if (t.type != T_STRING) {
+		printf("Expected string: %.*s\n", (int)(*c - s), s);
+		return -EINVAL;
+	}
+
+	*dst = (int)simple_strtoul(t.val, NULL, 10);
+
+	free(t.val);
+
+	return 1;
+}
+
+static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level);
+
+/*
+ * Parse an include statement, and retrieve and parse the file it mentions.
+ *
+ * base should point to a location where it's safe to store the file, and
+ * nest_level should indicate how many nested includes have occurred. For this
+ * include, nest_level has already been incremented and doesn't need to be
+ * incremented here.
+ */
+static int handle_include(char **c, char *base,
+				struct pxe_menu *cfg, int nest_level)
+{
+	char *include_path;
+	char *s = *c;
+	int err;
+
+	err = parse_sliteral(c, &include_path);
+
+	if (err < 0) {
+		printf("Expected include path: %.*s\n",
+				 (int)(*c - s), s);
+		return err;
+	}
+
+	err = get_pxe_file(include_path, base);
+
+	if (err < 0) {
+		printf("Couldn't retrieve %s\n", include_path);
+		return err;
+	}
+
+	return parse_pxefile_top(base, cfg, nest_level);
+}
+
+/*
+ * Parse lines that begin with 'menu'.
+ *
+ * b and nest are provided to handle the 'menu include' case.
+ *
+ * b should be the address where the file currently being parsed is stored.
+ *
+ * nest_level should be 1 when parsing the top level pxe file, 2 when parsing
+ * a file it includes, 3 when parsing a file included by that file, and so on.
+ */
+static int parse_menu(char **c, struct pxe_menu *cfg, char *b, int nest_level)
+{
+	struct token t;
+	char *s = *c;
+	int err;
+
+	get_token(c, &t, L_KEYWORD);
+
+	switch (t.type) {
+	case T_TITLE:
+		err = parse_sliteral(c, &cfg->title);
+
+		break;
+
+	case T_INCLUDE:
+		err = handle_include(c, b + strlen(b) + 1, cfg,
+						nest_level + 1);
+		break;
+
+	default:
+		printf("Ignoring malformed menu command: %.*s\n",
+				(int)(*c - s), s);
+	}
+
+	if (err < 0)
+		return err;
+
+	eol_or_eof(c);
+
+	return 1;
+}
+
+/*
+ * Handles parsing a 'menu line' when we're parsing a label.
+ */
+static int parse_label_menu(char **c, struct pxe_menu *cfg,
+				struct pxe_label *label)
+{
+	struct token t;
+	char *s;
+
+	s = *c;
+
+	get_token(c, &t, L_KEYWORD);
+
+	switch (t.type) {
+	case T_DEFAULT:
+		if (cfg->default_label)
+			free(cfg->default_label);
+
+		cfg->default_label = strdup(label->name);
+
+		if (!cfg->default_label)
+			return -ENOMEM;
+
+		break;
+	default:
+		printf("Ignoring malformed menu command: %.*s\n",
+				(int)(*c - s), s);
+	}
+
+	eol_or_eof(c);
+
+	return 0;
+}
+
+/*
+ * Parses a label and adds it to the list of labels for a menu.
+ *
+ * A label ends when we either get to the end of a file, or
+ * get some input we otherwise don't have a handler defined
+ * for.
+ *
+ */
+static int parse_label(char **c, struct pxe_menu *cfg)
+{
+	struct token t;
+	char *s = *c;
+	struct pxe_label *label;
+	int err;
+
+	label = label_create();
+	if (!label)
+		return -ENOMEM;
+
+	err = parse_sliteral(c, &label->name);
+	if (err < 0) {
+		printf("Expected label name: %.*s\n", (int)(*c - s), s);
+		label_destroy(label);
+		return -EINVAL;
+	}
+
+	list_add_tail(&label->list, &cfg->labels);
+
+	while (1) {
+		s = *c;
+		get_token(c, &t, L_KEYWORD);
+
+		err = 0;
+		switch (t.type) {
+		case T_MENU:
+			err = parse_label_menu(c, cfg, label);
+			break;
+
+		case T_KERNEL:
+			err = parse_sliteral(c, &label->kernel);
+			break;
+
+		case T_APPEND:
+			err = parse_sliteral(c, &label->append);
+			break;
+
+		case T_INITRD:
+			err = parse_sliteral(c, &label->initrd);
+			break;
+
+		case T_LOCALBOOT:
+			err = parse_integer(c, &label->localboot);
+			break;
+
+		case T_EOL:
+			break;
+
+		default:
+			/*
+			 * put the token back! we don't want it - it's the end
+			 * of a label and whatever token this is, it's
+			 * something for the menu level context to handle.
+			 */
+			*c = s;
+			return 1;
+		}
+
+		if (err < 0)
+			return err;
+	}
+}
+
+/*
+ * This 16 comes from the limit pxelinux imposes on nested includes.
+ *
+ * There is no reason@all we couldn't do more, but some limit helps prevent
+ * infinite (until crash occurs) recursion if a file tries to include itself.
+ */
+#define MAX_NEST_LEVEL 16
+
+/*
+ * Entry point for parsing a menu file. nest_level indicates how many times
+ * we've nested in includes.  It will be 1 for the top level menu file.
+ *
+ * Returns 1 on success, < 0 on error.
+ */
+static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)
+{
+	struct token t;
+	char *s, *b, *label_name;
+	int err;
+
+	b = p;
+
+	if (nest_level > MAX_NEST_LEVEL) {
+		printf("Maximum nesting (%d) exceeded\n", MAX_NEST_LEVEL);
+		return -EMLINK;
+	}
+
+	while (1) {
+		s = p;
+
+		get_token(&p, &t, L_KEYWORD);
+
+		err = 0;
+		switch (t.type) {
+		case T_MENU:
+			err = parse_menu(&p, cfg, b, nest_level);
+			break;
+
+		case T_TIMEOUT:
+			err = parse_integer(&p, &cfg->timeout);
+			break;
+
+		case T_LABEL:
+			err = parse_label(&p, cfg);
+			break;
+
+		case T_DEFAULT:
+			err = parse_sliteral(&p, &label_name);
+
+			if (label_name) {
+				if (cfg->default_label)
+					free(cfg->default_label);
+
+				cfg->default_label = label_name;
+			}
+
+			break;
+
+		case T_PROMPT:
+			err = parse_integer(&p, &cfg->prompt);
+			break;
+
+		case T_EOL:
+			break;
+
+		case T_EOF:
+			return 1;
+
+		default:
+			printf("Ignoring unknown command: %.*s\n",
+							(int)(p - s), s);
+			eol_or_eof(&p);
+		}
+
+		if (err < 0)
+			return err;
+	}
+}
+
+/*
+ * Free the memory used by a pxe_menu and its labels.
+ */
+static void destroy_pxe_menu(struct pxe_menu *cfg)
+{
+	struct list_head *pos, *n;
+	struct pxe_label *label;
+
+	if (cfg->title)
+		free(cfg->title);
+
+	if (cfg->default_label)
+		free(cfg->default_label);
+
+	list_for_each_safe(pos, n, &cfg->labels) {
+		label = list_entry(pos, struct pxe_label, list);
+
+		label_destroy(label);
+	}
+
+	free(cfg);
+}
+
+/*
+ * Entry point for parsing a pxe file. This is only used for the top level
+ * file.
+ *
+ * Returns NULL if there is an error, otherwise, returns a pointer to a
+ * pxe_menu struct populated with the results of parsing the pxe file (and any
+ * files it includes). The resulting pxe_menu struct can be free()'d by using
+ * the destroy_pxe_menu() function.
+ */
+static struct pxe_menu *parse_pxefile(char *menucfg)
+{
+	struct pxe_menu *cfg;
+
+	cfg = malloc(sizeof(struct pxe_menu));
+
+	if (!cfg)
+		return NULL;
+
+	memset(cfg, 0, sizeof(struct pxe_menu));
+
+	INIT_LIST_HEAD(&cfg->labels);
+
+	if (parse_pxefile_top(menucfg, cfg, 1) < 0) {
+		destroy_pxe_menu(cfg);
+		return NULL;
+	}
+
+	return cfg;
+}
+
+/*
+ * Converts a pxe_menu struct into a menu struct for use with U-boot's generic
+ * menu code.
+ */
+static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
+{
+	struct pxe_label *label;
+	struct list_head *pos;
+	struct menu *m;
+	int err;
+
+	/*
+	 * Create a menu and add items for all the labels.
+	 */
+	m = menu_create(cfg->title, cfg->timeout, cfg->prompt, label_print);
+
+	if (!m)
+		return NULL;
+
+	list_for_each(pos, &cfg->labels) {
+		label = list_entry(pos, struct pxe_label, list);
+
+		if (menu_item_add(m, label->name, label) != 1) {
+			menu_destroy(m);
+			return NULL;
+		}
+	}
+
+	/*
+	 * After we've created items for each label in the menu, set the
+	 * menu's default label if one was specified.
+	 */
+	if (cfg->default_label) {
+		err = menu_default_set(m, cfg->default_label);
+		if (err != 1) {
+			if (err != -ENOENT) {
+				menu_destroy(m);
+				return NULL;
+			}
+
+			printf("Missing default: %s\n", cfg->default_label);
+		}
+	}
+
+	return m;
+}
+
+/*
+ * Try to boot any labels we have yet to attempt to boot.
+ */
+static void boot_unattempted_labels(struct pxe_menu *cfg)
+{
+	struct list_head *pos;
+	struct pxe_label *label;
+
+	list_for_each(pos, &cfg->labels) {
+		label = list_entry(pos, struct pxe_label, list);
+
+		if (!label->attempted)
+			label_boot(label);
+	}
+}
+
+/*
+ * Boot the system as prescribed by a pxe_menu.
+ *
+ * Use the menu system to either get the user's choice or the default, based
+ * on config or user input.  If there is no default or user's choice,
+ * attempted to boot labels in the order they were given in pxe files.
+ * If the default or user's choice fails to boot, attempt to boot other
+ * labels in the order they were given in pxe files.
+ *
+ * If this function returns, there weren't any labels that successfully
+ * booted, or the user interrupted the menu selection via ctrl+c.
+ */
+static void handle_pxe_menu(struct pxe_menu *cfg)
+{
+	void *choice;
+	struct menu *m;
+	int err;
+
+	m = pxe_menu_to_menu(cfg);
+	if (!m)
+		return;
+
+	err = menu_get_choice(m, &choice);
+
+	menu_destroy(m);
+
+	if (err < 1)
+		return;
+
+	label_boot(choice);
+
+	boot_unattempted_labels(cfg);
+}
+
+/*
+ * Boots a system using a pxe file
+ *
+ * Returns 0 on success, 1 on error.
+ */
+static int
+do_pxe_boot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unsigned long pxefile_addr_r;
+	struct pxe_menu *cfg;
+	char *pxefile_addr_str;
+
+	if (argc == 1) {
+		pxefile_addr_str = from_env("pxefile_addr_r");
+		if (!pxefile_addr_str)
+			return 1;
+
+	} else if (argc == 2) {
+		pxefile_addr_str = argv[1];
+	} else {
+		return cmd_usage(cmdtp);
+	}
+
+	if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
+		printf("Invalid pxefile address: %s\n", pxefile_addr_str);
+		return 1;
+	}
+
+	cfg = parse_pxefile((char *)(pxefile_addr_r));
+
+	if (cfg == NULL) {
+		printf("Error parsing config file\n");
+		return 1;
+	}
+
+	handle_pxe_menu(cfg);
+
+	destroy_pxe_menu(cfg);
+
+	return 0;
+}
+
+static cmd_tbl_t cmd_pxe_sub[] = {
+	U_BOOT_CMD_MKENT(get, 1, 1, do_pxe_get, "", ""),
+	U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "")
+};
+
+int do_pxe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	cmd_tbl_t *cp;
+
+	if (argc < 2)
+		return cmd_usage(cmdtp);
+
+	/* drop initial "pxe" arg */
+	argc--;
+	argv++;
+
+	cp = find_cmd_tbl(argv[0], cmd_pxe_sub, ARRAY_SIZE(cmd_pxe_sub));
+
+	if (cp)
+		return cp->cmd(cmdtp, flag, argc, argv);
+
+	return cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(
+	pxe, 3, 1, do_pxe,
+	"commands to get and boot from pxe files",
+	"get - try to retrieve a pxe file using tftp\npxe "
+	"boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n"
+);
diff --git a/common/main.c b/common/main.c
index 5a623d8..e2d015b 100644
--- a/common/main.c
+++ b/common/main.c
@@ -266,7 +266,9 @@ int abortboot(int bootdelay)
 # endif	/* CONFIG_AUTOBOOT_KEYED */
 #endif	/* CONFIG_BOOTDELAY >= 0  */
 
+#ifndef CONFIG_CMD_PXE
 static inline
+#endif
 int run_command2(const char *cmd, int flag)
 {
 #ifndef CONFIG_SYS_HUSH_PARSER
diff --git a/doc/README.pxe b/doc/README.pxe
new file mode 100644
index 0000000..9026d9c
--- /dev/null
+++ b/doc/README.pxe
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2010-2011 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+The 'pxe' commands provide a near subset of the functionality provided by
+the PXELINUX boot loader. This allows U-boot based systems to be controlled
+remotely using the same PXE based techniques that many non U-boot based servers
+use.
+
+Commands
+========
+
+pxe get
+-------
+     syntax: pxe get
+
+     follows PXELINUX's rules for retrieving configuration files from a tftp
+     server, and supports a subset of PXELINUX's config file syntax.
+
+     Environment
+     -----------
+     'pxe get' requires two environment variables to be set:
+
+     pxefile_addr_r - should be set to a location in RAM large enough to hold
+     pxe files while they're being processed. Up to 16 config files may be
+     held in memory at once. The exact number and size of the files varies with
+     how the system is being used. A typical config file is a few hundred bytes
+     long.
+
+     bootfile,serverip - these two are typically set in the DHCP response
+     handler, and correspond to fields in the DHCP response.
+
+     'pxe get' optionally supports these two environment variables being set:
+
+     ethaddr - this is the standard MAC address for the ethernet adapter in use.
+     'pxe get' uses it to look for a configuration file specific to a system's
+     MAC address.
+
+     pxeuuid - this is a UUID in standard form using lower case hexadecimal
+     digits, for example, 550e8400-e29b-41d4-a716-446655440000. 'pxe get' uses
+     it to look for a configuration file based on the system's UUID.
+
+     File Paths
+     ----------
+     'pxe get' repeatedly tries to download config files until it either
+     successfully downloads one or runs out of paths to try. The order and
+     contents of paths it tries mirrors exactly that of PXELINUX - you can
+     read in more detail about it at:
+
+     http://syslinux.zytor.com/wiki/index.php/Doc/pxelinux
+
+pxe boot
+--------
+     syntax: pxe boot [pxefile_addr_r]
+
+     Interprets a pxe file stored in memory.
+
+     pxefile_addr_r is an optional argument giving the location of the pxe file.
+     The file must be terminated with a NUL byte.
+
+     Environment
+     -----------
+     There are some environment variables that may need to be set, depending
+     on conditions.
+
+     pxefile_addr_r - if the optional argument pxefile_addr_r is not supplied,
+     an environment variable named pxefile_addr_r must be supplied. This is
+     typically the same value as is used for the 'pxe get' command.
+
+     bootfile - typically set in the DHCP response handler based on the
+     same field in the DHCP respone, this path is used to generate the base
+     directory that all other paths to files retrieved by 'pxe boot' will use.
+     If no bootfile is specified, paths used in pxe files will be used as is.
+
+     serverip - typically set in the DHCP response handler, this is the IP
+     address of the tftp server from which other files will be retrieved.
+
+     kernel_addr_r, initrd_addr_r - locations in RAM at which 'pxe boot' will
+     store the kernel and initrd it retrieves from tftp. These locations will
+     be passed to the bootm command to boot the kernel. These environment
+     variables are required to be set.
+
+     fdt_addr - the location of a fdt blob. If this is set, it will be passed
+     to bootm when booting a kernel.
+
+pxe file format
+===============
+The pxe file format is nearly a subset of the PXELINUX file format; see
+http://syslinux.zytor.com/wiki/index.php/PXELINUX. It's composed of one line
+commands - global commands, and commands specific to labels. Lines begining
+with # are treated as comments. White space between and at the beginning of
+lines is ignored.
+
+The size of pxe files and the number of labels is only limited by the amount
+of RAM available to U-boot. Memory for labels is dynamically allocated as
+they're parsed, and memory for pxe files is statically allocated, and its
+location is given by the pxefile_addr_r environment variable. The pxe code is
+not aware of the size of the pxefile memory and will outgrow it if pxe files
+are too large.
+
+Supported global commands
+-------------------------
+Unrecognized commands are ignored.
+
+default <label>     - the label named here is treated as the default and is
+                      the first label 'pxe boot' attempts to boot.
+
+menu title <string> - sets a title for the menu of labels being displayed.
+
+menu include <path> - use tftp to retrieve the pxe file at <path>, which
+                      is then immediately parsed as if the start of its
+                      contents were the next line in the current file. nesting
+                      of include up to 16 files deep is supported.
+
+prompt <flag>       - if 1, always prompt the user to enter a label to boot
+                      from. if 0, only prompt the user if timeout expires.
+
+timeout <num>	    - wait for user input for <num>/10 seconds before
+                      auto-booting a node.
+
+label <name>        - begin a label definition. labels continue until
+                      a command not recognized as a label command is seen,
+                      or EOF is reached.
+
+Supported label commands
+------------------------
+labels end when a command not recognized as a label command is reached, or EOF.
+
+menu default        - set this label as the default label to boot; this is
+                      the same behavior as the global default command but
+                      specified in a different way
+
+kernel <path>       - if this label is chosen, use tftp to retrieve the kernel
+                      at <path>. it will be stored at the address indicated in
+                      the kernel_addr_r environment variable, and that address
+                      will be passed to bootm to boot this kernel.
+
+append <string>     - use <string> as the kernel command line when booting this
+                      label.
+
+initrd <path>       - if this label is chosen, use tftp to retrieve the initrd
+                      at <path>. it will be stored at the address indicated in
+                      the initrd_addr_r environment variable, and that address
+                      will be passed to bootm.
+
+localboot <flag>    - Run the command defined by "localcmd" in the environment.
+                      <flag> is ignored and is only here to match the syntax of
+                      PXELINUX config files.
+
+Example
+-------
+Here's a couple of example files to show how this works.
+
+------------/tftpboot/pxelinux.cfg/menus/linux.list----------
+menu title Linux selections
+
+# This is the default label
+label install
+	menu label Default Install Image
+	kernel kernels/install.bin
+	append console=ttyAMA0,38400 debug earlyprintk
+	initrd initrds/uzInitrdDebInstall
+
+# Just another label
+label linux-2.6.38
+	kernel kernels/linux-2.6.38.bin
+	append root=/dev/sdb1
+
+# The locally installed kernel
+label local
+	menu label Locally installed kernel
+	append root=/dev/sdb1
+	localboot 1
+-------------------------------------------------------------
+
+------------/tftpboot/pxelinux.cfg/default-------------------
+menu include pxelinux.cfg/menus/base.menu
+timeout 500
+
+default linux-2.6.38
+-------------------------------------------------------------
+
+When a pxe client retrieves and boots the default pxe file,
+'pxe boot' will wait for user input for 5 seconds before booting
+the linux-2.6.38 label, which will cause /tftpboot/kernels/linux-2.6.38.bin
+to be downloaded, and boot with the command line "root=/dev/sdb1"
+
+Differences with PXELINUX
+=========================
+The biggest difference between U-boot's pxe and PXELINUX is that since
+U-boot's pxe support is written entirely in C, it can run on any platform
+with network support in U-boot. Here are some other differences between
+PXELINUX and U-boot's pxe support.
+
+- U-boot's pxe does not support the PXELINUX DHCP option codes specified
+  in RFC 5071, but could be extended to do so.
+
+- when U-boot's pxe fails to boot, it will return control to U-boot,
+  allowing another command to run, other U-boot command, instead of resetting
+  the machine like PXELINUX.
+
+- U-boot's pxe doesn't rely on or provide an UNDI/PXE stack in memory, it
+  only uses U-boot.
+
+- U-boot's pxe doesn't provide the full menu implementation that PXELINUX
+  does, only a simple text based menu using the commands described in
+  this README.  With PXELINUX, it's possible to have a graphical boot
+  menu, submenus, passwords, etc. U-boot's pxe could be extended to support
+  a more robust menuing system like that of PXELINUX's.
+
+- U-boot's pxe expects U-boot uimg's as kernels.  Anything that would work
+  with the 'bootm' command in U-boot could work with the 'pxe boot' command.
+
+- U-boot's pxe doesn't recognize initrd options in the append command - you
+  must specify initrd files using the initrd command.
+
+- U-boot's pxe only recognizes a single file on the initrd command line.  It
+  could be extended to support multiple.
+
+- in U-boot's pxe, the localboot command doesn't necessarily cause a local
+  disk boot - it will do whatever is defined in the 'localcmd' env
+  variable. And since it doesn't support a full UNDI/PXE stack, the
+  type field is ignored.
+
+- the interactive prompt in U-boot's pxe only allows you to choose a label
+  from the menu.  If you want to boot something not listed, you can ctrl+c
+  out of 'pxe boot' and use existing U-boot commands to accomplish it.
diff --git a/include/common.h b/include/common.h
index 3a9d046..bacca8b 100644
--- a/include/common.h
+++ b/include/common.h
@@ -234,6 +234,9 @@ int	print_buffer (ulong addr, void* data, uint width, uint count, uint linelen);
 /* common/main.c */
 void	main_loop	(void);
 int	run_command	(const char *cmd, int flag);
+#ifdef CONFIG_CMD_PXE
+int run_command2(const char *cmd, int flag);
+#endif
 int	readline	(const char *const prompt);
 int	readline_into_buffer	(const char *const prompt, char * buffer);
 int	parse_line (char *, char *[]);
@@ -264,6 +267,9 @@ extern ulong load_addr;		/* Default Load Address */
 /* common/cmd_doc.c */
 void	doc_probe(unsigned long physadr);
 
+/* common/cmd_net.c */
+int do_tftpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
 /* common/cmd_nvedit.c */
 int	env_init     (void);
 void	env_relocate (void);
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 10/13] net: bootp: add PXE/RFC 4578 DHCP options support
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
                   ` (8 preceding siblings ...)
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 09/13] Add pxe command Jason Hobbs
@ 2011-08-23 21:06 ` Jason Hobbs
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 11/13] Convert ca9x4_ct_vxp to standard env variables Jason Hobbs
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:06 UTC (permalink / raw)
  To: u-boot

These options are required to be present in RFC 4578 compliant DHCP
requests. They give more information to DHCP servers to allow serving
different DHCP responses to different systems based on client
architecture, client capabilities, UUID, or vendor.

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
---
changes for v2:
- Use common.h to get uuid_str_to_bin prototype

changes for v4:
- Ensure pxeuuid contains a valid UUID string

 net/bootp.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/net/bootp.c b/net/bootp.c
index 45eaab1..b04bb2b 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -370,6 +370,11 @@ static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t R
 {
 	u8 *start = e;
 	u8 *cnt;
+#if defined(CONFIG_BOOTP_PXE)
+	char *uuid;
+	size_t vci_strlen;
+	u16 clientarch;
+#endif
 
 #if defined(CONFIG_BOOTP_VENDOREX)
 	u8 *x;
@@ -424,6 +429,41 @@ static int DhcpExtended (u8 * e, int message_type, IPaddr_t ServerID, IPaddr_t R
 	}
 #endif
 
+#if defined(CONFIG_BOOTP_PXE)
+	clientarch = CONFIG_BOOTP_PXE_CLIENTARCH;
+	*e++ = 93;	/* Client System Architecture */
+	*e++ = 2;
+	*e++ = (clientarch >> 8) & 0xff;
+	*e++ = clientarch & 0xff;
+
+	*e++ = 94;	/* Client Network Interface Identifier */
+	*e++ = 3;
+	*e++ = 1;	/* type field for UNDI */
+	*e++ = 0;	/* major revision */
+	*e++ = 0;	/* minor revision */
+
+	uuid = getenv("pxeuuid");
+
+	if (uuid) {
+		if (uuid_str_valid(uuid)) {
+			*e++ = 97;	/* Client Machine Identifier */
+			*e++ = 17;
+			*e++ = 0;	/* type 0 - UUID */
+
+			uuid_str_to_bin(uuid, e);
+			e += 16;
+		} else {
+			printf("Invalid pxeuuid: %s\n", uuid);
+		}
+	}
+
+	*e++ = 60;	/* Vendor Class Identifier */
+	vci_strlen = strlen(CONFIG_BOOTP_VCI_STRING);
+	*e++ = vci_strlen;
+	memcpy(e, CONFIG_BOOTP_VCI_STRING, vci_strlen);
+	e += vci_strlen;
+#endif
+
 #if defined(CONFIG_BOOTP_VENDOREX)
 	if ((x = dhcp_vendorex_prep (e)))
 		return x - start;
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 11/13] Convert ca9x4_ct_vxp to standard env variables
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
                   ` (9 preceding siblings ...)
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 10/13] net: bootp: add PXE/RFC 4578 DHCP options support Jason Hobbs
@ 2011-08-23 21:06 ` Jason Hobbs
  2011-08-23 21:07 ` [U-Boot] [PATCH v4 12/13] arm: ca9x4_ct_vxp: enable pxe command support Jason Hobbs
  2011-08-23 21:07 ` [U-Boot] [PATCH v4 13/13] arm: ca9x4_ct_vxp: enable PXE BOOTP options support Jason Hobbs
  12 siblings, 0 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:06 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
Cc: Matt Waddel <matt.waddel@linaro.org>
---
new in v4

 include/configs/ca9x4_ct_vxp.h |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/include/configs/ca9x4_ct_vxp.h b/include/configs/ca9x4_ct_vxp.h
index 8c57eab..7e5dc66 100644
--- a/include/configs/ca9x4_ct_vxp.h
+++ b/include/configs/ca9x4_ct_vxp.h
@@ -129,10 +129,10 @@
 #define CONFIG_BOOTCOMMAND		"run bootflash;"
 #define CONFIG_EXTRA_ENV_SETTINGS \
 		"loadaddr=0x80008000\0" \
-		"initrd=0x61000000\0" \
-		"kerneladdr=0x44100000\0" \
-		"initrdaddr=0x44800000\0" \
-		"maxinitrd=0x1800000\0" \
+		"ramdisk_addr_r=0x61000000\0" \
+		"kernel_addr=0x44100000\0" \
+		"ramdisk_addr=0x44800000\0" \
+		"maxramdisk=0x1800000\0" \
 		"console=ttyAMA0,38400n8\0" \
 		"dram=1024M\0" \
 		"root=/dev/sda1 rw\0" \
@@ -142,8 +142,8 @@
 			"mem=${dram} mtdparts=${mtd} mmci.fmax=190000 " \
 			"devtmpfs.mount=0  vmalloc=256M\0" \
 		"bootflash=run flashargs; " \
-			"cp ${initrdaddr} ${initrd} ${maxinitrd}; " \
-			"bootm ${kerneladdr} ${initrd}\0"
+			"cp ${ramdisk_addr} ${ramdisk_addr_r} ${maxramdisk}; " \
+			"bootm ${kernel_addr} ${ramdisk_addr_r}\0"
 
 /* FLASH and environment organization */
 #define PHYS_FLASH_SIZE			0x04000000	/* 64MB */
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 12/13] arm: ca9x4_ct_vxp: enable pxe command support
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
                   ` (10 preceding siblings ...)
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 11/13] Convert ca9x4_ct_vxp to standard env variables Jason Hobbs
@ 2011-08-23 21:07 ` Jason Hobbs
  2011-08-23 21:07 ` [U-Boot] [PATCH v4 13/13] arm: ca9x4_ct_vxp: enable PXE BOOTP options support Jason Hobbs
  12 siblings, 0 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:07 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
Cc: Matt Waddel <matt.waddel@linaro.org>
---
changes in v2:
- use CONFIG_MENU to enable building the menu for pxecfg use

changes in v4:
- use CONFIG_CMD_PXE instead of CONFIG_CMD_PXECFG
- update to standard environment variables

 include/configs/ca9x4_ct_vxp.h |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/include/configs/ca9x4_ct_vxp.h b/include/configs/ca9x4_ct_vxp.h
index 7e5dc66..5f49f49 100644
--- a/include/configs/ca9x4_ct_vxp.h
+++ b/include/configs/ca9x4_ct_vxp.h
@@ -70,6 +70,8 @@
 /* Command line configuration */
 #define CONFIG_CMD_BDI
 #define CONFIG_CMD_DHCP
+#define CONFIG_CMD_PXE
+#define CONFIG_MENU
 #define CONFIG_CMD_ELF
 #define CONFIG_CMD_ENV
 #define CONFIG_CMD_FLASH
@@ -133,6 +135,8 @@
 		"kernel_addr=0x44100000\0" \
 		"ramdisk_addr=0x44800000\0" \
 		"maxramdisk=0x1800000\0" \
+		"pxefile_addr_r=0x88000000\0" \
+		"kernel_addr_r=0x80008000\0" \
 		"console=ttyAMA0,38400n8\0" \
 		"dram=1024M\0" \
 		"root=/dev/sda1 rw\0" \
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 13/13] arm: ca9x4_ct_vxp: enable PXE BOOTP options support
  2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
                   ` (11 preceding siblings ...)
  2011-08-23 21:07 ` [U-Boot] [PATCH v4 12/13] arm: ca9x4_ct_vxp: enable pxe command support Jason Hobbs
@ 2011-08-23 21:07 ` Jason Hobbs
  12 siblings, 0 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-23 21:07 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
Cc: Matt Waddel <matt.waddel@linaro.org>
---
changes for v2:
- add armv7 architecture to VCI string

changes for v4:
- combine the PXE bootp options with the other bootp options

 include/configs/ca9x4_ct_vxp.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/include/configs/ca9x4_ct_vxp.h b/include/configs/ca9x4_ct_vxp.h
index 5f49f49..5adfe64 100644
--- a/include/configs/ca9x4_ct_vxp.h
+++ b/include/configs/ca9x4_ct_vxp.h
@@ -98,6 +98,9 @@
 #define CONFIG_BOOTP_BOOTPATH
 #define CONFIG_BOOTP_GATEWAY
 #define CONFIG_BOOTP_HOSTNAME
+#define CONFIG_BOOTP_PXE
+#define CONFIG_BOOTP_PXE_CLIENTARCH	0x100
+#define CONFIG_BOOTP_VCI_STRING		"U-boot.armv7.ca9x4_ct_vxp"
 
 /* Miscellaneous configurable options */
 #undef	CONFIG_SYS_CLKS_IN_HZ
-- 
1.7.0.4

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

* [U-Boot] [PATCH v4 04/13] Add isblank
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 04/13] Add isblank Jason Hobbs
@ 2011-08-23 21:40   ` Mike Frysinger
  2011-08-24 15:40     ` Jason Hobbs
  0 siblings, 1 reply; 21+ messages in thread
From: Mike Frysinger @ 2011-08-23 21:40 UTC (permalink / raw)
  To: u-boot

On Tuesday, August 23, 2011 17:06:52 Jason Hobbs wrote:
> Existing ctype checks are implemented using a 256 byte lookup table,
> allowing each character to be in any of 8 character classes. Since there
> are 8 existing character classes without the blank class, I implemented
> isblank without using the lookup table.  Since there are only two blank
> characters - tab and space - this is a more reasonable approach than
> doubling the size of the lookup table to accommodate one more class.

and isspace() doesnt work because ... ?
-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/20110823/db692b7f/attachment.pgp 

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

* [U-Boot] [PATCH v4 06/13] Replace space and tab checks with isblank
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 06/13] Replace space and tab checks with isblank Jason Hobbs
@ 2011-08-23 21:42   ` Mike Frysinger
  2011-08-24 15:56     ` Jason Hobbs
  0 siblings, 1 reply; 21+ messages in thread
From: Mike Frysinger @ 2011-08-23 21:42 UTC (permalink / raw)
  To: u-boot

On Tuesday, August 23, 2011 17:06:54 Jason Hobbs wrote:
> -	while (*nn == ' ' || *nn == '\t')
> +	while (isblank(*nn))
>  		nn++;

at least for these "walking forward" ones, they could be replaced with:
	nn += strspn(nn, " \t");
-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/20110823/f791462e/attachment.pgp 

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

* [U-Boot] [PATCH v4 07/13] Add standard environment variables README
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 07/13] Add standard environment variables README Jason Hobbs
@ 2011-08-23 21:45   ` Mike Frysinger
  2011-08-24 16:29     ` Jason Hobbs
  0 siblings, 1 reply; 21+ messages in thread
From: Mike Frysinger @ 2011-08-23 21:45 UTC (permalink / raw)
  To: u-boot

this somewhat duplicates the "Environment Variables" section in the top level 
README.  can't we have just one location for this stuff ?
-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/20110823/57dee6df/attachment.pgp 

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

* [U-Boot] [PATCH v4 03/13] common: add run_command2 for running simple or hush commands
  2011-08-23 21:06 ` [U-Boot] [PATCH v4 03/13] common: add run_command2 for running simple or hush commands Jason Hobbs
@ 2011-08-23 21:46   ` Mike Frysinger
  0 siblings, 0 replies; 21+ messages in thread
From: Mike Frysinger @ 2011-08-23 21:46 UTC (permalink / raw)
  To: u-boot

On Tuesday, August 23, 2011 17:06:51 Jason Hobbs wrote:
> Signed-off-by: Jason Hobbs <jason.hobbs@calxeda.com>
> ---
> changes in v2:
> - whitespace correction
> 
> changes in v4:
> - fix indention of a run_command2 line
> - make run_command2 static inline
> 
>  common/hush.c  |    2 +-
>  common/main.c  |   50 +++++++++++++++++++++-----------------------------
>  include/hush.h |    2 +-
>  3 files changed, 23 insertions(+), 31 deletions(-)
> 
> diff --git a/common/hush.c b/common/hush.c
> index 85a6030..940889b 100644
> --- a/common/hush.c
> +++ b/common/hush.c
> @@ -3217,7 +3217,7 @@ int parse_stream_outer(struct in_str *inp, int flag)
>  #ifndef __U_BOOT__
>  static int parse_string_outer(const char *s, int flag)
>  #else
> -int parse_string_outer(char *s, int flag)
> +int parse_string_outer(const char *s, int flag)
>  #endif	/* __U_BOOT__ */
>  {
>  	struct in_str input;
> diff --git a/common/main.c b/common/main.c
> index b97d89e..e9e8350 100644
> --- a/common/main.c
> +++ b/common/main.c
> @@ -83,8 +83,7 @@ extern void mdm_init(void); /* defined in board.c */
> 
>  /*************************************************************************
> ** * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
> - * returns: 0 -  no key string, allow autoboot
> - *          1 - got key string, abort
> + * returns: 0 -  no key string, allow autoboot 1 - got key string, abort
>   */
>  #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
>  # if defined(CONFIG_AUTOBOOT_KEYED)
> @@ -266,6 +265,20 @@ int abortboot(int bootdelay)
>  # endif	/* CONFIG_AUTOBOOT_KEYED */
>  #endif	/* CONFIG_BOOTDELAY >= 0  */
> 
> +static inline
> +int run_command2(const char *cmd, int flag)
> +{
> +#ifndef CONFIG_SYS_HUSH_PARSER
> +	if (run_command(cmd, flag) == -1)
> +		return 1;
> +#else
> +	if (parse_string_outer(cmd,
> +	    FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
> +		return 1;
> +#endif
> +	return 0;
> +}

do you need to do your own return value munging ?  seems like "returns 0 on 
success, non-zero on failure" would allow you to do:
{
#ifndef CONFIG_SYS_HUSH_PARSER
	return run_command(cmd, flag);
#else
	return parse_string_outer(cmd,
		FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);
#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/20110823/e0487afe/attachment.pgp 

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

* [U-Boot] [PATCH v4 04/13] Add isblank
  2011-08-23 21:40   ` Mike Frysinger
@ 2011-08-24 15:40     ` Jason Hobbs
  0 siblings, 0 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-24 15:40 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 23, 2011 at 05:40:35PM -0400, Mike Frysinger wrote:
> On Tuesday, August 23, 2011 17:06:52 Jason Hobbs wrote:
> > Existing ctype checks are implemented using a 256 byte lookup table,
> > allowing each character to be in any of 8 character classes. Since there
> > are 8 existing character classes without the blank class, I implemented
> > isblank without using the lookup table.  Since there are only two blank
> > characters - tab and space - this is a more reasonable approach than
> > doubling the size of the lookup table to accommodate one more class.
> 
> and isspace() doesnt work because ... ?

Because isspace matches characters other than tab and space, like end of
line, which isn't always desired.

Jason

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

* [U-Boot] [PATCH v4 06/13] Replace space and tab checks with isblank
  2011-08-23 21:42   ` Mike Frysinger
@ 2011-08-24 15:56     ` Jason Hobbs
  0 siblings, 0 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-24 15:56 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 23, 2011 at 05:42:59PM -0400, Mike Frysinger wrote:
> On Tuesday, August 23, 2011 17:06:54 Jason Hobbs wrote:
> > -	while (*nn == ' ' || *nn == '\t')
> > +	while (isblank(*nn))
> >  		nn++;
> 
> at least for these "walking forward" ones, they could be replaced with:
> 	nn += strspn(nn, " \t");
> -mike

Sure, and we'd pick up the use of a currently unused function which
might otherwise get optimized away with linker garbage collection. Even
without taking garbage collection of strspn into account, switching one
of the "walkahead while isblank" lines in my tree to the strspn pattern
inceases my binary size by 11 bytes - two of them inceases it by 31
bytes. There's also the extra overhead for the function call and
strspn's local variables. I'd consider it if strspn was more readable (I
don't think it is), or there was some cost to adding the isblank macro
(there isn't, as it's replacing existing code that was doing the same
thing).

Jason

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

* [U-Boot] [PATCH v4 07/13] Add standard environment variables README
  2011-08-23 21:45   ` Mike Frysinger
@ 2011-08-24 16:29     ` Jason Hobbs
  0 siblings, 0 replies; 21+ messages in thread
From: Jason Hobbs @ 2011-08-24 16:29 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 23, 2011 at 05:45:07PM -0400, Mike Frysinger wrote:
> this somewhat duplicates the "Environment Variables" section in the top level 
> README.  can't we have just one location for this stuff ?

Ah, you're right. When I searched for existing doc before adding this
file, I didn't think to look outside of the doc dir.

I will move this doc into README.

Jason

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

end of thread, other threads:[~2011-08-24 16:29 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-23 21:06 [U-Boot] [PATCH v4 00/13] Add PXE support Jason Hobbs
2011-08-23 21:06 ` [U-Boot] [PATCH v4 01/13] Add generic, reusable menu code Jason Hobbs
2011-08-23 21:06 ` [U-Boot] [PATCH v4 02/13] common, menu: use abortboot for menu timeout Jason Hobbs
2011-08-23 21:06 ` [U-Boot] [PATCH v4 03/13] common: add run_command2 for running simple or hush commands Jason Hobbs
2011-08-23 21:46   ` Mike Frysinger
2011-08-23 21:06 ` [U-Boot] [PATCH v4 04/13] Add isblank Jason Hobbs
2011-08-23 21:40   ` Mike Frysinger
2011-08-24 15:40     ` Jason Hobbs
2011-08-23 21:06 ` [U-Boot] [PATCH v4 05/13] cosmetic: remove unneeded curly braces Jason Hobbs
2011-08-23 21:06 ` [U-Boot] [PATCH v4 06/13] Replace space and tab checks with isblank Jason Hobbs
2011-08-23 21:42   ` Mike Frysinger
2011-08-24 15:56     ` Jason Hobbs
2011-08-23 21:06 ` [U-Boot] [PATCH v4 07/13] Add standard environment variables README Jason Hobbs
2011-08-23 21:45   ` Mike Frysinger
2011-08-24 16:29     ` Jason Hobbs
2011-08-23 21:06 ` [U-Boot] [PATCH v4 08/13] lib: add uuid_str_to_bin for use with bootp and PXE uuid Jason Hobbs
2011-08-23 21:06 ` [U-Boot] [PATCH v4 09/13] Add pxe command Jason Hobbs
2011-08-23 21:06 ` [U-Boot] [PATCH v4 10/13] net: bootp: add PXE/RFC 4578 DHCP options support Jason Hobbs
2011-08-23 21:06 ` [U-Boot] [PATCH v4 11/13] Convert ca9x4_ct_vxp to standard env variables Jason Hobbs
2011-08-23 21:07 ` [U-Boot] [PATCH v4 12/13] arm: ca9x4_ct_vxp: enable pxe command support Jason Hobbs
2011-08-23 21:07 ` [U-Boot] [PATCH v4 13/13] arm: ca9x4_ct_vxp: enable PXE BOOTP options support Jason Hobbs

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.