summaryrefslogtreecommitdiff
path: root/ecos/packages/redboot/current/src
diff options
context:
space:
mode:
authorschodet2007-02-23 12:33:47 +0000
committerschodet2007-02-23 12:33:47 +0000
commit22e4b1be3fe83053543994c325cb0d44e4587723 (patch)
tree6a4ef5b3c8ed45de299c185e5dd3391c934c6e1b /ecos/packages/redboot/current/src
parent16697c575dfa90feb62c8db019d62682dfe026ca (diff)
Added ecos and build system.
git-svn-id: svn+ssh://pessac/svn/cesar/trunk@4 017c9cb6-072f-447c-8318-d5b54f68fe89
Diffstat (limited to 'ecos/packages/redboot/current/src')
-rw-r--r--ecos/packages/redboot/current/src/alias.c174
-rw-r--r--ecos/packages/redboot/current/src/caches.c101
-rw-r--r--ecos/packages/redboot/current/src/cksum.c96
-rw-r--r--ecos/packages/redboot/current/src/decompress.c315
-rw-r--r--ecos/packages/redboot/current/src/dump.c158
-rw-r--r--ecos/packages/redboot/current/src/fconfig.c1194
-rw-r--r--ecos/packages/redboot/current/src/flash.c1439
-rw-r--r--ecos/packages/redboot/current/src/fs/disk.c441
-rw-r--r--ecos/packages/redboot/current/src/fs/e2fs.c613
-rw-r--r--ecos/packages/redboot/current/src/fs/fileio.c311
-rw-r--r--ecos/packages/redboot/current/src/fs/ide.c529
-rw-r--r--ecos/packages/redboot/current/src/io.c760
-rw-r--r--ecos/packages/redboot/current/src/iomem.c171
-rw-r--r--ecos/packages/redboot/current/src/load.c820
-rw-r--r--ecos/packages/redboot/current/src/main.c758
-rw-r--r--ecos/packages/redboot/current/src/mcmp.c135
-rw-r--r--ecos/packages/redboot/current/src/mcopy.c134
-rw-r--r--ecos/packages/redboot/current/src/mfill.c113
-rw-r--r--ecos/packages/redboot/current/src/misc_funs.c81
-rw-r--r--ecos/packages/redboot/current/src/net/arp.c212
-rw-r--r--ecos/packages/redboot/current/src/net/bootp.c344
-rw-r--r--ecos/packages/redboot/current/src/net/cksum.c124
-rw-r--r--ecos/packages/redboot/current/src/net/dns.c287
-rw-r--r--ecos/packages/redboot/current/src/net/enet.c248
-rw-r--r--ecos/packages/redboot/current/src/net/http_client.c255
-rw-r--r--ecos/packages/redboot/current/src/net/icmp.c126
-rw-r--r--ecos/packages/redboot/current/src/net/inet_addr.c118
-rw-r--r--ecos/packages/redboot/current/src/net/ip.c216
-rw-r--r--ecos/packages/redboot/current/src/net/net_io.c899
-rw-r--r--ecos/packages/redboot/current/src/net/ping.c248
-rw-r--r--ecos/packages/redboot/current/src/net/pktbuf.c167
-rw-r--r--ecos/packages/redboot/current/src/net/tcp.c921
-rw-r--r--ecos/packages/redboot/current/src/net/tftp_client.c279
-rw-r--r--ecos/packages/redboot/current/src/net/timers.c135
-rw-r--r--ecos/packages/redboot/current/src/net/udp.c268
-rw-r--r--ecos/packages/redboot/current/src/parse.c402
-rw-r--r--ecos/packages/redboot/current/src/syscall.c655
-rw-r--r--ecos/packages/redboot/current/src/ticks.c77
-rw-r--r--ecos/packages/redboot/current/src/time_date.cxx124
-rw-r--r--ecos/packages/redboot/current/src/version.c97
-rw-r--r--ecos/packages/redboot/current/src/xyzModem.c597
-rw-r--r--ecos/packages/redboot/current/src/xyzModem.h84
42 files changed, 15226 insertions, 0 deletions
diff --git a/ecos/packages/redboot/current/src/alias.c b/ecos/packages/redboot/current/src/alias.c
new file mode 100644
index 0000000000..58cbd6a826
--- /dev/null
+++ b/ecos/packages/redboot/current/src/alias.c
@@ -0,0 +1,174 @@
+//==========================================================================
+//
+// alias.c
+//
+// RedBoot - alias support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas, jskov
+// Date: 2002-05-15
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+
+#ifdef CYGNUM_REDBOOT_FLASH_STRING_SIZE
+# define MAX_STRING_LENGTH CYGNUM_REDBOOT_FLASH_STRING_SIZE
+#else
+# define MAX_STRING_LENGTH 32
+#endif
+
+// Lookup an alias. First try plain string aliases. If that fails try
+// other types so allowing access to all configured values. This allows
+// for alias (macro) expansion of normal 'fconfig' data, such as the
+// board IP address.
+static char *
+lookup_alias(char *alias, char *alias_buf)
+{
+ if (0 == strcasecmp("FREEMEMLO", alias)) {
+ diag_sprintf(alias_buf,"0x%x", ((CYG_ADDRWORD)mem_segments[0].start + 0x03ff) & ~0x03ff);
+ return alias_buf;
+ } else if (0 == strcasecmp("FREEMEMHI", alias)) {
+ diag_sprintf(alias_buf,"0x%x", ((CYG_ADDRWORD)mem_segments[0].end) & ~0x03ff);
+ return alias_buf;
+ }
+
+#ifdef CYGSEM_REDBOOT_FLASH_ALIASES
+ return flash_lookup_alias(alias, alias_buf);
+#else
+ return NULL;
+#endif
+}
+
+// Expand aliases, this is recursive. ie if one alias contains other
+// aliases, these will also be expanded from the insertion point
+// onwards.
+//
+// If 'iter' is zero, then quoted strings are not expanded
+//
+static bool
+_expand_aliases(char *line, int len, int iter)
+{
+ char *lp = line;
+ char *ms, *me, *ep;
+ char *alias;
+ char c;
+ int offset, line_len, alias_len;
+ char alias_buf[MAX_STRING_LENGTH];
+ bool macro_found = false;
+
+ if ((line_len = strlen(line)) != 0) {
+ while (*lp) {
+ c = *lp++;
+ if ((c == '%') && (*lp == '{')) {
+ // Found a macro/alias to expand
+ ms = lp+1;
+ lp += 2;
+ while (*lp && (*lp != '}')) lp++;
+ if (!*lp) {
+ diag_printf("Invalid macro/alias '%s'\n", ms);
+ line[0] = '\0'; // Destroy line
+ return false;
+ }
+ me = lp;
+ *me = '\0';
+ lp++;
+ if ((alias = lookup_alias(ms,alias_buf)) != (char *)NULL) {
+ alias_len = strlen(alias);
+ // See if there is room in the line to expand this macro/alias
+ if ((line_len+alias_len) < len) {
+ // Make a hole by moving data within the line
+ offset = alias_len-strlen(ms)-2; // Number of bytes being inserted
+ ep = &lp[strlen(lp)-1];
+ if (offset > 1) {
+ ep[offset] = '\0';
+ while (ep != (lp-1)) {
+ ep[offset-1] = *ep;
+ ep--;
+ }
+ } else {
+ if (offset <=0) {
+ while ((lp-1) != ep) {
+ lp[offset-1] = *lp;
+ lp++;
+ }
+ lp[offset-1]='\0';
+ }
+ }
+ // Insert the macro/alias data
+ lp = ms-2;
+ while (*alias) {
+ if ((alias[0] == '%') && (alias[1] == '{')) macro_found = true;
+ *lp++ = *alias++;
+ }
+ line_len = strlen(line);
+ lp = lp - alias_len;
+ } else {
+ diag_printf("No room to expand '%s'\n", ms);
+ line[0] = '\0'; // Destroy line
+ return false;
+ }
+ } else {
+ diag_printf("Alias '%s' not defined\n", ms);
+ *me = '|';
+ }
+ } else if ((c == '"') && (iter == 0)) {
+ // Skip quoted strings
+ while (*lp && (*lp != '"')) lp++;
+ }
+ }
+ }
+ return macro_found;
+}
+
+void
+expand_aliases(char *line, int len)
+{
+ int iter = 0;
+
+ while (_expand_aliases(line, len, iter++)) {
+ }
+}
diff --git a/ecos/packages/redboot/current/src/caches.c b/ecos/packages/redboot/current/src/caches.c
new file mode 100644
index 0000000000..b126f19af1
--- /dev/null
+++ b/ecos/packages/redboot/current/src/caches.c
@@ -0,0 +1,101 @@
+//==========================================================================
+//
+// caches.c
+//
+// RedBoot cache control functions
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2002-08-06
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/hal_cache.h>
+
+RedBoot_cmd("cache",
+ "Manage machine caches",
+ "[ON | OFF]",
+ do_caches
+ );
+
+void
+do_caches(int argc, char *argv[])
+{
+ unsigned long oldints;
+ int dcache_on=0, icache_on=0;
+
+ if (argc == 2) {
+ if (strcasecmp(argv[1], "on") == 0) {
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_ICACHE_ENABLE();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ } else if (strcasecmp(argv[1], "off") == 0) {
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_ICACHE_DISABLE();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_ICACHE_INVALIDATE_ALL();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ } else {
+ diag_printf("Invalid cache mode: %s\n", argv[1]);
+ }
+ } else {
+#ifdef HAL_DCACHE_IS_ENABLED
+ HAL_DCACHE_IS_ENABLED(dcache_on);
+#endif
+#ifdef HAL_ICACHE_IS_ENABLED
+ HAL_ICACHE_IS_ENABLED(icache_on);
+#endif
+ diag_printf("Data cache: %s, Instruction cache: %s\n",
+ dcache_on?"On":"Off", icache_on?"On":"Off");
+ }
+}
diff --git a/ecos/packages/redboot/current/src/cksum.c b/ecos/packages/redboot/current/src/cksum.c
new file mode 100644
index 0000000000..6d467e009a
--- /dev/null
+++ b/ecos/packages/redboot/current/src/cksum.c
@@ -0,0 +1,96 @@
+//==========================================================================
+//
+// cksum.c
+//
+// RedBoot POSIX CRC calculation/command
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2001-01-31
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+
+// Compute a CRC, using the POSIX 1003 definition
+
+RedBoot_cmd("cksum",
+ "Compute a 32bit checksum [POSIX algorithm] for a range of memory",
+ "-b <location> -l <length>",
+ do_cksum
+ );
+
+void
+do_cksum(int argc, char *argv[])
+{
+ struct option_info opts[2];
+ unsigned long base, len, crc;
+ bool base_set, len_set;
+
+ init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&base, (bool *)&base_set, "base address");
+ init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&len, (bool *)&len_set, "length");
+ if (!scan_opts(argc, argv, 1, opts, 2, 0, 0, "")) {
+ return;
+ }
+ if (!base_set || !len_set) {
+ if (load_address >= (CYG_ADDRESS)ram_start &&
+ load_address_end < (CYG_ADDRESS)ram_end &&
+ load_address < load_address_end) {
+ base = load_address;
+ len = load_address_end - load_address;
+ diag_printf("Computing cksum for area %lx-%lx\n",
+ base, load_address_end);
+ } else {
+ diag_printf("usage: cksum -b <addr> -l <length>\n");
+ return;
+ }
+ }
+ crc = cyg_posix_crc32((unsigned char *)base, len);
+ diag_printf("POSIX cksum = %lu %lu (0x%08lx 0x%08lx)\n", crc, len, crc, len);
+}
+
diff --git a/ecos/packages/redboot/current/src/decompress.c b/ecos/packages/redboot/current/src/decompress.c
new file mode 100644
index 0000000000..4ea4b4b513
--- /dev/null
+++ b/ecos/packages/redboot/current/src/decompress.c
@@ -0,0 +1,315 @@
+//==========================================================================
+//
+// decompress.c
+//
+// RedBoot decompress support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): jskov
+// Contributors: jskov, gthomas, tkoeller
+// Date: 2001-03-08
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+
+#ifdef CYGPKG_COMPRESS_ZLIB
+#include <cyg/compress/zlib.h>
+static z_stream stream;
+static bool stream_end;
+
+#define __ZLIB_MAGIC__ 0x5A4C4942 // 'ZLIB'
+
+//
+// Free memory [blocks] are stored as a linked list of "struct _block"
+// The 'magic' is kept to insure that the block being freed is reasonable
+//
+// One of either next or size might be removable, if a sentinal block
+// is placed at the end of the region at initialisation time.
+struct _block {
+ int size; // always the total length of the block, including this header
+ long magic; // Must be __ZLIB_MAGIC__ if allocated and 0 if free
+ struct _block *next;
+ struct _block *prev;
+};
+static struct _block *memlist;
+
+#ifdef CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER
+# define ZLIB_COMPRESSION_OVERHEAD CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE
+#else
+# define ZLIB_COMPRESSION_OVERHEAD 0xC000
+#endif
+static void *zlib_workspace;
+
+//
+// This function is run as part of RedBoot's initialization.
+// It will allocate some memory from the "workspace" pool for
+// use by the gzip/zlib routines. This allows the memory usage
+// of RedBoot to be more finely controlled than if we simply
+// used the generic 'malloc() from the heap' functionality.
+//
+static void
+_zlib_init(void)
+{
+ struct _block *bp;
+#ifdef CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER
+ zlib_workspace = fis_zlib_common_buffer;
+#else
+ // Allocate some RAM for use by the gzip/zlib routines
+ workspace_end -= ZLIB_COMPRESSION_OVERHEAD;
+ zlib_workspace = workspace_end;
+#endif
+ bp = (struct _block *)zlib_workspace;
+ memlist = bp;
+ bp->next = bp->prev = 0;
+ bp->size = ZLIB_COMPRESSION_OVERHEAD;
+ bp->magic = 0;
+#ifdef DEBUG_ZLIB_MALLOC
+ show_memlist(__FUNCTION__);
+#endif
+}
+
+RedBoot_init(_zlib_init, RedBoot_INIT_FIRST);
+
+// #define DEBUG_ZLIB_MALLOC
+#ifdef DEBUG_ZLIB_MALLOC
+static void
+show_memlist(char *when)
+{
+ struct _block *bp = memlist;
+
+ diag_printf("memory list after %s\n", when);
+ diag_printf(" --START--- --END----- --SIZE---- --PREV---- --NEXT---- TYPE-----\n");
+ while (bp != (struct _block *)0) {
+ diag_printf(" %08p-%08p 0x%08x %08p %08p %s\n", bp, (unsigned char *)bp+bp->size,
+ bp->size, bp->prev, bp->next, bp->magic == 0 ? "FREE" : "ALLOCATED" );
+ bp = bp->next;
+ }
+ diag_printf("\n");
+}
+#endif
+
+// Note: these have to be global and match the prototype used by the
+// gzip/zlib package since we are exactly replacing them.
+
+void
+*zcalloc(void *opaque, unsigned int items, unsigned int size)
+{
+ voidpf res = 0;
+ int len = (items*size) + sizeof(struct _block);
+ struct _block *bp = memlist;
+ struct _block *nbp;
+
+#ifdef DEBUG_ZLIB_MALLOC
+ /* do this here because when int is called output is not setup yet */
+ static int first_alloc = 1;
+ if ( first_alloc ) {
+ show_memlist("initialization");
+ first_alloc = 0;
+ }
+#endif
+
+ // Simple, first-fit algorithm
+ while (bp) {
+ if (bp->magic == 0 && bp->size > len) {
+ nbp = (struct _block *)((char *)bp + len);
+ /* link new block into chain */
+ nbp->next = bp->next;
+ bp->next = nbp;
+ nbp->prev = bp;
+ /* split size between the two blocks */
+ nbp->size = bp->size - len;
+ bp->size = len;
+ /* mark the new block as free */
+ nbp->magic = 0;
+ /* mark allocated block as allocated */
+ bp->magic = __ZLIB_MAGIC__;
+ res = bp +1;
+ memset(res, 0, len - sizeof(struct _block));
+ break;
+ }
+ bp = bp->next;
+ }
+#ifdef DEBUG_ZLIB_MALLOC
+ diag_printf("%s(0x%x,0x%x) = %p\n", __FUNCTION__, items, size, res);
+ show_memlist(__FUNCTION__);
+#endif
+ if ( res == NULL )
+ diag_printf("zcalloc: failed to allocate 0x%x items of 0x%x bytes == 0x%x bytes\n", items, size, len);
+ return res;
+}
+
+void
+zcfree(void *opaque, void *ptr)
+{
+ struct _block *bp;
+
+ if (!ptr) return; // Safety
+ bp = (struct _block *)((char *)ptr - sizeof(struct _block));
+ if (bp->magic != __ZLIB_MAGIC__) {
+ diag_printf("%s(%p) - invalid block\n", __FUNCTION__, ptr);
+ return;
+ }
+
+ /* mark as free */
+ bp->magic = 0;
+
+#ifdef DEBUG_ZLIB_MALLOC
+ diag_printf("%s(%p) = 0x%x bytes\n", __FUNCTION__, ptr, bp->size);
+#endif
+
+ while(bp->next && bp->next->magic == 0) {
+#ifdef DEBUG_ZLIB_MALLOC
+ diag_printf(" merging %08p and %08p (after)\n", bp, bp->next);
+#endif
+ bp->size += bp->next->size;
+ bp->next = bp->next->next;
+ }
+
+ while(bp->prev && bp->prev->magic == 0) {
+#ifdef DEBUG_ZLIB_MALLOC
+ diag_printf(" merging %08p and %08p (before)\n", bp->prev, bp);
+#endif
+ bp->prev->size += bp->size;
+ bp->prev->next = bp->next;
+ bp = bp->prev;
+ }
+
+#ifdef DEBUG_ZLIB_MALLOC
+ show_memlist(__FUNCTION__);
+#endif
+}
+
+//
+// This function is called to initialize a gzip/zlib stream.
+//
+static int
+gzip_init(_pipe_t* p)
+{
+ int err;
+
+ // Note: this code used to [re]initialize the memory pool used
+ // by zlib. This is now done in _zlib_init(), but only once.
+ stream.zalloc = zcalloc;
+ stream.zfree = zcfree;
+ stream.next_in = NULL;
+ stream.avail_in = 0;
+ stream.next_out = NULL;
+ stream.avail_out = 0;
+ err = inflateInit(&stream);
+ stream_end = false;
+
+ return err;
+}
+
+//
+// This function is called during the decompression cycle to
+// actually cause a buffer to be filled with uncompressed data.
+//
+static int
+gzip_inflate(_pipe_t* p)
+{
+ int err, bytes_out;
+
+ if (stream_end)
+ return Z_STREAM_END;
+
+ stream.next_in = p->in_buf;
+ stream.avail_in = p->in_avail;
+ stream.next_out = p->out_buf;
+ stream.avail_out = p->out_max;
+ err = inflate(&stream, Z_SYNC_FLUSH);
+ bytes_out = stream.next_out - p->out_buf;
+ p->out_size += bytes_out;
+ p->out_buf = stream.next_out;
+ p->msg = stream.msg;
+ p->in_avail = stream.avail_in;
+ p->in_buf = stream.next_in;
+
+ // Let upper layers process any inflated bytes at
+ // end of stream.
+ if (err == Z_STREAM_END && bytes_out) {
+ stream_end = true;
+ err = Z_OK;
+ }
+
+ return err;
+}
+
+//
+// Called when the input data is completed or an error has
+// occured. This allows for clean up as well as passing error
+// information up.
+//
+static int
+gzip_close(_pipe_t* p, int err)
+{
+ switch (err) {
+ case Z_STREAM_END:
+ err = 0;
+ break;
+ case Z_OK:
+ if (stream_end) {
+ break;
+ }
+ // Decompression didn't complete
+ p->msg = "premature end of input";
+ // fall-through
+ default:
+ err = -1;
+ break;
+ }
+
+ inflateEnd(&stream);
+
+ return err;
+}
+
+//
+// Exported interfaces
+//
+_decompress_fun_init* _dc_init = gzip_init;
+_decompress_fun_inflate* _dc_inflate = gzip_inflate;
+_decompress_fun_close* _dc_close = gzip_close;
+#endif // CYGPKG_COMPRESS_ZLIB
diff --git a/ecos/packages/redboot/current/src/dump.c b/ecos/packages/redboot/current/src/dump.c
new file mode 100644
index 0000000000..6c6fca1aa3
--- /dev/null
+++ b/ecos/packages/redboot/current/src/dump.c
@@ -0,0 +1,158 @@
+//==========================================================================
+//
+// dump.c
+//
+// RedBoot dump support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2002-08-06
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+
+RedBoot_cmd("dump",
+ "Display (hex dump) a range of memory",
+ "-b <location> [-l <length>] [-s] [-1|-2|-4]",
+ do_dump
+ );
+RedBoot_cmd("x",
+ "Display (hex dump) a range of memory",
+ "-b <location> [-l <length>] [-s] [-1|-2|-4]",
+ do_x
+ );
+
+void
+do_dump(int argc, char *argv[])
+{
+ struct option_info opts[6];
+ unsigned long base, len;
+ bool base_set, len_set;
+ static unsigned long _base, _len;
+ static char _size = 1;
+ bool srec_dump, set_32bit, set_16bit, set_8bit;
+ int i, n, off, cksum;
+ cyg_uint8 ch;
+
+ init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&base, (bool *)&base_set, "base address");
+ init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&len, (bool *)&len_set, "length");
+ init_opts(&opts[2], 's', false, OPTION_ARG_TYPE_FLG,
+ (void *)&srec_dump, 0, "dump data using Morotola S-records");
+ init_opts(&opts[3], '4', false, OPTION_ARG_TYPE_FLG,
+ (void *)&set_32bit, (bool *)0, "dump 32 bit units");
+ init_opts(&opts[4], '2', false, OPTION_ARG_TYPE_FLG,
+ (void *)&set_16bit, (bool *)0, "dump 16 bit units");
+ init_opts(&opts[5], '1', false, OPTION_ARG_TYPE_FLG,
+ (void *)&set_8bit, (bool *)0, "dump 8 bit units");
+ if (!scan_opts(argc, argv, 1, opts, 6, 0, 0, "")) {
+ return;
+ }
+ if (!base_set) {
+ if (_base == 0) {
+ diag_printf("Dump what [location]?\n");
+ return;
+ }
+ base = _base;
+ if (!len_set) {
+ len = _len;
+ len_set = true;
+ }
+ }
+
+ if (set_32bit) {
+ _size = 4;
+ } else if (set_16bit) {
+ _size = 2;
+ } else if (set_8bit) {
+ _size = 1;
+ }
+
+ if (!len_set) {
+ len = 32;
+ }
+ if (srec_dump) {
+ off = 0;
+ while (off < len) {
+ n = (len > 16) ? 16 : len;
+ cksum = n+5;
+ diag_printf("S3%02X%08lX", n+5, off+base);
+ for (i = 0; i < 4; i++) {
+ cksum += (((base+off)>>(i*8)) & 0xFF);
+ }
+ for (i = 0; i < n; i++) {
+ ch = *(cyg_uint8 *)(base+off+i);
+ diag_printf("%02X", ch);
+ cksum += ch;
+ }
+ diag_printf("%02X\n", ~cksum & 0xFF);
+ off += n;
+ }
+ } else {
+ switch( _size ) {
+ case 1:
+ diag_dump_buf((void *)base, len);
+ break;
+ case 2:
+ diag_dump_buf_16bit((void *)base, len);
+ break;
+ case 4:
+ diag_dump_buf_32bit((void *)base, len);
+ break;
+ }
+ }
+ _base = base + len;
+ _len = len;
+}
+
+// Simple alias for the dump command
+void
+do_x(int argc, char *argv[])
+{
+ do_dump(argc, argv);
+}
diff --git a/ecos/packages/redboot/current/src/fconfig.c b/ecos/packages/redboot/current/src/fconfig.c
new file mode 100644
index 0000000000..92d85e6cc5
--- /dev/null
+++ b/ecos/packages/redboot/current/src/fconfig.c
@@ -0,0 +1,1194 @@
+//==========================================================================
+//
+// fconfig.c
+//
+// RedBoot - persistent data storage support (FLASH or EEPROM)
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas, tkoeller
+// Date: 2000-07-28
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <cyg/io/flash.h>
+#ifdef CYGOPT_REDBOOT_FIS
+#include <fis.h>
+#endif
+
+#ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
+// Note horrid intertwining of functions, to save precious FLASH
+externC void fis_read_directory(void);
+externC void fis_update_directory(void);
+#endif
+
+#ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_EEPROM
+externC void write_eeprom(void *buf, int len);
+externC void read_eeprom(void *buf, int len);
+#endif
+
+#ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
+externC bool cyg_plf_redboot_esa_validate(unsigned char *val);
+#endif
+
+#ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
+externC bool do_flash_init(void);
+externC int flash_read(void *flash_base, void *ram_base, int len, void **err_address);
+#endif
+
+// Round a quantity up
+#define _rup(n,s) ((((n)+(s-1))/s)*s)
+
+#include <flash_config.h>
+
+// Configuration data, saved in FLASH, used to set/update RedBoot
+// normal "configuration" data items.
+struct _config *config, *backup_config;
+
+// Local data used by these routines
+#ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
+extern void *flash_start, *flash_end;
+extern int flash_block_size, flash_num_blocks;
+extern int __flash_init;
+#ifdef CYGOPT_REDBOOT_FIS
+extern void *fis_work_block;
+extern void *fis_addr;
+extern int fisdir_size; // Size of FIS directory.
+#endif
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
+static struct _config *readonly_config;
+#endif
+void *cfg_base; // Location in Flash of config data
+int cfg_size; // Length of config data - rounded to Flash block size
+#endif // FLASH MEDIA
+
+// Prototypes for local functions
+static unsigned char *flash_lookup_config(char *key);
+
+static bool config_ok;
+
+#define CONFIG_KEY1 0x0BADFACE
+#define CONFIG_KEY2 0xDEADDEAD
+
+#define CONFIG_DONE 0
+#define CONFIG_ABORT -1
+#define CONFIG_CHANGED 1
+#define CONFIG_OK 2
+#define CONFIG_BACK 3
+#define CONFIG_BAD 4
+
+// Note: the following options are related. If 'boot_script' is false, then
+// the other values are used in the configuration. Because of the way
+// that configuration tables are generated, they should have names which
+// are related. The configuration options will show up lexicographically
+// ordered, thus the peculiar naming.
+RedBoot_config_option("Run script at boot",
+ boot_script,
+ ALWAYS_ENABLED, true,
+ CONFIG_BOOL,
+ false
+ );
+RedBoot_config_option("Boot script",
+ boot_script_data,
+ "boot_script", true,
+ CONFIG_SCRIPT,
+ ""
+ );
+// Some preprocessor magic for building the [constant] prompt string
+#define __cat(s1,c2,s3) s1 #c2 s3
+#define _cat(s1,c2,s3) __cat(s1,c2,s3)
+RedBoot_config_option(_cat("Boot script timeout (",
+ CYGNUM_REDBOOT_BOOT_SCRIPT_TIMEOUT_RESOLUTION,
+ "ms resolution)"),
+ boot_script_timeout,
+ "boot_script", true,
+ CONFIG_INT,
+ 0
+ );
+#undef __cat
+#undef _cat
+
+#ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
+RedBoot_config_option("Console baud rate",
+ console_baud_rate,
+ ALWAYS_ENABLED, true,
+ CONFIG_INT,
+ CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD
+ );
+#endif
+
+CYG_HAL_TABLE_BEGIN( __CONFIG_options_TAB__, RedBoot_config_options);
+CYG_HAL_TABLE_END( __CONFIG_options_TAB_END__, RedBoot_config_options);
+
+extern struct config_option __CONFIG_options_TAB__[], __CONFIG_options_TAB_END__[];
+
+//
+// Layout of config data
+// Each data item is variable length, with the name, type and dependencies
+// encoded into the object.
+// offset contents
+// 0 data type
+// 1 length of name (N)
+// 2 enable sense
+// 3 length of enable key (M)
+// 4 key name
+// N+4 enable key
+// M+N+4 data value
+//
+
+#define CONFIG_OBJECT_TYPE(dp) (dp)[0]
+#define CONFIG_OBJECT_KEYLEN(dp) (dp)[1]
+#define CONFIG_OBJECT_ENABLE_SENSE(dp) (dp)[2]
+#define CONFIG_OBJECT_ENABLE_KEYLEN(dp) (dp)[3]
+#define CONFIG_OBJECT_KEY(dp) ((dp)+4)
+#define CONFIG_OBJECT_ENABLE_KEY(dp) ((dp)+4+CONFIG_OBJECT_KEYLEN(dp))
+#define CONFIG_OBJECT_VALUE(dp) ((dp)+4+CONFIG_OBJECT_KEYLEN(dp)+CONFIG_OBJECT_ENABLE_KEYLEN(dp))
+
+#define LIST_OPT_LIST_ONLY (1)
+#define LIST_OPT_NICKNAMES (2)
+#define LIST_OPT_FULLNAMES (4)
+#define LIST_OPT_DUMBTERM (8)
+
+static void config_init(void);
+static int config_length(int type);
+
+// Change endianness of config data
+void
+conf_endian_fixup(void *ptr)
+{
+#ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
+ struct _config *p = (struct _config *)ptr;
+ unsigned char *dp = p->config_data;
+ void *val_ptr;
+ int len;
+ cyg_uint16 u16;
+ cyg_uint32 u32;
+
+ p->len = CYG_SWAP32(p->len);
+ p->key1 = CYG_SWAP32(p->key1);
+ p->key2 = CYG_SWAP32(p->key2);
+ p->cksum = CYG_SWAP32(p->cksum);
+
+ while (dp < &p->config_data[sizeof(config->config_data)]) {
+ len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
+ config_length(CONFIG_OBJECT_TYPE(dp));
+ val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
+
+ switch (CONFIG_OBJECT_TYPE(dp)) {
+ // Note: the data may be unaligned in the configuration data
+ case CONFIG_BOOL:
+ if (sizeof(bool) == 2) {
+ memcpy(&u16, val_ptr, 2);
+ u16 = CYG_SWAP16(u16);
+ memcpy(val_ptr, &u16, 2);
+ } else if (sizeof(bool) == 4) {
+ memcpy(&u32, val_ptr, 4);
+ u32 = CYG_SWAP32(u32);
+ memcpy(val_ptr, &u32, 4);
+ }
+ break;
+ case CONFIG_INT:
+ if (sizeof(unsigned long) == 2) {
+ memcpy(&u16, val_ptr, 2);
+ u16 = CYG_SWAP16(u16);
+ memcpy(val_ptr, &u16, 2);
+ } else if (sizeof(unsigned long) == 4) {
+ memcpy(&u32, val_ptr, 4);
+ u32 = CYG_SWAP32(u32);
+ memcpy(val_ptr, &u32, 4);
+ }
+ break;
+ }
+
+ dp += len;
+ }
+#endif
+}
+
+static int
+get_config(unsigned char *dp, char *title, int list_opt, char *newvalue )
+{
+ char line[256], hold_line[256], *sp, *lp;
+ int ret;
+ bool hold_bool_val, new_bool_val, enable;
+ unsigned long hold_int_val, new_int_val;
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ in_addr_t hold_ip_val, new_ip_val;
+ enet_addr_t hold_esa_val;
+ int esa_ptr;
+ char *esp;
+#endif
+ void *val_ptr;
+ int type, script_len;
+
+ if (CONFIG_OBJECT_ENABLE_KEYLEN(dp)) {
+ flash_get_config(CONFIG_OBJECT_ENABLE_KEY(dp), &enable, CONFIG_BOOL);
+ if (((bool)CONFIG_OBJECT_ENABLE_SENSE(dp) && !enable) ||
+ (!(bool)CONFIG_OBJECT_ENABLE_SENSE(dp) && enable)) {
+ return CONFIG_OK; // Disabled field
+ }
+ }
+ lp = line; *lp = '\0';
+ val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
+ if (LIST_OPT_NICKNAMES & list_opt)
+ diag_printf("%s: ", CONFIG_OBJECT_KEY(dp));
+ if (LIST_OPT_FULLNAMES & list_opt) {
+ if (title != (char *)NULL) {
+ diag_printf("%s: ", title);
+ } else {
+ diag_printf("%s: ", CONFIG_OBJECT_KEY(dp));
+ }
+ }
+ switch (type = CONFIG_OBJECT_TYPE(dp)) {
+ case CONFIG_BOOL:
+ memcpy(&hold_bool_val, val_ptr, sizeof(bool));
+ lp += diag_sprintf(lp, "%s", hold_bool_val ? "true" : "false");
+ break;
+ case CONFIG_INT:
+ memcpy(&hold_int_val, val_ptr, sizeof(unsigned long));
+ lp += diag_sprintf(lp, "%ld", hold_int_val);
+ break;
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ case CONFIG_IP:
+ lp += diag_sprintf(lp, "%s", inet_ntoa((in_addr_t *)val_ptr));
+ if (0 == strcmp("0.0.0.0", line) && !(LIST_OPT_LIST_ONLY & list_opt)) {
+ // then we have a deeply unhelpful starting text - kill it off
+ // (unless we are just listing all values)
+ lp = line; *lp = '\0';
+ }
+ break;
+ case CONFIG_ESA:
+ for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) {
+ lp += diag_sprintf(lp, "0x%02X", ((unsigned char *)val_ptr)[esa_ptr]);
+ if (esa_ptr < (sizeof(enet_addr_t)-1)) lp += diag_sprintf(lp, ":");
+ }
+ break;
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ case CONFIG_NETPORT:
+ lp += diag_sprintf(lp, "%s", (unsigned char *)val_ptr);
+ break;
+#endif
+#endif
+ case CONFIG_STRING:
+ lp += diag_sprintf(lp, "%s", (unsigned char *)val_ptr);
+ break;
+ case CONFIG_SCRIPT:
+ diag_printf("\n");
+ sp = lp = (unsigned char *)val_ptr;
+ while (*sp) {
+ while (*lp != '\n') lp++;
+ *lp = '\0';
+ diag_printf(".. %s\n", sp);
+ *lp++ = '\n';
+ sp = lp;
+ }
+ break;
+ }
+ if (LIST_OPT_LIST_ONLY & list_opt) {
+ diag_printf("%s\n", line);
+ return CONFIG_OK;
+ }
+ if (type != CONFIG_SCRIPT) {
+ if (NULL != newvalue) {
+ ret = strlen(newvalue);
+ if (ret > sizeof(line))
+ return CONFIG_BAD;
+ strcpy(hold_line, line); // Hold the old value for comparison
+ strcpy(line, newvalue);
+ diag_printf("Setting to %s\n", newvalue);
+ } else {
+ // read from terminal
+ strcpy(hold_line, line);
+ if (LIST_OPT_DUMBTERM & list_opt) {
+ diag_printf( (CONFIG_STRING == type ?
+ "%s > " :
+ "%s ? " ), line);
+ *line = '\0';
+ }
+ ret = _rb_gets_preloaded(line, sizeof(line), 0);
+ }
+ if (ret < 0) return CONFIG_ABORT;
+ // empty input - leave value untouched (else DNS goes away for a
+ // minute to try to look it up) but we must accept empty value for strings.
+ if (0 == line[0] && CONFIG_STRING != type) return CONFIG_OK;
+ if (strcmp(line, hold_line) == 0) return CONFIG_OK; // Just a CR - leave value untouched
+ lp = &line[strlen(line)-1];
+ if (*lp == '.') return CONFIG_DONE;
+ if (*lp == '^') return CONFIG_BACK;
+ }
+ switch (type) {
+ case CONFIG_BOOL:
+ memcpy(&hold_bool_val, val_ptr, sizeof(bool));
+ if (!parse_bool(line, &new_bool_val)) {
+ return CONFIG_BAD;
+ }
+ if (hold_bool_val != new_bool_val) {
+ memcpy(val_ptr, &new_bool_val, sizeof(bool));
+ return CONFIG_CHANGED;
+ } else {
+ return CONFIG_OK;
+ }
+ break;
+ case CONFIG_INT:
+ memcpy(&hold_int_val, val_ptr, sizeof(unsigned long));
+ if (!parse_num(line, &new_int_val, 0, 0)) {
+ return CONFIG_BAD;
+ }
+ if (hold_int_val != new_int_val) {
+ memcpy(val_ptr, &new_int_val, sizeof(unsigned long));
+ return CONFIG_CHANGED;
+ } else {
+ return CONFIG_OK;
+ }
+ break;
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ case CONFIG_IP:
+ memcpy(&hold_ip_val.s_addr, &((in_addr_t *)val_ptr)->s_addr, sizeof(in_addr_t));
+ if (!_gethostbyname(line, &new_ip_val)) {
+ return CONFIG_BAD;
+ }
+ if (hold_ip_val.s_addr != new_ip_val.s_addr) {
+ memcpy(val_ptr, &new_ip_val, sizeof(in_addr_t));
+ return CONFIG_CHANGED;
+ } else {
+ return CONFIG_OK;
+ }
+ break;
+ case CONFIG_ESA:
+ memcpy(&hold_esa_val, val_ptr, sizeof(enet_addr_t));
+ esp = line;
+ for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) {
+ unsigned long esa_byte;
+ if (!parse_num(esp, &esa_byte, &esp, ":")) {
+ memcpy(val_ptr, &hold_esa_val, sizeof(enet_addr_t));
+ return CONFIG_BAD;
+ }
+ ((unsigned char *)val_ptr)[esa_ptr] = esa_byte;
+ }
+#ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
+ if (!cyg_plf_redboot_esa_validate(val_ptr)) {
+ memcpy(val_ptr, &hold_esa_val, sizeof(enet_addr_t));
+ return CONFIG_BAD;
+ }
+#endif
+ return CONFIG_CHANGED;
+ break;
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ case CONFIG_NETPORT:
+ if (strlen(line) >= MAX_STRING_LENGTH || net_devindex(line) < 0) {
+ int index;
+ const char *name;
+ diag_printf("Sorry, Port name must be one of:\n");
+ for (index = 0; (name = net_devname(index)) != NULL; index++)
+ diag_printf(" %s\n", name);
+ return CONFIG_BAD;
+ }
+ strcpy((unsigned char *)val_ptr, line);
+ break;
+#endif
+#endif
+ case CONFIG_SCRIPT:
+ // Assume it always changes
+ sp = (unsigned char *)val_ptr;
+ script_len = 0;
+ diag_printf("Enter script, terminate with empty line\n");
+ while (true) {
+ *sp = '\0';
+ diag_printf(">> ");
+ ret = _rb_gets(line, sizeof(line), 0);
+ if (ret < 0) return CONFIG_ABORT;
+ if (strlen(line) == 0) break;
+ script_len += strlen(line) + 1;
+ if (script_len > config_length(CONFIG_SCRIPT)) {
+ diag_printf("script longer than %d not allowed!\n",
+ config_length(CONFIG_SCRIPT));
+ return CONFIG_ABORT;
+ }
+ lp = line;
+ while (*lp) {
+ *sp++ = *lp++;
+ }
+ *sp++ = '\n';
+ }
+ break;
+ case CONFIG_STRING:
+ if (strlen(line) >= MAX_STRING_LENGTH) {
+ diag_printf("Sorry, value is too long\n");
+ return CONFIG_BAD;
+ }
+ strcpy((unsigned char *)val_ptr, line);
+ break;
+ }
+ return CONFIG_CHANGED;
+}
+
+//
+// Manage configuration information with the FLASH
+//
+
+static int
+config_length(int type)
+{
+ switch (type) {
+ case CONFIG_BOOL:
+ return sizeof(bool);
+ case CONFIG_INT:
+ return sizeof(unsigned long);
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ case CONFIG_IP:
+ return sizeof(in_addr_t);
+ case CONFIG_ESA:
+ // Would like this to be sizeof(enet_addr_t), but that causes much
+ // pain since it fouls the alignment of data which follows.
+ return 8;
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ case CONFIG_NETPORT:
+ return MAX_STRING_LENGTH;
+#endif
+#endif
+ case CONFIG_STRING:
+ return MAX_STRING_LENGTH;
+ case CONFIG_SCRIPT:
+ return MAX_SCRIPT_LENGTH;
+ default:
+ return 0;
+ }
+}
+
+static cmd_fun do_flash_config;
+RedBoot_cmd("fconfig",
+ "Manage configuration kept in FLASH memory",
+ "[-i] [-l] [-n] [-f] [-d] | [-d] nickname [value]",
+ do_flash_config
+ );
+
+static void
+do_flash_config(int argc, char *argv[])
+{
+ bool need_update = false;
+ struct config_option *optend = __CONFIG_options_TAB_END__;
+ struct config_option *opt = __CONFIG_options_TAB__;
+ struct option_info opts[5];
+ bool list_only;
+ bool nicknames;
+ bool fullnames;
+ bool dumbterminal;
+ int list_opt = 0;
+ unsigned char *dp;
+ int len, ret;
+ char *title;
+ char *onlyone = NULL;
+ char *onevalue = NULL;
+ bool doneone = false;
+ bool init = false;
+
+#ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
+ if (!__flash_init) {
+ diag_printf("Sorry, no FLASH memory is available\n");
+ return;
+ }
+#endif
+ memcpy(backup_config, config, sizeof(struct _config));
+ script = (unsigned char *)0;
+
+ init_opts(&opts[0], 'l', false, OPTION_ARG_TYPE_FLG,
+ (void *)&list_only, (bool *)0, "list configuration only");
+ init_opts(&opts[1], 'n', false, OPTION_ARG_TYPE_FLG,
+ (void *)&nicknames, (bool *)0, "show nicknames");
+ init_opts(&opts[2], 'f', false, OPTION_ARG_TYPE_FLG,
+ (void *)&fullnames, (bool *)0, "show full names");
+ init_opts(&opts[3], 'i', false, OPTION_ARG_TYPE_FLG,
+ (void *)&init, (bool *)0, "initialize configuration database");
+ init_opts(&opts[4], 'd', false, OPTION_ARG_TYPE_FLG,
+ (void *)&dumbterminal, (bool *)0, "dumb terminal: no clever edits");
+
+ // First look to see if we are setting or getting a single option
+ // by just quoting its nickname
+ if ( (2 == argc && '-' != argv[1][0]) ||
+ (3 == argc && '-' != argv[1][0] && '-' != argv[2][0])) {
+ // then the command was "fconfig foo [value]"
+ onlyone = argv[1];
+ onevalue = (3 == argc) ? argv[2] : NULL;
+ list_opt = LIST_OPT_NICKNAMES;
+ }
+ // Next see if we are setting or getting a single option with a dumb
+ // terminal invoked, ie. no line editing.
+ else if (3 == argc &&
+ '-' == argv[1][0] && 'd' == argv[1][1] && 0 == argv[1][2] &&
+ '-' != argv[2][0]) {
+ // then the command was "fconfig -d foo"
+ onlyone = argv[2];
+ onevalue = NULL;
+ list_opt = LIST_OPT_NICKNAMES | LIST_OPT_DUMBTERM;
+ }
+ else {
+ if (!scan_opts(argc, argv, 1, opts, 5, 0, 0, ""))
+ return;
+ list_opt |= list_only ? LIST_OPT_LIST_ONLY : 0;
+ list_opt |= nicknames ? LIST_OPT_NICKNAMES : LIST_OPT_FULLNAMES;
+ list_opt |= fullnames ? LIST_OPT_FULLNAMES : 0;
+ list_opt |= dumbterminal ? LIST_OPT_DUMBTERM : 0;
+ }
+
+ if (init && verify_action("Initialize non-volatile configuration")) {
+ config_init();
+ need_update = true;
+ }
+
+ dp = &config->config_data[0];
+ while (dp < &config->config_data[sizeof(config->config_data)]) {
+ if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) {
+ break;
+ }
+ len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
+ config_length(CONFIG_OBJECT_TYPE(dp));
+ // Provide a title for well known [i.e. builtin] objects
+ title = (char *)NULL;
+ opt = __CONFIG_options_TAB__;
+ while (opt != optend) {
+ if (strcmp(opt->key, CONFIG_OBJECT_KEY(dp)) == 0) {
+ title = opt->title;
+ break;
+ }
+ opt++;
+ }
+ if ( onlyone && 0 != strcmp(CONFIG_OBJECT_KEY(dp), onlyone) )
+ ret = CONFIG_OK; // skip this entry
+ else {
+ doneone = true;
+ ret = get_config(dp, title, list_opt, onevalue); // do this opt
+ }
+ switch (ret) {
+ case CONFIG_DONE:
+ goto done;
+ case CONFIG_ABORT:
+ memcpy(config, backup_config, sizeof(struct _config));
+ return;
+ case CONFIG_CHANGED:
+ need_update = true;
+ case CONFIG_OK:
+ dp += len;
+ break;
+ case CONFIG_BACK:
+ dp = &config->config_data[0];
+ continue;
+ case CONFIG_BAD:
+ // Nothing - make him do it again
+ diag_printf ("** invalid entry\n");
+ onevalue = NULL; // request a good value be typed in - or abort/whatever
+ }
+ }
+
+ done:
+ if (NULL != onlyone && !doneone) {
+#ifdef CYGSEM_REDBOOT_ALLOW_DYNAMIC_FLASH_CONFIG_DATA
+ if (verify_action("** entry '%s' not found - add", onlyone)) {
+ struct config_option opt;
+ diag_printf("Trying to add value\n");
+ }
+#else
+ diag_printf("** entry '%s' not found\n", onlyone);
+#endif
+ }
+ if (!need_update)
+ return;
+ flash_write_config(true);
+}
+
+
+#ifdef CYGSEM_REDBOOT_FLASH_ALIASES
+static cmd_fun do_alias;
+RedBoot_cmd("alias",
+ "Manage aliases kept in FLASH memory",
+ "name [value]",
+ do_alias
+ );
+
+static void
+make_alias(char *alias, char *name)
+{
+ diag_sprintf(alias, "alias/%s", name);
+}
+
+static void
+do_alias(int argc, char *argv[])
+{
+ char name[80];
+ char *val;
+ struct config_option opt;
+
+ switch (argc) {
+ case 2:
+ make_alias(name, argv[1]);
+ if (flash_get_config(name, &val, CONFIG_STRING)) {
+ diag_printf("'%s' = '%s'\n", argv[1], val);
+ } else {
+ diag_printf("'%s' not found\n", argv[1]);
+ }
+ break;
+ case 3:
+ if (strlen(argv[2]) >= MAX_STRING_LENGTH) {
+ diag_printf("Sorry, value is too long\n");
+ break;
+ }
+ make_alias(name, argv[1]);
+ opt.type = CONFIG_STRING;
+ opt.enable = (char *)0;
+ opt.enable_sense = 1;
+ opt.key = name;
+ opt.dflt = (CYG_ADDRESS)argv[2];
+ flash_add_config(&opt, true);
+ break;
+ default:
+ diag_printf("usage: alias name [value]\n");
+ }
+}
+
+// Lookup an alias. First try plain string aliases. If that fails try
+// other types so allowing access to all configured values. This allows
+// for alias (macro) expansion of normal 'fconfig' data, such as the
+// board IP address.
+char *
+flash_lookup_alias(char *alias, char *alias_buf)
+{
+ char name[80];
+ char *val;
+ unsigned char * dp;
+ void *val_ptr;
+ int type;
+ bool hold_bool_val;
+ long hold_long_val;
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ int esa_ptr;
+#endif
+
+ make_alias(name, alias);
+ if (flash_get_config(name, &val, CONFIG_STRING)) {
+ return val;
+ } else {
+ dp = flash_lookup_config(alias);
+ if (dp) {
+ val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
+ switch (type = CONFIG_OBJECT_TYPE(dp)) {
+ case CONFIG_BOOL:
+ memcpy(&hold_bool_val, val_ptr, sizeof(bool));
+ diag_sprintf(alias_buf, "%s", hold_bool_val ? "true" : "false");
+ break;
+ case CONFIG_INT:
+ memcpy(&hold_long_val, val_ptr, sizeof(unsigned long));
+ diag_sprintf(alias_buf,"%ld", hold_long_val);
+ break;
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ case CONFIG_IP:
+ diag_sprintf(alias_buf,"%s", inet_ntoa((in_addr_t *)val_ptr));
+ break;
+ case CONFIG_ESA:
+ for (esa_ptr = 0; esa_ptr < sizeof(enet_addr_t); esa_ptr++) {
+ diag_sprintf(alias_buf+(3*esa_ptr), "0x%02X", ((unsigned char *)val_ptr)[esa_ptr]);
+ if (esa_ptr < (sizeof(enet_addr_t)-1)) diag_printf(":");
+ }
+ break;
+#endif
+ case CONFIG_SCRIPT:
+ return (char *) val_ptr;
+ break;
+ default:
+ return (char *)NULL;
+ }
+ return alias_buf;
+ }
+ return (char *)NULL;
+ }
+}
+
+#endif // CYGSEM_REDBOOT_FLASH_ALIASES
+
+cyg_uint32
+flash_crc(struct _config *conf)
+{
+ cyg_uint32 crc;
+#ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
+ int swabbed = 0;
+
+ if (conf->key1 == CONFIG_KEY1 && conf->key2 == CONFIG_KEY2) {
+ swabbed = 1;
+ conf_endian_fixup(conf);
+ }
+#endif
+
+ crc = cyg_crc32((unsigned char *)conf, sizeof(*conf)-sizeof(conf->cksum));
+
+#ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
+ if (swabbed)
+ conf_endian_fixup(conf);
+#endif
+ return crc;
+}
+
+//
+// Write the in-memory copy of the configuration data to the flash device.
+//
+void
+flash_write_config(bool prompt)
+{
+#if defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
+#if !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG)
+ void *err_addr;
+ int stat;
+#endif
+#endif
+
+ config->len = sizeof(struct _config);
+ config->key1 = CONFIG_KEY1;
+ config->key2 = CONFIG_KEY2;
+ config->cksum = flash_crc(config);
+ if (!prompt || verify_action("Update RedBoot non-volatile configuration")) {
+#ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
+#ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
+ fis_read_directory();
+ fis_update_directory();
+#else
+#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
+ // Insure [quietly] that the config page is unlocked before trying to update
+ flash_unlock((void *)cfg_base, cfg_size, (void **)&err_addr);
+#endif
+ if ((stat = flash_erase(cfg_base, cfg_size, (void **)&err_addr)) != 0) {
+ diag_printf(" initialization failed at %p: %s\n", err_addr, flash_errmsg(stat));
+ } else {
+ conf_endian_fixup(config);
+ if ((stat = FLASH_PROGRAM(cfg_base, config, sizeof(struct _config), (void **)&err_addr)) != 0) {
+ diag_printf("Error writing config data at %p: %s\n",
+ err_addr, flash_errmsg(stat));
+ }
+ conf_endian_fixup(config);
+ }
+#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
+ // Insure [quietly] that the config data is locked after the update
+ flash_lock((void *)cfg_base, cfg_size, (void **)&err_addr);
+#endif
+#endif // CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
+#else // CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
+ write_eeprom(config, sizeof(struct _config)); // into 'config'
+#endif
+ }
+}
+
+//
+// Find the configuration entry for a particular key
+//
+static unsigned char *
+flash_lookup_config(char *key)
+{
+ unsigned char *dp;
+ int len;
+
+ if (!config_ok) return (unsigned char *)NULL;
+
+ dp = &config->config_data[0];
+ while (dp < &config->config_data[sizeof(config->config_data)]) {
+ len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
+ config_length(CONFIG_OBJECT_TYPE(dp));
+ if (strcmp(key, CONFIG_OBJECT_KEY(dp)) == 0) {
+ return dp;
+ }
+ dp += len;
+ }
+// diag_printf("Can't find config data for '%s'\n", key);
+ return false;
+}
+
+//
+// Enumerate the keys from the configuration
+//
+bool
+flash_next_key(char *key, int keylen, int *type, int *offset)
+{
+ unsigned char *dp;
+ int len;
+
+ if (!config_ok) return false;
+ if ((*offset < 0) || (*offset >= MAX_CONFIG_DATA)) return false;
+
+ dp = &config->config_data[*offset];
+ if ((*type = CONFIG_OBJECT_TYPE(dp)) == CONFIG_EMPTY) return false;
+ if ((len = CONFIG_OBJECT_KEYLEN(dp)) > keylen) return false;
+ memcpy(key, CONFIG_OBJECT_KEY(dp), len);
+ *offset += 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
+ config_length(CONFIG_OBJECT_TYPE(dp));
+ return true;
+}
+
+//
+// Retrieve a data object from the data base (in memory copy)
+//
+bool
+flash_get_config(char *key, void *val, int type)
+{
+ unsigned char *dp;
+ void *val_ptr;
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
+ struct _config *save_config = 0;
+ bool res;
+#endif
+
+ if (!config_ok) return false;
+
+ if ((dp = flash_lookup_config(key)) != (unsigned char *)NULL) {
+ if (CONFIG_OBJECT_TYPE(dp) == type) {
+ val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
+ switch (type) {
+ // Note: the data may be unaligned in the configuration data
+ case CONFIG_BOOL:
+ memcpy(val, val_ptr, sizeof(bool));
+ break;
+ case CONFIG_INT:
+ memcpy(val, val_ptr, sizeof(unsigned long));
+ break;
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ case CONFIG_IP:
+ memcpy(val, val_ptr, sizeof(in_addr_t));
+ break;
+ case CONFIG_ESA:
+ memcpy(val, val_ptr, sizeof(enet_addr_t));
+ break;
+#endif
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ case CONFIG_NETPORT:
+#endif
+ case CONFIG_STRING:
+ case CONFIG_SCRIPT:
+ // Just return a pointer to the script/line
+ *(unsigned char **)val = (unsigned char *)val_ptr;
+ break;
+ }
+ } else {
+ diag_printf("Request for config value '%s' - wrong type\n", key);
+ }
+ return true;
+ }
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
+ // Did not find key. Is configuration data valid?
+ // Check to see if the config data is valid, if not, revert to
+ // readonly mode, by setting config to readonly_config. We
+ // will set it back before we leave this function.
+ if ( (config != readonly_config) && ((flash_crc(config) != config->cksum) ||
+ (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2))) {
+ save_config = config;
+ config = readonly_config;
+ if ((flash_crc(config) != config->cksum) ||
+ (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2)) {
+ diag_printf("FLASH configuration checksum error or invalid key\n");
+ config = save_config;
+ return false;
+ }
+ else{
+ diag_printf("Getting config information in READONLY mode\n");
+ res = flash_get_config(key, val, type);
+ config = save_config;
+ return res;
+ }
+ }
+#endif
+ return false;
+}
+
+//
+// Update a data object in the data base (in memory copy & backing store)
+//
+bool
+flash_set_config(char *key, void *val, int type)
+{
+ unsigned char *dp;
+ void *val_ptr;
+
+ if (!config_ok) return false;
+
+ if ((dp = flash_lookup_config(key)) != (unsigned char *)NULL) {
+ if (CONFIG_OBJECT_TYPE(dp) == type) {
+ val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
+ switch (type) {
+ // Note: the data may be unaligned in the configuration data
+ case CONFIG_BOOL:
+ memcpy(val_ptr, val, sizeof(bool));
+ break;
+ case CONFIG_INT:
+ memcpy(val_ptr, val, sizeof(unsigned long));
+ break;
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ case CONFIG_IP:
+ memcpy(val_ptr, val, sizeof(in_addr_t));
+ break;
+ case CONFIG_ESA:
+ memcpy(val_ptr, val, sizeof(enet_addr_t));
+ break;
+#endif
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ case CONFIG_NETPORT:
+#endif
+ case CONFIG_STRING:
+ case CONFIG_SCRIPT:
+ memcpy(val_ptr, val, config_length(CONFIG_STRING));
+ break;
+ }
+ } else {
+ diag_printf("Can't set config value '%s' - wrong type\n", key);
+ return false;
+ }
+ flash_write_config(false);
+ return true;
+ }
+ return false;
+}
+
+//
+// Copy data into the config area
+//
+static void
+flash_config_insert_value(unsigned char *dp, struct config_option *opt)
+{
+ switch (opt->type) {
+ // Note: the data may be unaligned in the configuration data
+ case CONFIG_BOOL:
+ memcpy(dp, (void *)&opt->dflt, sizeof(bool));
+ break;
+ case CONFIG_INT:
+ memcpy(dp, (void *)&opt->dflt, sizeof(unsigned long));
+ break;
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ case CONFIG_IP:
+ memcpy(dp, (void *)&opt->dflt, sizeof(in_addr_t));
+ break;
+ case CONFIG_ESA:
+ memcpy(dp, (void *)opt->dflt, sizeof(enet_addr_t));
+ break;
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ case CONFIG_NETPORT:
+ // validate dflt and if not acceptable use first port
+ {
+ int index;
+ const char *name;
+ for (index = 0; (name = net_devname(index)) != NULL; index++)
+ if (!strcmp((char *)opt->dflt, name))
+ break;
+ if (name == NULL)
+ name = net_devname(0);
+ memcpy(dp, name, strlen(name) + 1);
+ }
+ break;
+#endif
+#endif
+ case CONFIG_STRING:
+ memcpy(dp, (void *)opt->dflt, config_length(CONFIG_STRING));
+ break;
+ case CONFIG_SCRIPT:
+ break;
+ }
+}
+
+//
+// Add a new option to the database
+//
+bool
+flash_add_config(struct config_option *opt, bool update)
+{
+ unsigned char *dp, *kp;
+ int len, elen, size;
+
+ // If data item is already present, just update it
+ // Note: only the data value can be thusly changed
+ if ((dp = flash_lookup_config(opt->key)) != (unsigned char *)NULL) {
+ flash_config_insert_value(CONFIG_OBJECT_VALUE(dp), opt);
+ if (update) {
+ flash_write_config(true);
+ }
+ return true;
+ }
+ // Add the data item
+ dp = &config->config_data[0];
+ size = 0;
+ while (size < sizeof(config->config_data)) {
+ if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) {
+ kp = opt->key;
+ len = strlen(kp) + 1;
+ size += len + 2 + 2 + config_length(opt->type);
+ if (opt->enable) {
+ elen = strlen(opt->enable) + 1;
+ size += elen;
+ } else {
+ elen = 0;
+ }
+ if (size > sizeof(config->config_data)) {
+ break;
+ }
+ CONFIG_OBJECT_TYPE(dp) = opt->type;
+ CONFIG_OBJECT_KEYLEN(dp) = len;
+ CONFIG_OBJECT_ENABLE_SENSE(dp) = opt->enable_sense;
+ CONFIG_OBJECT_ENABLE_KEYLEN(dp) = elen;
+ dp = CONFIG_OBJECT_KEY(dp);
+ while (*kp) *dp++ += *kp++;
+ *dp++ = '\0';
+ if (elen) {
+ kp = opt->enable;
+ while (*kp) *dp++ += *kp++;
+ *dp++ = '\0';
+ }
+ flash_config_insert_value(dp, opt);
+ if (update) {
+ flash_write_config(true);
+ }
+ return true;
+ } else {
+ len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
+ config_length(CONFIG_OBJECT_TYPE(dp));
+ dp += len;
+ size += len;
+ }
+ }
+ diag_printf("No space to add '%s'\n", opt->key);
+ return false;
+}
+
+//
+// Reset/initialize configuration data - used only when starting from scratch
+//
+static void
+config_init(void)
+{
+ // Well known option strings
+ struct config_option *optend = __CONFIG_options_TAB_END__;
+ struct config_option *opt = __CONFIG_options_TAB__;
+
+ memset(config, 0, sizeof(struct _config));
+ while (opt != optend) {
+ if (!flash_add_config(opt, false)) {
+ return;
+ }
+ opt++;
+ }
+ config_ok = true;
+}
+
+//
+// Attempt to get configuration information from the FLASH.
+// If available (i.e. good checksum, etc), initialize "known"
+// values for later use.
+//
+static void
+load_flash_config(void)
+{
+ bool use_boot_script;
+ unsigned char *cfg_temp = (unsigned char *)workspace_end;
+#ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
+ void *err_addr;
+#endif
+
+ config_ok = false;
+ script = (unsigned char *)0;
+ cfg_temp -= sizeof(struct _config); // Space for primary config data
+ config = (struct _config *)cfg_temp;
+ cfg_temp -= sizeof(struct _config); // Space for backup config data
+ backup_config = (struct _config *)cfg_temp;
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
+ cfg_temp -= sizeof(struct _config); // Space for readonly copy of config data
+ readonly_config = (struct _config *)cfg_temp;
+#endif
+ workspace_end = cfg_temp;
+#ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
+ if (!do_flash_init()) return;
+#ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
+ cfg_size = _rup(sizeof(struct _config), sizeof(struct fis_image_desc));
+ if ((fisdir_size-cfg_size) < (CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_COUNT *
+ CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_SIZE)) {
+ // Too bad this can't be checked at compile/build time
+ diag_printf("Sorry, FLASH config exceeds available space in FIS directory\n");
+ return;
+ }
+ cfg_base = (void *)(((CYG_ADDRESS)fis_addr + fisdir_size) - cfg_size);
+ fisdir_size -= cfg_size;
+#else
+ cfg_size = (flash_block_size > sizeof(struct _config)) ?
+ sizeof(struct _config) :
+ _rup(sizeof(struct _config), flash_block_size);
+ if (CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK < 0) {
+ cfg_base = (void *)((CYG_ADDRESS)flash_end + 1 -
+ _rup(_rup((-CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK*flash_block_size), cfg_size), flash_block_size));
+ } else {
+ cfg_base = (void *)((CYG_ADDRESS)flash_start +
+ _rup(_rup((CYGNUM_REDBOOT_FLASH_CONFIG_BLOCK*flash_block_size), cfg_size), flash_block_size));
+ }
+#endif
+ FLASH_READ(cfg_base, config, sizeof(struct _config), &err_addr);
+ conf_endian_fixup(config);
+#else
+ read_eeprom(config, sizeof(struct _config)); // into 'config'
+#endif
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG_READONLY_FALLBACK
+ memcpy(readonly_config, config, sizeof(struct _config));
+#endif
+ if ((flash_crc(config) != config->cksum) ||
+ (config->key1 != CONFIG_KEY1)|| (config->key2 != CONFIG_KEY2)) {
+ diag_printf("**Warning** FLASH configuration checksum error or invalid key\n");
+ diag_printf("Use 'fconfig -i' to [re]initialize database\n");
+ config_init();
+ return;
+ }
+ config_ok = true;
+ flash_get_config("boot_script", &use_boot_script, CONFIG_BOOL);
+ if (use_boot_script) {
+ flash_get_config("boot_script_data", &script, CONFIG_SCRIPT);
+ flash_get_config("boot_script_timeout", &script_timeout, CONFIG_INT);
+ }
+#ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
+ if (flash_get_config("console_baud_rate", &console_baud_rate, CONFIG_INT)) {
+ extern int set_console_baud_rate(int);
+ set_console_baud_rate(console_baud_rate);
+ }
+#endif
+}
+
+RedBoot_init(load_flash_config, RedBoot_INIT_SECOND);
+
+// EOF fconfig.c
diff --git a/ecos/packages/redboot/current/src/flash.c b/ecos/packages/redboot/current/src/flash.c
new file mode 100644
index 0000000000..bd548fc87e
--- /dev/null
+++ b/ecos/packages/redboot/current/src/flash.c
@@ -0,0 +1,1439 @@
+//==========================================================================
+//
+// flash.c
+//
+// RedBoot - FLASH memory support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
+// Copyright (C) 2003, 2004 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas, tkoeller
+// Date: 2000-07-28
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <cyg/io/flash.h>
+#include <fis.h>
+#include <sib.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
+// Note horrid intertwining of functions, to save precious FLASH
+extern void conf_endian_fixup(void *p);
+#endif
+
+// Round a quantity up
+#define _rup(n,s) ((((n)+(s-1))/s)*s)
+
+#ifdef CYGOPT_REDBOOT_FIS
+// Image management functions
+local_cmd_entry("init",
+ "Initialize FLASH Image System [FIS]",
+ "[-f]",
+ fis_init,
+ FIS_cmds
+ );
+#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
+# define FIS_LIST_OPTS "[-c] [-d]"
+#else
+# define FIS_LIST_OPTS "[-d]"
+#endif
+local_cmd_entry("list",
+ "Display contents of FLASH Image System [FIS]",
+ FIS_LIST_OPTS,
+ fis_list,
+ FIS_cmds
+ );
+local_cmd_entry("free",
+ "Display free [available] locations within FLASH Image System [FIS]",
+ "",
+ fis_free,
+ FIS_cmds
+ );
+local_cmd_entry("delete",
+ "Delete an image from FLASH Image System [FIS]",
+ "name",
+ fis_delete,
+ FIS_cmds
+ );
+
+static char fis_load_usage[] =
+#ifdef CYGPRI_REDBOOT_ZLIB_FLASH
+ "[-d] "
+#endif
+ "[-b <memory_load_address>] [-c] name";
+
+local_cmd_entry("load",
+ "Load image from FLASH Image System [FIS] into RAM",
+ fis_load_usage,
+ fis_load,
+ FIS_cmds
+ );
+local_cmd_entry("create",
+ "Create an image",
+ "-b <mem_base> -l <image_length> [-s <data_length>]\n"
+ " [-f <flash_addr>] [-e <entry_point>] [-r <ram_addr>] [-n] <name>",
+ fis_create,
+ FIS_cmds
+ );
+#endif
+
+// Raw flash access functions
+local_cmd_entry("erase",
+ "Erase FLASH contents",
+ "-f <flash_addr> -l <length>",
+ fis_erase,
+ FIS_cmds
+ );
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+local_cmd_entry("lock",
+ "LOCK FLASH contents",
+ "[-f <flash_addr> -l <length>] [name]",
+ fis_lock,
+ FIS_cmds
+ );
+local_cmd_entry("unlock",
+ "UNLOCK FLASH contents",
+ "[-f <flash_addr> -l <length>] [name]",
+ fis_unlock,
+ FIS_cmds
+ );
+#endif
+local_cmd_entry("write",
+ "Write raw data directly to FLASH",
+ "-f <flash_addr> -b <mem_base> -l <image_length>",
+ fis_write,
+ FIS_cmds
+ );
+
+// Define table boundaries
+CYG_HAL_TABLE_BEGIN( __FIS_cmds_TAB__, FIS_cmds);
+CYG_HAL_TABLE_END( __FIS_cmds_TAB_END__, FIS_cmds);
+
+extern struct cmd __FIS_cmds_TAB__[], __FIS_cmds_TAB_END__;
+
+// CLI function
+static cmd_fun do_fis;
+RedBoot_nested_cmd("fis",
+ "Manage FLASH images",
+ "{cmds}",
+ do_fis,
+ __FIS_cmds_TAB__, &__FIS_cmds_TAB_END__
+ );
+
+// Local data used by these routines
+void *flash_start, *flash_end;
+int flash_block_size, flash_num_blocks;
+#ifdef CYGOPT_REDBOOT_FIS
+void *fis_work_block;
+void *fis_addr;
+int fisdir_size; // Size of FIS directory.
+#endif
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+extern void *cfg_base; // Location in Flash of config data
+extern int cfg_size; // Length of config data - rounded to Flash block size
+extern struct _config *config;
+#endif
+
+static void
+fis_usage(char *why)
+{
+ diag_printf("*** invalid 'fis' command: %s\n", why);
+ cmd_usage(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__, "fis ");
+}
+
+static void
+_show_invalid_flash_address(CYG_ADDRESS flash_addr, int stat)
+{
+ diag_printf("Invalid FLASH address %p: %s\n", (void *)flash_addr, flash_errmsg(stat));
+ diag_printf(" valid range is %p-%p\n", (void *)flash_start, (void *)flash_end);
+}
+
+#ifdef CYGOPT_REDBOOT_FIS
+
+// fis_endian_fixup() is used to swap endianess if required.
+//
+static inline void fis_endian_fixup(void *addr)
+{
+#ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
+ struct fis_image_desc *p = addr;
+ int cnt = fisdir_size / sizeof(struct fis_image_desc);
+
+ while (cnt-- > 0) {
+ p->flash_base = CYG_SWAP32(p->flash_base);
+ p->mem_base = CYG_SWAP32(p->mem_base);
+ p->size = CYG_SWAP32(p->size);
+ p->entry_point = CYG_SWAP32(p->entry_point);
+ p->data_length = CYG_SWAP32(p->data_length);
+ p->desc_cksum = CYG_SWAP32(p->desc_cksum);
+ p->file_cksum = CYG_SWAP32(p->file_cksum);
+ p++;
+ }
+#endif
+}
+
+void
+fis_read_directory(void)
+{
+ void *err_addr;
+
+ FLASH_READ(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr);
+ fis_endian_fixup(fis_work_block);
+}
+
+struct fis_image_desc *
+fis_lookup(char *name, int *num)
+{
+ int i;
+ struct fis_image_desc *img;
+
+ fis_read_directory();
+
+ img = (struct fis_image_desc *)fis_work_block;
+ for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) {
+ if ((img->name[0] != (unsigned char)0xFF) &&
+ (strcasecmp(name, img->name) == 0)) {
+ if (num) *num = i;
+ return img;
+ }
+ }
+ return (struct fis_image_desc *)0;
+}
+
+void
+fis_update_directory(void)
+{
+ int stat;
+ void *err_addr;
+
+ fis_endian_fixup(fis_work_block);
+#ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
+ memcpy((char *)fis_work_block+fisdir_size, config, cfg_size);
+ conf_endian_fixup((char *)fis_work_block+fisdir_size);
+#endif
+#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
+ // Ensure [quietly] that the directory is unlocked before trying to update
+ flash_unlock((void *)fis_addr, flash_block_size, (void **)&err_addr);
+#endif
+ if ((stat = flash_erase(fis_addr, flash_block_size, (void **)&err_addr)) != 0) {
+ diag_printf("Error erasing FIS directory at %p: %s\n", err_addr, flash_errmsg(stat));
+ } else {
+ if ((stat = FLASH_PROGRAM(fis_addr, fis_work_block,
+ flash_block_size, (void **)&err_addr)) != 0) {
+ diag_printf("Error writing FIS directory at %p: %s\n",
+ err_addr, flash_errmsg(stat));
+ }
+ }
+#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
+ // Ensure [quietly] that the directory is locked after the update
+ flash_lock((void *)fis_addr, flash_block_size, (void **)&err_addr);
+#endif
+ fis_endian_fixup(fis_work_block);
+}
+
+static void
+fis_init(int argc, char *argv[])
+{
+ int stat;
+ struct fis_image_desc *img;
+ void *err_addr;
+ bool full_init = false;
+ struct option_info opts[1];
+ CYG_ADDRESS redboot_flash_start;
+ unsigned long redboot_image_size;
+
+ init_opts(&opts[0], 'f', false, OPTION_ARG_TYPE_FLG,
+ (void *)&full_init, (bool *)0, "full initialization, erases all of flash");
+ if (!scan_opts(argc, argv, 2, opts, 1, 0, 0, ""))
+ {
+ return;
+ }
+
+ if (!verify_action("About to initialize [format] FLASH image system")) {
+ diag_printf("** Aborted\n");
+ return;
+ }
+ diag_printf("*** Initialize FLASH Image System\n");
+
+#define MIN_REDBOOT_IMAGE_SIZE CYGBLD_REDBOOT_MIN_IMAGE_SIZE
+ redboot_image_size = flash_block_size > MIN_REDBOOT_IMAGE_SIZE ?
+ flash_block_size : MIN_REDBOOT_IMAGE_SIZE;
+
+ // Create a pseudo image for RedBoot
+ img = (struct fis_image_desc *)fis_work_block;
+ memset(img, 0xFF, fisdir_size); // Start with erased data
+#ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE
+ memset(img, 0, sizeof(*img));
+ strcpy(img->name, "(reserved)");
+ img->flash_base = (CYG_ADDRESS)flash_start;
+ img->mem_base = (CYG_ADDRESS)flash_start;
+ img->size = CYGNUM_REDBOOT_FLASH_RESERVED_BASE;
+ img++;
+#endif
+ redboot_flash_start = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
+#ifdef CYGOPT_REDBOOT_FIS_REDBOOT
+ memset(img, 0, sizeof(*img));
+ strcpy(img->name, "RedBoot");
+ img->flash_base = redboot_flash_start;
+ img->mem_base = redboot_flash_start;
+ img->size = redboot_image_size;
+ img++;
+ redboot_flash_start += redboot_image_size;
+#endif
+#ifdef CYGOPT_REDBOOT_FIS_REDBOOT_POST
+#ifdef CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET
+ // Take care to place the POST entry at the right offset:
+ redboot_flash_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET;
+#endif
+ memset(img, 0, sizeof(*img));
+ strcpy(img->name, "RedBoot[post]");
+ img->flash_base = redboot_flash_start;
+ img->mem_base = redboot_flash_start;
+ img->size = redboot_image_size;
+ img++;
+ redboot_flash_start += redboot_image_size;
+#endif
+#ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP
+ // And a backup image
+ memset(img, 0, sizeof(*img));
+ strcpy(img->name, "RedBoot[backup]");
+ img->flash_base = redboot_flash_start;
+ img->mem_base = redboot_flash_start;
+ img->size = redboot_image_size;
+ img++;
+ redboot_flash_start += redboot_image_size;
+#endif
+#if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
+ // And a descriptor for the configuration data
+ memset(img, 0, sizeof(*img));
+ strcpy(img->name, "RedBoot config");
+ img->flash_base = (CYG_ADDRESS)cfg_base;
+ img->mem_base = (CYG_ADDRESS)cfg_base;
+ img->size = cfg_size;
+ img++;
+#endif
+ // And a descriptor for the descriptor table itself
+ memset(img, 0, sizeof(*img));
+ strcpy(img->name, "FIS directory");
+ img->flash_base = (CYG_ADDRESS)fis_addr;
+ img->mem_base = (CYG_ADDRESS)fis_addr;
+ img->size = fisdir_size;
+ img++;
+
+#ifdef CYGOPT_REDBOOT_FIS_DIRECTORY_ARM_SIB_ID
+ // FIS gets the size of a full block - note, this should be changed
+ // if support is added for multi-block FIS structures.
+ img = (struct fis_image_desc *)((CYG_ADDRESS)fis_work_block + fisdir_size);
+ // Add a footer so the FIS will be recognized by the ARM Boot
+ // Monitor as a reserved area.
+ {
+ tFooter* footer_p = (tFooter*)((CYG_ADDRESS)img - sizeof(tFooter));
+ cyg_uint32 check = 0;
+ cyg_uint32 *check_ptr = (cyg_uint32 *)footer_p;
+ cyg_int32 count = (sizeof(tFooter) - 4) >> 2;
+
+ // Prepare footer. Try to protect all but the reserved space
+ // and the first RedBoot image (which is expected to be
+ // bootable), but fall back to just protecting the FIS if it's
+ // not at the default position in the flash.
+#if defined(CYGOPT_REDBOOT_FIS_RESERVED_BASE) && (-1 == CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK)
+ footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(flash_start);
+ footer_p->blockBase += CYGNUM_REDBOOT_FLASH_RESERVED_BASE + redboot_image_size;
+#else
+ footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(fis_work_block);
+#endif
+ footer_p->infoBase = NULL;
+ footer_p->signature = FLASH_FOOTER_SIGNATURE;
+ footer_p->type = TYPE_REDHAT_REDBOOT;
+
+ // and compute its checksum
+ for ( ; count > 0; count--) {
+ if (*check_ptr > ~check)
+ check++;
+ check += *check_ptr++;
+ }
+ footer_p->checksum = ~check;
+ }
+#endif
+
+ // Do this after creating the initialized table because that inherently
+ // calculates where the high water mark of default RedBoot images is.
+
+ if (full_init) {
+ unsigned long erase_size;
+ CYG_ADDRESS erase_start;
+ // Erase everything except default RedBoot images, fis block,
+ // and config block.
+ // First deal with the possible first part, before RedBoot images:
+#if (CYGBLD_REDBOOT_FLASH_BOOT_OFFSET > CYGNUM_REDBOOT_FLASH_RESERVED_BASE)
+ erase_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FLASH_RESERVED_BASE;
+ erase_size = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
+ if ( erase_size > erase_start ) {
+ erase_size -= erase_start;
+ if ((stat = flash_erase((void *)erase_start, erase_size,
+ (void **)&err_addr)) != 0) {
+ diag_printf(" initialization failed at %p: %s\n",
+ err_addr, flash_errmsg(stat));
+ }
+ }
+#endif
+ // second deal with the larger part in the main:
+ erase_start = redboot_flash_start; // high water of created images
+ // Now the empty bits between the end of Redboot and the cfg and dir
+ // blocks.
+#if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && \
+ defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH) && \
+ !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG)
+ if (fis_addr > cfg_base) {
+ erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between HWM and config data
+ } else {
+ erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
+ }
+ if ((stat = flash_erase((void *)erase_start, erase_size,
+ (void **)&err_addr)) != 0) {
+ diag_printf(" initialization failed %p: %s\n",
+ err_addr, flash_errmsg(stat));
+ }
+ erase_start += (erase_size + flash_block_size);
+ if (fis_addr > cfg_base) {
+ erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between config and fis data
+ } else {
+ erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between fis and config data
+ }
+ if ((stat = flash_erase((void *)erase_start, erase_size,
+ (void **)&err_addr)) != 0) {
+ diag_printf(" initialization failed %p: %s\n",
+ err_addr, flash_errmsg(stat));
+ }
+ erase_start += (erase_size + flash_block_size);
+#else // !CYGSEM_REDBOOT_FLASH_CONFIG
+ erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
+ if ((stat = flash_erase((void *)erase_start, erase_size,
+ (void **)&err_addr)) != 0) {
+ diag_printf(" initialization failed %p: %s\n",
+ err_addr, flash_errmsg(stat));
+ }
+ erase_start += (erase_size + flash_block_size);
+#endif
+ // Lastly, anything at the end, if there is any
+ if ( erase_start < (((CYG_ADDRESS)flash_end)+1) ) {
+ erase_size = ((CYG_ADDRESS)flash_end - erase_start) + 1;
+ if ((stat = flash_erase((void *)erase_start, erase_size,
+ (void **)&err_addr)) != 0) {
+ diag_printf(" initialization failed at %p: %s\n",
+ err_addr, flash_errmsg(stat));
+ }
+ }
+#ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
+ // In this case, 'fis free' works by scanning for erased blocks. Since the
+ // "-f" option was not supplied, there may be areas which are not used but
+ // don't appear to be free since they are not erased - thus the warning
+ } else {
+ diag_printf(" Warning: device contents not erased, some blocks may not be usable\n");
+#endif
+ }
+ fis_update_directory();
+}
+
+static void
+fis_list(int argc, char *argv[])
+{
+ struct fis_image_desc *img;
+ int i, image_indx;
+ bool show_cksums = false;
+ bool show_datalen = false;
+ struct option_info opts[2];
+ unsigned long last_addr, lowest_addr;
+ bool image_found;
+
+#ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB
+ // FIXME: this is somewhat half-baked
+ extern void arm_fis_list(void);
+ arm_fis_list();
+ return;
+#endif
+
+ init_opts(&opts[0], 'd', false, OPTION_ARG_TYPE_FLG,
+ (void *)&show_datalen, (bool *)0, "display data length");
+#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
+ init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG,
+ (void *)&show_cksums, (bool *)0, "display checksums");
+ i = 2;
+#else
+ i = 1;
+#endif
+ if (!scan_opts(argc, argv, 2, opts, i, 0, 0, "")) {
+ return;
+ }
+ fis_read_directory();
+
+ // Let diag_printf do the formatting in both cases, rather than counting
+ // cols by hand....
+ diag_printf("%-16s %-10s %-10s %-10s %-s\n",
+ "Name","FLASH addr",
+ show_cksums ? "Checksum" : "Mem addr",
+ show_datalen ? "Datalen" : "Length",
+ "Entry point" );
+ last_addr = 0;
+ image_indx = 0;
+ do {
+ image_found = false;
+ lowest_addr = 0xFFFFFFFF;
+ img = (struct fis_image_desc *) fis_work_block;
+ for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) {
+ if (img->name[0] != (unsigned char)0xFF) {
+ if ((img->flash_base > last_addr) && (img->flash_base < lowest_addr)) {
+ lowest_addr = img->flash_base;
+ image_found = true;
+ image_indx = i;
+ }
+ }
+ }
+ if (image_found) {
+ img = (struct fis_image_desc *) fis_work_block;
+ img += image_indx;
+ diag_printf("%-16s 0x%08lX 0x%08lX 0x%08lX 0x%08lX\n", img->name,
+ (unsigned long)img->flash_base,
+#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
+ show_cksums ? img->file_cksum : img->mem_base,
+ show_datalen ? img->data_length : img->size,
+#else
+ img->mem_base,
+ img->size,
+#endif
+ (unsigned long)img->entry_point);
+ }
+ last_addr = lowest_addr;
+ } while (image_found == true);
+}
+
+#ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
+struct free_chunk {
+ CYG_ADDRESS start, end;
+};
+
+static int
+find_free(struct free_chunk *chunks)
+{
+ CYG_ADDRESS *fis_ptr, *fis_end;
+ struct fis_image_desc *img;
+ int i, idx;
+ int num_chunks = 1;
+
+ // Do not search the area reserved for pre-RedBoot systems:
+ fis_ptr = (CYG_ADDRESS *)((CYG_ADDRESS)flash_start +
+ CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
+ fis_end = (CYG_ADDRESS *)flash_end;
+ chunks[num_chunks-1].start = (CYG_ADDRESS)fis_ptr;
+ chunks[num_chunks-1].end = (CYG_ADDRESS)fis_end;
+ fis_read_directory();
+ img = (struct fis_image_desc *) fis_work_block;
+ for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) {
+ if (img->name[0] != (unsigned char)0xFF) {
+ // Figure out which chunk this is in and split it
+ for (idx = 0; idx < num_chunks; idx++) {
+ if ((img->flash_base >= chunks[idx].start) &&
+ (img->flash_base <= chunks[idx].end)) {
+ if (img->flash_base == chunks[idx].start) {
+ chunks[idx].start += img->size;
+ if (chunks[idx].start >= chunks[idx].end) {
+ // This free chunk has collapsed
+ while (idx < (num_chunks-1)) {
+ chunks[idx] = chunks[idx+1];
+ idx++;
+ }
+ num_chunks--;
+ }
+ } else if ((img->flash_base+img->size) == chunks[idx].end) {
+ chunks[idx].end = img->flash_base;
+ } else {
+ // Split chunk into two parts
+ if ((img->flash_base+img->size) < (CYG_ADDRESS)fis_end) {
+ int j;
+ // make room for new chunk
+ for (j = num_chunks; j > (idx+1); j--)
+ chunks[j] = chunks[j-1];
+ chunks[idx+1].start = img->flash_base + img->size;
+ chunks[idx+1].end = chunks[idx].end;
+ if (++num_chunks == CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS) {
+ diag_printf("Warning: too many free chunks\n");
+ return num_chunks;
+ }
+ }
+ chunks[idx].end = img->flash_base;
+ }
+ break;
+ }
+ }
+ }
+ }
+ return num_chunks;
+}
+#endif // CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
+
+static void
+fis_free(int argc, char *argv[])
+{
+#ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
+ unsigned long *fis_ptr, *fis_end, flash_data;
+ unsigned long *area_start;
+ void *err_addr;
+
+ // Do not search the area reserved for pre-RedBoot systems:
+ fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +
+ CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
+ fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
+ area_start = fis_ptr;
+ while (fis_ptr < fis_end) {
+ flash_read(fis_ptr, &flash_data, sizeof(unsigned long), (void **)&err_addr);
+ if (flash_data != (unsigned long)0xFFFFFFFF) {
+ if (area_start != fis_ptr) {
+ // Assume that this is something
+ diag_printf(" 0x%08lX .. 0x%08lX\n",
+ (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
+ }
+ // Find next blank block
+ area_start = fis_ptr;
+ while (area_start < fis_end) {
+ flash_read(area_start, &flash_data, sizeof(unsigned long), (void **)&err_addr);
+ if (flash_data == (unsigned long)0xFFFFFFFF) {
+ break;
+ }
+ area_start += flash_block_size / sizeof(CYG_ADDRESS);
+ }
+ fis_ptr = area_start;
+ } else {
+ fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
+ }
+ }
+ if (area_start != fis_ptr) {
+ diag_printf(" 0x%08lX .. 0x%08lX\n",
+ (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
+ }
+#else
+ struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
+ int idx, num_chunks;
+
+ num_chunks = find_free(chunks);
+ for (idx = 0; idx < num_chunks; idx++) {
+ diag_printf(" 0x%08lX .. 0x%08lX\n",
+ (unsigned long)chunks[idx].start,
+ (unsigned long)chunks[idx].end);
+ }
+#endif
+}
+
+// Find the first unused area of flash which is long enough
+static bool
+fis_find_free(CYG_ADDRESS *addr, unsigned long length)
+{
+#ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
+ unsigned long *fis_ptr, *fis_end, flash_data;
+ unsigned long *area_start;
+ void *err_addr;
+
+ // Do not search the area reserved for pre-RedBoot systems:
+ fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +
+ CYGNUM_REDBOOT_FLASH_RESERVED_BASE);
+ fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
+ area_start = fis_ptr;
+ while (fis_ptr < fis_end) {
+ flash_read(fis_ptr, &flash_data, sizeof(unsigned long), (void **)&err_addr);
+ if (flash_data != (unsigned long)0xFFFFFFFF) {
+ if (area_start != fis_ptr) {
+ // Assume that this is something
+ if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) {
+ *addr = (CYG_ADDRESS)area_start;
+ return true;
+ }
+ }
+ // Find next blank block
+ area_start = fis_ptr;
+ while (area_start < fis_end) {
+ flash_read(area_start, &flash_data, sizeof(unsigned long), (void **)&err_addr);
+ if (flash_data == (unsigned long)0xFFFFFFFF) {
+ break;
+ }
+ area_start += flash_block_size / sizeof(CYG_ADDRESS);
+ }
+ fis_ptr = area_start;
+ } else {
+ fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
+ }
+ }
+ if (area_start != fis_ptr) {
+ if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) {
+ *addr = (CYG_ADDRESS)area_start;
+ return true;
+ }
+ }
+ return false;
+#else
+ struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
+ int idx, num_chunks;
+
+ num_chunks = find_free(chunks);
+ for (idx = 0; idx < num_chunks; idx++) {
+ if ((chunks[idx].end - chunks[idx].start) >= length) {
+ *addr = (CYG_ADDRESS)chunks[idx].start;
+ return true;
+ }
+ }
+ return false;
+#endif
+}
+
+static void
+fis_create(int argc, char *argv[])
+{
+ int i, stat;
+ unsigned long length, img_size;
+ CYG_ADDRESS mem_addr, exec_addr, flash_addr, entry_addr;
+ char *name;
+ bool mem_addr_set = false;
+ bool exec_addr_set = false;
+ bool entry_addr_set = false;
+ bool flash_addr_set = false;
+ bool length_set = false;
+ bool img_size_set = false;
+ bool no_copy = false;
+ void *err_addr;
+ struct fis_image_desc *img = NULL;
+ bool defaults_assumed;
+ struct option_info opts[7];
+ bool prog_ok = true;
+
+ init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&mem_addr, (bool *)&mem_addr_set, "memory base address");
+ init_opts(&opts[1], 'r', true, OPTION_ARG_TYPE_NUM,
+ (void *)&exec_addr, (bool *)&exec_addr_set, "ram base address");
+ init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM,
+ (void *)&entry_addr, (bool *)&entry_addr_set, "entry point address");
+ init_opts(&opts[3], 'f', true, OPTION_ARG_TYPE_NUM,
+ (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
+ init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&length, (bool *)&length_set, "image length [in FLASH]");
+ init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM,
+ (void *)&img_size, (bool *)&img_size_set, "image size [actual data]");
+ init_opts(&opts[6], 'n', false, OPTION_ARG_TYPE_FLG,
+ (void *)&no_copy, (bool *)0, "don't copy from RAM to FLASH, just update directory");
+ if (!scan_opts(argc, argv, 2, opts, 7, (void *)&name, OPTION_ARG_TYPE_STR, "file name"))
+ {
+ fis_usage("invalid arguments");
+ return;
+ }
+
+ fis_read_directory();
+ defaults_assumed = false;
+ if (name) {
+ // Search existing files to acquire defaults for params not specified:
+ img = fis_lookup(name, NULL);
+ if (img) {
+ // Found it, so get image size from there
+ if (!length_set) {
+ length_set = true;
+ length = img->size;
+ defaults_assumed = true;
+ }
+ }
+ }
+ if (!mem_addr_set && (load_address >= (CYG_ADDRESS)ram_start) &&
+ (load_address_end) < (CYG_ADDRESS)ram_end) {
+ mem_addr = load_address;
+ mem_addr_set = true;
+ defaults_assumed = true;
+ // Get entry address from loader, unless overridden
+ if (!entry_addr_set)
+ entry_addr = entry_address;
+ if (!length_set) {
+ length = load_address_end - load_address;
+ length_set = true;
+ } else if (defaults_assumed && !img_size_set) {
+ /* We got length from the FIS table, so the size of the
+ actual loaded image becomes img_size */
+ img_size = load_address_end - load_address;
+ img_size_set = true;
+ }
+ }
+ // Get the remaining fall-back values from the fis
+ if (img) {
+ if (!exec_addr_set) {
+ // Preserve "normal" behaviour
+ exec_addr_set = true;
+ exec_addr = flash_addr_set ? flash_addr : mem_addr;
+ }
+ if (!flash_addr_set) {
+ flash_addr_set = true;
+ flash_addr = img->flash_base;
+ defaults_assumed = true;
+ }
+ }
+
+ if ((!no_copy && !mem_addr_set) || (no_copy && !flash_addr_set) ||
+ !length_set || !name) {
+ fis_usage("required parameter missing");
+ return;
+ }
+ if (!img_size_set) {
+ img_size = length;
+ }
+ // 'length' is size of FLASH image, 'img_size' is actual data size
+ // Round up length to FLASH block size
+#ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
+ length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
+ if (length < img_size) {
+ diag_printf("Invalid FLASH image size/length combination\n");
+ return;
+ }
+#endif
+ if (flash_addr_set &&
+ ((stat = flash_verify_addr((void *)flash_addr)) ||
+ (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
+ _show_invalid_flash_address(flash_addr, stat);
+ return;
+ }
+ if (flash_addr_set && ((flash_addr & (flash_block_size-1)) != 0)) {
+ diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
+ diag_printf(" must be 0x%x aligned\n", flash_block_size);
+ return;
+ }
+ if (strlen(name) >= sizeof(img->name)) {
+ diag_printf("Name is too long, must be less than %d chars\n", (int)sizeof(img->name));
+ return;
+ }
+ if (!no_copy) {
+ if ((mem_addr < (CYG_ADDRESS)ram_start) ||
+ ((mem_addr+img_size) >= (CYG_ADDRESS)ram_end)) {
+ diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
+ diag_printf(" valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
+ }
+ if (!flash_addr_set && !fis_find_free(&flash_addr, length)) {
+ diag_printf("Can't locate %lx(%ld) bytes free in FLASH\n", length, length);
+ return;
+ }
+ }
+ // First, see if the image by this name has agreable properties
+ if (img) {
+ if (flash_addr_set && (img->flash_base != flash_addr)) {
+ diag_printf("Image found, but flash address (%p)\n"
+ " is incorrect (present image location %p)\n",
+ (void*)flash_addr, (void*)img->flash_base);
+
+ return;
+ }
+ if (img->size != length) {
+ diag_printf("Image found, but length (0x%lx, necessitating image size 0x%lx)\n"
+ " is incorrect (present image size 0x%lx)\n",
+ img_size, length, img->size);
+ return;
+ }
+ if (!verify_action("An image named '%s' exists", name)) {
+ return;
+ } else {
+ if (defaults_assumed) {
+ if (no_copy &&
+ !verify_action("* CAUTION * about to program '%s'\n at %p..%p from %p",
+ name, (void *)flash_addr, (void *)(flash_addr+img_size-1),
+ (void *)mem_addr)) {
+ return; // The guy gave up
+ }
+ }
+ }
+ } else {
+#ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
+ // Make sure that any FLASH address specified directly is truly free
+ if (flash_addr_set && !no_copy) {
+ struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
+ int idx, num_chunks;
+ bool is_free = false;
+
+ num_chunks = find_free(chunks);
+ for (idx = 0; idx < num_chunks; idx++) {
+ if ((flash_addr >= chunks[idx].start) &&
+ ((flash_addr+length-1) <= chunks[idx].end)) {
+ is_free = true;
+ }
+ }
+ if (!is_free) {
+ diag_printf("Invalid FLASH address - not free!\n");
+ return;
+ }
+ }
+#endif
+ // If not image by that name, try and find an empty slot
+ img = (struct fis_image_desc *)fis_work_block;
+ for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) {
+ if (img->name[0] == (unsigned char)0xFF) {
+ break;
+ }
+ }
+ if (i >= fisdir_size/sizeof(*img)) {
+ diag_printf("Can't find an empty slot in FIS directory!\n");
+ return;
+ }
+ }
+ if (!no_copy) {
+ // Safety check - make sure the address range is not within the code we're running
+ if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+img_size-1))) {
+ diag_printf("Can't program this region - contains code in use!\n");
+ return;
+ }
+ if (prog_ok) {
+ // Erase area to be programmed
+ if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) {
+ diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
+ prog_ok = false;
+ }
+ }
+ if (prog_ok) {
+ // Now program it
+ if ((stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, img_size, (void **)&err_addr)) != 0) {
+ diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
+ prog_ok = false;
+ }
+ }
+ }
+ if (prog_ok) {
+ // Update directory
+ memset(img, 0, sizeof(*img));
+ strcpy(img->name, name);
+ img->flash_base = flash_addr;
+ img->mem_base = exec_addr_set ? exec_addr : (flash_addr_set ? flash_addr : mem_addr);
+ img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address; // Hope it's been set
+ img->size = length;
+ img->data_length = img_size;
+#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
+ if (!no_copy) {
+ img->file_cksum = cyg_crc32((unsigned char *)mem_addr, img_size);
+ } else {
+ // No way to compute this, sorry
+ img->file_cksum = 0;
+ }
+#endif
+ fis_update_directory();
+ }
+}
+
+extern void arm_fis_delete(char *);
+static void
+fis_delete(int argc, char *argv[])
+{
+ char *name;
+ int num_reserved, i, stat;
+ void *err_addr;
+ struct fis_image_desc *img;
+
+ if (!scan_opts(argc, argv, 2, 0, 0, (void *)&name, OPTION_ARG_TYPE_STR, "image name"))
+ {
+ fis_usage("invalid arguments");
+ return;
+ }
+#ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB
+ // FIXME: this is somewhat half-baked
+ arm_fis_delete(name);
+ return;
+#endif
+ img = (struct fis_image_desc *)fis_work_block;
+ num_reserved = 0;
+#ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE
+ num_reserved++;
+#endif
+#ifdef CYGOPT_REDBOOT_FIS_REDBOOT
+ num_reserved++;
+#endif
+#ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP
+ num_reserved++;
+#endif
+#ifdef CYGOPT_REDBOOT_FIS_REDBOOT_POST
+ num_reserved++;
+#endif
+#if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
+ num_reserved++;
+#endif
+#if 1 // And the descriptor for the descriptor table itself
+ num_reserved++;
+#endif
+
+ img = fis_lookup(name, &i);
+ if (img) {
+ if (i < num_reserved) {
+ diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->name);
+ return;
+ }
+ if (!verify_action("Delete image '%s'", name)) {
+ return;
+ }
+ } else {
+ diag_printf("No image '%s' found\n", name);
+ return;
+ }
+ // Erase Data blocks (free space)
+ if ((stat = flash_erase((void *)img->flash_base, img->size, (void **)&err_addr)) != 0) {
+ diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
+ } else {
+ img->name[0] = (unsigned char)0xFF;
+ fis_update_directory();
+ }
+}
+
+static void
+fis_load(int argc, char *argv[])
+{
+ char *name;
+ struct fis_image_desc *img;
+ CYG_ADDRESS mem_addr;
+ bool mem_addr_set = false;
+ bool show_cksum = false;
+ struct option_info opts[3];
+#if defined(CYGSEM_REDBOOT_FIS_CRC_CHECK)
+ unsigned long cksum;
+#endif
+ int num_options;
+#if defined(CYGPRI_REDBOOT_ZLIB_FLASH) || defined(CYGSEM_REDBOOT_FIS_CRC_CHECK)
+ bool decompress = false;
+#endif
+ void *err_addr;
+
+ init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&mem_addr, (bool *)&mem_addr_set, "memory [load] base address");
+ init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG,
+ (void *)&show_cksum, (bool *)0, "display checksum");
+ num_options = 2;
+#ifdef CYGPRI_REDBOOT_ZLIB_FLASH
+ init_opts(&opts[num_options], 'd', false, OPTION_ARG_TYPE_FLG,
+ (void *)&decompress, 0, "decompress");
+ num_options++;
+#endif
+
+ CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options");
+
+ if (!scan_opts(argc, argv, 2, opts, num_options, (void *)&name, OPTION_ARG_TYPE_STR, "image name"))
+ {
+ fis_usage("invalid arguments");
+ return;
+ }
+ if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) {
+ diag_printf("No image '%s' found\n", name);
+ return;
+ }
+ if (!mem_addr_set) {
+ mem_addr = img->mem_base;
+ }
+ // Load image from FLASH into RAM
+#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
+ if (!valid_address((void *)mem_addr)) {
+ diag_printf("Not a loadable image - try using -b ADDRESS option\n");
+ return;
+ }
+#endif
+#ifdef CYGPRI_REDBOOT_ZLIB_FLASH
+ if (decompress) {
+ int err;
+ _pipe_t fis_load_pipe;
+ _pipe_t* p = &fis_load_pipe;
+ p->out_buf = (unsigned char*) mem_addr;
+ p->out_max = p->out_size = -1;
+ p->in_buf = (unsigned char*) img->flash_base;
+ p->in_avail = img->data_length;
+
+ err = (*_dc_init)(p);
+
+ if (0 == err)
+ err = (*_dc_inflate)(p);
+
+ // Free used resources, do final translation of
+ // error value.
+ err = (*_dc_close)(p, err);
+
+ if (0 != err && p->msg) {
+ diag_printf("decompression error: %s\n", p->msg);
+ } else {
+ diag_printf("Image loaded from %p-%p\n", (unsigned char *)mem_addr, p->out_buf);
+ }
+
+ // Set load address/top
+ load_address = mem_addr;
+ load_address_end = (unsigned long)p->out_buf;
+
+ // Reload fis directory
+ fis_read_directory();
+ } else // dangling block
+#endif
+ {
+ flash_read((void *)img->flash_base, (void *)mem_addr, img->data_length, (void **)&err_addr);
+
+ // Set load address/top
+ load_address = mem_addr;
+ load_address_end = mem_addr + img->data_length;
+ }
+ entry_address = (unsigned long)img->entry_point;
+
+#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
+ cksum = cyg_crc32((unsigned char *)mem_addr, img->data_length);
+ if (show_cksum) {
+ diag_printf("Checksum: 0x%08lx\n", cksum);
+ }
+ // When decompressing, leave CRC checking to decompressor
+ if (!decompress && img->file_cksum) {
+ if (cksum != img->file_cksum) {
+ diag_printf("** Warning - checksum failure. stored: 0x%08lx, computed: 0x%08lx\n",
+ img->file_cksum, cksum);
+ entry_address = (unsigned long)NO_MEMORY;
+ }
+ }
+#endif
+}
+#endif // CYGOPT_REDBOOT_FIS
+
+static void
+fis_write(int argc, char *argv[])
+{
+ int stat;
+ unsigned long length;
+ CYG_ADDRESS mem_addr, flash_addr;
+ bool mem_addr_set = false;
+ bool flash_addr_set = false;
+ bool length_set = false;
+ void *err_addr;
+ struct option_info opts[3];
+ bool prog_ok;
+
+ init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&mem_addr, (bool *)&mem_addr_set, "memory base address");
+ init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM,
+ (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
+ init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&length, (bool *)&length_set, "image length [in FLASH]");
+ if (!scan_opts(argc, argv, 2, opts, 3, 0, 0, 0))
+ {
+ fis_usage("invalid arguments");
+ return;
+ }
+
+ if (!mem_addr_set || !flash_addr_set || !length_set) {
+ fis_usage("required parameter missing");
+ return;
+ }
+
+ // Round up length to FLASH block size
+#ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
+ length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
+#endif
+ if (flash_addr_set &&
+ ((stat = flash_verify_addr((void *)flash_addr)) ||
+ (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
+ _show_invalid_flash_address(flash_addr, stat);
+ return;
+ }
+ if (flash_addr_set && flash_addr & (flash_block_size-1)) {
+ diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
+ diag_printf(" must be 0x%x aligned\n", flash_block_size);
+ return;
+ }
+ if ((mem_addr < (CYG_ADDRESS)ram_start) ||
+ ((mem_addr+length) >= (CYG_ADDRESS)ram_end)) {
+ diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr);
+ diag_printf(" valid range is %p-%p\n", (void *)ram_start, (void *)ram_end);
+ }
+ // Safety check - make sure the address range is not within the code we're running
+ if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) {
+ diag_printf("Can't program this region - contains code in use!\n");
+ return;
+ }
+ if (!verify_action("* CAUTION * about to program FLASH\n at %p..%p from %p",
+ (void *)flash_addr, (void *)(flash_addr+length-1),
+ (void *)mem_addr)) {
+ return; // The guy gave up
+ }
+ prog_ok = true;
+ if (prog_ok) {
+ // Erase area to be programmed
+ if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) {
+ diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat));
+ prog_ok = false;
+ }
+ }
+ if (prog_ok) {
+ // Now program it
+ if ((stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, length, (void **)&err_addr)) != 0) {
+ diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat));
+ prog_ok = false;
+ }
+ }
+}
+
+static void
+fis_erase(int argc, char *argv[])
+{
+ int stat;
+ unsigned long length;
+ CYG_ADDRESS flash_addr;
+ bool flash_addr_set = false;
+ bool length_set = false;
+ void *err_addr;
+ struct option_info opts[2];
+
+ init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
+ (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
+ init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&length, (bool *)&length_set, "length");
+ if (!scan_opts(argc, argv, 2, opts, 2, (void **)0, 0, ""))
+ {
+ fis_usage("invalid arguments");
+ return;
+ }
+
+ if (!flash_addr_set || !length_set) {
+ fis_usage("missing argument");
+ return;
+ }
+ if (flash_addr_set &&
+ ((stat = flash_verify_addr((void *)flash_addr)) ||
+ (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
+ _show_invalid_flash_address(flash_addr, stat);
+ return;
+ }
+ if (flash_addr_set && flash_addr & (flash_block_size-1)) {
+ diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr);
+ diag_printf(" must be 0x%x aligned\n", flash_block_size);
+ return;
+ }
+ // Safety check - make sure the address range is not within the code we're running
+ if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) {
+ diag_printf("Can't erase this region - contains code in use!\n");
+ return;
+ }
+ if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) {
+ diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
+ }
+}
+
+#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
+
+static void
+fis_lock(int argc, char *argv[])
+{
+ char *name;
+ int stat;
+ unsigned long length;
+ CYG_ADDRESS flash_addr;
+ bool flash_addr_set = false;
+ bool length_set = false;
+ void *err_addr;
+ struct option_info opts[2];
+
+ init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
+ (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
+ init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&length, (bool *)&length_set, "length");
+ if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name"))
+ {
+ fis_usage("invalid arguments");
+ return;
+ }
+
+ /* Get parameters from image if specified */
+ if (name) {
+ struct fis_image_desc *img;
+ if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) {
+ diag_printf("No image '%s' found\n", name);
+ return;
+ }
+
+ flash_addr = img->flash_base;
+ length = img->size;
+ } else if (!flash_addr_set || !length_set) {
+ fis_usage("missing argument");
+ return;
+ }
+ if (flash_addr_set &&
+ ((stat = flash_verify_addr((void *)flash_addr)) ||
+ (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
+ _show_invalid_flash_address(flash_addr, stat);
+ return;
+ }
+ if ((stat = flash_lock((void *)flash_addr, length, (void **)&err_addr)) != 0) {
+ diag_printf("Error locking at %p: %s\n", err_addr, flash_errmsg(stat));
+ }
+}
+
+static void
+fis_unlock(int argc, char *argv[])
+{
+ char *name;
+ int stat;
+ unsigned long length;
+ CYG_ADDRESS flash_addr;
+ bool flash_addr_set = false;
+ bool length_set = false;
+ void *err_addr;
+ struct option_info opts[2];
+
+ init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM,
+ (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
+ init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&length, (bool *)&length_set, "length");
+ if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name"))
+ {
+ fis_usage("invalid arguments");
+ return;
+ }
+
+ if (name) {
+ struct fis_image_desc *img;
+ if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) {
+ diag_printf("No image '%s' found\n", name);
+ return;
+ }
+
+ flash_addr = img->flash_base;
+ length = img->size;
+ } else if (!flash_addr_set || !length_set) {
+ fis_usage("missing argument");
+ return;
+ }
+ if (flash_addr_set &&
+ ((stat = flash_verify_addr((void *)flash_addr)) ||
+ (stat = flash_verify_addr((void *)(flash_addr+length-1))))) {
+ _show_invalid_flash_address(flash_addr, stat);
+ return;
+ }
+
+ if ((stat = flash_unlock((void *)flash_addr, length, (void **)&err_addr)) != 0) {
+ diag_printf("Error unlocking at %p: %s\n", err_addr, flash_errmsg(stat));
+ }
+}
+#endif
+
+// This is set non-zero if the FLASH subsystem has successfully been initialized
+int __flash_init = 0;
+
+void
+_flash_info(void)
+{
+ if (!__flash_init) return;
+ diag_printf("FLASH: %p - 0x%x, %d blocks of %p bytes each.\n",
+ flash_start, (CYG_ADDRWORD)flash_end + 1, flash_num_blocks, (void *)flash_block_size);
+}
+
+bool
+do_flash_init(void)
+{
+ int stat;
+
+ if (!__flash_init) {
+ __flash_init = 1;
+ if ((stat = flash_init(diag_printf)) != 0) {
+ diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat));
+ return false;
+ }
+ flash_get_limits((void *)0, (void **)&flash_start, (void **)&flash_end);
+ // Keep 'end' address as last valid location, to avoid wrap around problems
+ flash_end = (void *)((CYG_ADDRESS)flash_end - 1);
+ flash_get_block_info(&flash_block_size, &flash_num_blocks);
+#ifdef CYGOPT_REDBOOT_FIS
+ fisdir_size = CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_COUNT * CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_SIZE;
+ fisdir_size = ((fisdir_size + flash_block_size - 1) / flash_block_size) * flash_block_size;
+# if defined(CYGPRI_REDBOOT_ZLIB_FLASH) && defined(CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER)
+ fis_work_block = fis_zlib_common_buffer;
+ if(CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE < fisdir_size) {
+ diag_printf("FLASH: common buffer too small\n");
+ return false;
+ }
+# else
+ workspace_end = (unsigned char *)(workspace_end-fisdir_size);
+ fis_work_block = workspace_end;
+# endif
+ if (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK < 0) {
+ fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 +
+ (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size));
+ } else {
+ fis_addr = (void *)((CYG_ADDRESS)flash_start +
+ (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size));
+ }
+ if (((CYG_ADDRESS)fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) {
+ diag_printf("FIS directory doesn't fit\n");
+ return false;
+ }
+ fis_read_directory();
+#endif
+ }
+ return true;
+}
+
+// Wrapper to avoid compiler warnings
+static void
+_do_flash_init(void)
+{
+ static int init_done = 0;
+ if (init_done) return;
+ init_done = 1;
+ do_flash_init();
+}
+
+RedBoot_init(_do_flash_init, RedBoot_INIT_FIRST);
+
+static void
+do_fis(int argc, char *argv[])
+{
+ struct cmd *cmd;
+
+ if (argc < 2) {
+ fis_usage("too few arguments");
+ return;
+ }
+ if (!do_flash_init()) {
+ diag_printf("Sorry, no FLASH memory is available\n");
+ return;
+ }
+ if ((cmd = cmd_search(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__,
+ argv[1])) != (struct cmd *)0) {
+ (cmd->fun)(argc, argv);
+ return;
+ }
+ fis_usage("unrecognized command");
+}
+
+// EOF flash.c
diff --git a/ecos/packages/redboot/current/src/fs/disk.c b/ecos/packages/redboot/current/src/fs/disk.c
new file mode 100644
index 0000000000..96a9e82acf
--- /dev/null
+++ b/ecos/packages/redboot/current/src/fs/disk.c
@@ -0,0 +1,441 @@
+//==========================================================================
+//
+// disk.c
+//
+// RedBoot disk support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): msalter
+// Contributors: msalter
+// Date: 2001-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <fs/disk.h>
+
+#ifdef CYGSEM_REDBOOT_DISK_EXT2FS
+#include <fs/e2fs.h>
+#endif
+#ifdef CYGSEM_REDBOOT_DISK_ISO9660
+#include <fs/iso9660fs.h>
+#endif
+
+static void do_disks(int argc, char *argv[]);
+
+RedBoot_cmd("disks",
+ "Display disks/partitions.",
+ "",
+ do_disks
+ );
+
+static disk_t disk_table[CYGNUM_REDBOOT_MAX_DISKS];
+static int disk_count = 0;
+
+static inline cyg_uint32
+u32_unaligned(void *p)
+{
+ cyg_uint32 val;
+ char *d = (char *)&val;
+ char *s = p;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ *d++ = *s++;
+
+ return val;
+}
+
+static int
+find_dos_partitions(disk_t *d, cyg_uint8 *mbr)
+{
+ cyg_uint32 s, n;
+ struct mbr_partition *p;
+ int i, found = 0;
+
+ p = (struct mbr_partition *)(mbr + MBR_PTABLE_OFFSET);
+
+ // Look for primary partitions
+ for (i = 0; i < 4 && i < CYGNUM_REDBOOT_MAX_PARTITIONS; i++) {
+
+ s = SWAB_LE32(u32_unaligned(p->start_sect));
+ n = SWAB_LE32(u32_unaligned(p->nr_sects));
+
+ if (s && n) {
+ ++found;
+ d->partitions[i].disk = d;
+ d->partitions[i].start_sector = s;
+ d->partitions[i].nr_sectors = n;
+ d->partitions[i].systype = p->sys_ind;
+ d->partitions[i].bootflag = p->boot_ind;
+ }
+ p++;
+ }
+
+#if CYGNUM_REDBOOT_MAX_PARTITIONS > 4
+ {
+ cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)], xoffset;
+ cyg_uint16 magic;
+ int nextp;
+
+ // Go back through and find extended partitions
+ for (i = 0, nextp = 4; i < 4 && nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; i++) {
+ if (d->partitions[i].systype == SYSTYPE_EXTENDED) {
+ // sector offsets in partition tables are relative to start
+ // of extended partition.
+ xoffset = d->partitions[i].start_sector;
+ for ( ; nextp < CYGNUM_REDBOOT_MAX_PARTITIONS; ++nextp) {
+
+ // read partition boot record (same format as mbr except
+ // there should only be 2 entries max: a normal partition
+ // and another extended partition
+ if (DISK_READ(d, xoffset, buf, 1) <= 0)
+ break;
+
+ magic = *(cyg_uint16 *)((char *)buf + MBR_MAGIC_OFFSET);
+ if (SWAB_LE16(magic) != MBR_MAGIC)
+ break;
+
+ p = (struct mbr_partition *)((char *)buf + MBR_PTABLE_OFFSET);
+
+ s = SWAB_LE32(u32_unaligned(p->start_sect));
+ n = SWAB_LE32(u32_unaligned(p->nr_sects));
+
+ if (s && n) {
+ ++found;
+ d->partitions[nextp].disk = d;
+ d->partitions[nextp].start_sector = s + xoffset;
+ d->partitions[nextp].nr_sectors = n;
+ d->partitions[nextp].systype = p->sys_ind;
+ d->partitions[nextp].bootflag = p->boot_ind;
+ }
+ ++p;
+
+ s = SWAB_LE32(u32_unaligned(p->start_sect));
+ n = SWAB_LE32(u32_unaligned(p->nr_sects));
+
+ // more extended partitions?
+ if (p->sys_ind != SYSTYPE_EXTENDED || !s || !n)
+ break;
+
+ xoffset += s;
+ }
+ }
+ }
+ }
+#endif
+ return found;
+}
+
+
+// Find partitions on given disk.
+// Return number of partitions found
+static int
+find_partitions(disk_t *d)
+{
+ cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)];
+ cyg_uint16 magic;
+ partition_t *p;
+ int i, found = 0;
+
+
+ if (d->kind == DISK_IDE_CDROM) {
+#ifdef CYGSEM_REDBOOT_DISK_ISO9660
+ // no partition table, so fake it
+ p = d->partitions;
+ p->disk = d;
+ p->start_sector = 0;
+ p->nr_sectors = d->nr_sectors;
+ p->funs = &redboot_iso9660fs_funs;
+ return 1;
+#else
+ return 0;
+#endif
+ }
+
+ // read Master Boot Record
+ if (DISK_READ(d, 0, buf, 1) <= 0)
+ return 0;
+
+ // Check for DOS MBR
+ magic = *(cyg_uint16 *)((char *)buf + MBR_MAGIC_OFFSET);
+ if (SWAB_LE16(magic) == MBR_MAGIC) {
+ found = find_dos_partitions(d, (cyg_uint8 *)buf);
+ } else {
+ // Might want to handle other MBR types, here...
+ }
+
+ // Now go through all partitions and install the correct
+ // funcs for supported filesystems.
+ for (i = 0, p = d->partitions; i < CYGNUM_REDBOOT_MAX_PARTITIONS; i++, p++) {
+ switch (p->systype) {
+#ifdef CYGSEM_REDBOOT_DISK_EXT2FS
+ case SYSTYPE_LINUX:
+ p->funs = &redboot_e2fs_funs;
+ break;
+#endif
+#ifdef CYGSEM_REDBOOT_DISK_FAT16
+ case SYSTYPE_FAT16:
+ p->funs = &redboot_fat16_funs;
+ break;
+#endif
+#ifdef CYGSEM_REDBOOT_DISK_FAT32
+ case SYSTYPE_FAT32:
+ p->funs = &redboot_fat32_funs;
+ break;
+#endif
+ default:
+ break; // ignore unsupported filesystems
+ }
+ }
+
+ return found;
+}
+
+// Add a disk to the disk table.
+// Return zero if no more room in table.
+externC int
+disk_register(disk_t *d)
+{
+ int i;
+
+ // make sure we have room for it
+ if (disk_count >= CYGNUM_REDBOOT_MAX_DISKS)
+ return 0;
+
+ // Set the index
+ d->index = 0;
+ for (i = 0; i < disk_count; i++)
+ if (disk_table[i].kind == d->kind)
+ d->index++;
+
+ // put it in the table
+ disk_table[disk_count] = *d;
+
+ // fill in partition info
+ find_partitions(&disk_table[disk_count++]);
+
+ return 1;
+}
+
+// Convert a filename in the form <partition_name>:<filename> into
+// a partition and path.
+//
+static int
+disk_parse_filename(const char *name, partition_t **part, const char **path)
+{
+ int i, kind, index, pindex;
+
+ kind = index = pindex = 0;
+
+ if (name[0] == 'h' && name[1] == 'd') {
+ // IDE hard drives
+ kind = DISK_IDE_HD;
+ if (name[2] < 'a' || name[2] > 'z')
+ return 0;
+ index = name[2] - 'a';
+ if (name[3] < '1' || name[3] >= ('1' + CYGNUM_REDBOOT_MAX_PARTITIONS))
+ return 0;
+ pindex = name[3] - '1';
+ if (name[4] != ':')
+ return 0;
+ *path = &name[5];
+ }
+#ifdef CYGSEM_REDBOOT_DISK_ISO9660
+ else if (name[0] == 'c' && name[1] == 'd') {
+ // CD drives
+ kind = DISK_IDE_CDROM;
+ if (name[2] < '0' || name[2] > '9')
+ return 0;
+ index = name[2] - '0';
+ if (name[3] != ':')
+ return 0;
+ *path = &name[4];
+ }
+#endif
+
+ if (kind) {
+ for (i = 0; i < CYGNUM_REDBOOT_MAX_DISKS; i++) {
+ if (disk_table[i].kind == kind && disk_table[i].index == index) {
+ *part = &disk_table[i].partitions[pindex];
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static const struct {
+ int kind;
+ const char *str;
+} systype_names[] = {
+ { SYSTYPE_FAT12, "FAT12" },
+ { SYSTYPE_FAT16_32M, "FAT16 <32M" },
+ { SYSTYPE_FAT16, "FAT16" },
+ { SYSTYPE_EXTENDED, "Extended" },
+ { SYSTYPE_LINUX_SWAP, "Linux Swap" },
+ { SYSTYPE_LINUX, "Linux" }
+};
+
+static const char *
+systype_name(int systype)
+{
+ int i;
+
+ for (i = 0; i < sizeof(systype_names)/sizeof(systype_names[0]); i++)
+ if (systype_names[i].kind == systype)
+ return systype_names[i].str;
+ return "Unknown";
+}
+
+// List disk partitions
+static void
+do_disks(int argc, char *argv[])
+{
+ int i, j;
+ disk_t *d;
+ partition_t *p;
+ char name[16];
+
+ for (i = 0, d = disk_table; i < disk_count; i++, d++) {
+ switch (d->kind) {
+ case DISK_IDE_HD:
+ for (j = 0, p = d->partitions;
+ j < CYGNUM_REDBOOT_MAX_PARTITIONS;
+ j++, p++) {
+ if (p->systype) {
+ diag_sprintf(name, "hd%c%d", 'a' + d->index, j+1);
+ diag_printf("%-8s %s\n", name, systype_name(p->systype));
+ }
+ }
+ break;
+ case DISK_IDE_CDROM:
+ diag_sprintf(name, "cd%d", d->index);
+ diag_printf("%-8s ISO9660\n", name);
+ break;
+ }
+ }
+}
+
+static void *fileptr;
+static partition_t *file_part;
+
+externC int
+disk_stream_open(connection_info_t *info, int *err)
+{
+ const char *filepath;
+ char *filename = info->filename;
+
+ // The filename is in <disk>:<path> format.
+ // Convert to a partition and path.
+ if (!disk_parse_filename(filename, &file_part, &filepath)) {
+ *err = diskerr_badname;
+ return -1;
+ }
+
+ if (file_part->disk->kind != DISK_IDE_CDROM && file_part->systype == 0) {
+ *err = diskerr_partition;
+ return -1;
+ }
+
+ if (file_part->funs == (fs_funs_t *)0) {
+ *err = diskerr_partition;
+ return -1;
+ }
+
+ fileptr = (file_part->funs->open)(file_part, filepath);
+ if (fileptr == NULL) {
+ *err = diskerr_open;
+ return -1;
+ }
+ return 0;
+}
+
+externC int
+disk_stream_read(char *buf, int size, int *err)
+{
+ int nread;
+
+ if ((nread = (file_part->funs->read)(fileptr, buf, size)) < 0) {
+ *err = diskerr_read;
+ return -1;
+ }
+ return nread;
+}
+
+externC void
+disk_stream_close(int *err)
+{
+ fileptr = NULL;
+}
+
+externC char *
+disk_error(int err)
+{
+ switch (err) {
+ case diskerr_badname:
+ return "Bad filename";
+ break;
+ case diskerr_partition:
+ return "Unsupported filesystem";
+ break;
+ case diskerr_open:
+ return "Can't open file";
+ break;
+ case diskerr_read:
+ return "Can't read file";
+ break;
+ default:
+ return "Unknown error";
+ break;
+ }
+}
+
+//
+// RedBoot interface
+//
+GETC_IO_FUNCS(disk_io, disk_stream_open, disk_stream_close,
+ 0, disk_stream_read, disk_error);
+RedBoot_load(disk, disk_io, true, true, 0);
diff --git a/ecos/packages/redboot/current/src/fs/e2fs.c b/ecos/packages/redboot/current/src/fs/e2fs.c
new file mode 100644
index 0000000000..3b37ede8f8
--- /dev/null
+++ b/ecos/packages/redboot/current/src/fs/e2fs.c
@@ -0,0 +1,613 @@
+//==========================================================================
+//
+// e2fs.c
+//
+// RedBoot support for second extended filesystem
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas <gary@mind.be>
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): msalter
+// Contributors: msalter
+// Date: 2001-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <fs/disk.h>
+#include <fs/e2fs.h>
+
+#define DEBUG_E2FS 0
+
+#if DEBUG_E2FS > 4
+static void dump_sb(struct e2fs_super_block *s);
+static void dump_inode(struct e2fs_inode *i);
+#endif
+
+static void *e2fs_open(partition_t *p, const char *path);
+static int e2fs_read(void *fp, char *buf, cyg_uint32 nbytes);
+
+// This structure is the only thing exported by this module.
+// These filesystem function pointers are attached to disk
+// partitions in the generic disk handling code.
+//
+fs_funs_t redboot_e2fs_funs = {
+ e2fs_open,
+ e2fs_read
+};
+
+// A single block buffer to be shared carefully.
+static cyg_uint32 blockbuf[E2FS_MAX_BLOCK_SIZE/sizeof(cyg_uint32)];
+
+#define __READ_BLOCK(n) \
+ PARTITION_READ(e2fs->part, E2FS_BLOCK_TO_SECTOR(e2fs, (n)), \
+ blockbuf, e2fs->blocksize/SECTOR_SIZE)
+
+// Get a group descriptor. Returns non-zero for success.
+//
+static int
+e2fs_get_gdesc(e2fs_desc_t *e2fs, cyg_uint32 group_nr, e2fs_group_t *gdesc)
+{
+ cyg_uint32 sec_nr;
+
+ if (group_nr < e2fs->gdesc_first ||
+ group_nr >= (e2fs->gdesc_first + E2FS_GDESC_CACHE_SIZE)) {
+
+ // cache miss
+ sec_nr = E2FS_BLOCK_TO_SECTOR(e2fs, e2fs->gdesc_block);
+ sec_nr += (group_nr / E2FS_GDESC_PER_SECTOR);
+
+#if DEBUG_E2FS > 2
+ diag_printf("%s: group[%d] cache miss, sec_nr[%d]\n",
+ __FUNCTION__, group_nr, sec_nr);
+#endif
+ if (!PARTITION_READ(e2fs->part, sec_nr, (cyg_uint32 *)e2fs->gdesc_cache,
+ sizeof(e2fs->gdesc_cache)/SECTOR_SIZE))
+ return 0;
+
+ e2fs->gdesc_first = (group_nr / E2FS_GDESC_CACHE_SIZE) * E2FS_GDESC_CACHE_SIZE;
+ }
+ *gdesc = e2fs->gdesc_cache[group_nr - e2fs->gdesc_first];
+
+ return 1;
+}
+
+// Read the requested inode from disk. Return non-zero if successful
+//
+static int
+e2fs_get_inode(e2fs_desc_t *e2fs, int ino, e2fs_inode_t *ip)
+{
+ cyg_uint32 offset, sec_nr, buf[SECTOR_SIZE/sizeof(cyg_uint32)];
+ e2fs_group_t gdesc;
+
+ // get descriptor for group which this inode belongs to
+ if (!e2fs_get_gdesc(e2fs, (ino - 1) / e2fs->inodes_per_group, &gdesc))
+ return 0;
+ if (gdesc.inode_table == 0)
+ return 0;
+
+ // byte offset within group inode table
+ offset = ((ino - 1) % e2fs->inodes_per_group) * sizeof(struct e2fs_inode);
+
+ // figure out which sector holds the inode
+ sec_nr = E2FS_BLOCK_TO_SECTOR(e2fs, SWAB_LE32(gdesc.inode_table));
+ sec_nr += offset / SECTOR_SIZE;
+
+ // and the offset within that sector.
+ offset %= SECTOR_SIZE;
+
+#if DEBUG_E2FS > 0x08
+ diag_printf("%s: ino[%d], sec_nr[%d] offset[%d]\n", __FUNCTION__,
+ ino, sec_nr, offset);
+#endif
+
+ if (!PARTITION_READ(e2fs->part, sec_nr, buf, 1))
+ return 0;
+
+ *ip = *(e2fs_inode_t *)((char *)buf + offset);
+
+#if DEBUG_E2FS > 0
+ diag_printf("%s: inode size[%d]\n", __FUNCTION__, SWAB_LE32(ip->size));
+#endif
+
+ return 1;
+}
+
+// Mount an e2fs filesystem on the given partition.
+// Return 0 if successful.
+//
+static int
+e2fs_mount(partition_t *part, e2fs_desc_t *e2fs)
+{
+ int sb_block = 1;
+ cyg_uint32 sb_buf[E2FS_MIN_BLOCK_SIZE/sizeof(cyg_uint32)];
+ struct e2fs_super_block *sb = (struct e2fs_super_block *)sb_buf;
+
+ e2fs->part = part;
+
+ if (!PARTITION_READ(part, sb_block*(E2FS_MIN_BLOCK_SIZE/SECTOR_SIZE),
+ (cyg_uint32 *)sb, E2FS_MIN_BLOCK_SIZE/SECTOR_SIZE))
+ return -1;
+
+ if (SWAB_LE16(sb->magic) != E2FS_SUPER_MAGIC) {
+ diag_printf("ext2_mount: bad magic 0x%x\n", SWAB_LE16(sb->magic));
+ return -1;
+ }
+
+ // save some stuff for easy access
+ e2fs->blocksize = E2FS_BLOCK_SIZE(sb);
+ e2fs->nr_ind_blocks = (e2fs)->blocksize / sizeof(cyg_uint32);
+ e2fs->nr_dind_blocks = e2fs->nr_ind_blocks * ((e2fs)->blocksize / sizeof(cyg_uint32));
+ e2fs->nr_tind_blocks = e2fs->nr_dind_blocks * ((e2fs)->blocksize / sizeof(cyg_uint32));
+ e2fs->blocks_per_group = SWAB_LE32(sb->blocks_per_group);
+ e2fs->ngroups = (SWAB_LE32(sb->blocks_count) + e2fs->blocks_per_group - 1) /
+ e2fs->blocks_per_group;
+ e2fs->inodes_per_group = SWAB_LE32(sb->inodes_per_group);
+
+ // Find the group descriptors which follow superblock
+ e2fs->gdesc_block = ((sb_block * E2FS_MIN_BLOCK_SIZE) / e2fs->blocksize) + 1;
+ e2fs->gdesc_first = 0; // cache group 0 initially
+
+ if (!PARTITION_READ(part, E2FS_BLOCK_TO_SECTOR(e2fs,e2fs->gdesc_block),
+ (cyg_uint32 *)e2fs->gdesc_cache, 1))
+ return -1;
+
+#if DEBUG_E2FS > 1
+ diag_printf("E2FS superblock:\n");
+ diag_printf(" [%d] inodes\n", SWAB_LE32(sb->inodes_count));
+ diag_printf(" [%d] blocks\n", SWAB_LE32(sb->blocks_count));
+ diag_printf(" [%d] blocksize\n", e2fs->blocksize);
+ diag_printf(" [%d] blocks per group\n", e2fs->blocks_per_group);
+ diag_printf(" [%d] ngroups\n", e2fs->ngroups);
+#endif
+
+#if DEBUG_E2FS > 4
+ dump_sb(sb);
+#endif
+
+ return 0;
+}
+
+// Convert a block index into inode data into a block_nr.
+// If successful, store block number in pblknr and return non-zero.
+//
+// NB: This needs some block/sector caching to be speedier. But
+// that takes memory and speed is not too bad now for files
+// small enough to avoid double and triple indirection.
+//
+static int
+e2fs_inode_block(e2fs_desc_t *e2fs, e2fs_inode_t *inode,
+ cyg_uint32 bindex, cyg_uint32 *pblknr)
+{
+ if (bindex < E2FS_NR_DIR_BLOCKS) {
+ *pblknr = SWAB_LE32(inode->block[bindex]);
+ return 1;
+ }
+ bindex -= E2FS_NR_DIR_BLOCKS;
+
+ if (bindex < e2fs->nr_ind_blocks) {
+ // Indirect block
+ if (!__READ_BLOCK(SWAB_LE32(inode->block[E2FS_IND_BLOCK])))
+ return 0;
+ *pblknr = SWAB_LE32(blockbuf[bindex]);
+ return 1;
+ }
+ bindex -= e2fs->nr_ind_blocks;
+
+ if (bindex < e2fs->nr_dind_blocks) {
+ // Double indirect block
+ if (!__READ_BLOCK(SWAB_LE32(inode->block[E2FS_DIND_BLOCK])))
+ return 0;
+ if (!__READ_BLOCK(SWAB_LE32(blockbuf[bindex / e2fs->nr_ind_blocks])))
+ return 0;
+ *pblknr = SWAB_LE32(blockbuf[bindex % e2fs->nr_ind_blocks]);
+ return 1;
+ }
+ bindex -= e2fs->nr_dind_blocks;
+
+ // Triple indirect block
+ if (!__READ_BLOCK(SWAB_LE32(inode->block[E2FS_TIND_BLOCK])))
+ return 0;
+ if (!__READ_BLOCK(SWAB_LE32(blockbuf[bindex / e2fs->nr_dind_blocks])))
+ return 0;
+ bindex %= e2fs->nr_dind_blocks;
+ if (!__READ_BLOCK(SWAB_LE32(blockbuf[bindex / e2fs->nr_ind_blocks])))
+ return 0;
+ *pblknr = SWAB_LE32(blockbuf[bindex % e2fs->nr_ind_blocks]);
+ return 1;
+}
+
+
+// search a single directory block in memory looking for an
+// entry with the given name. Return pointer to entry if
+// found, NULL if not.
+//
+static e2fs_dir_entry_t *
+search_dir_block(e2fs_desc_t *e2fs, cyg_uint32 *blkbuf,
+ const char *name, int namelen)
+{
+ e2fs_dir_entry_t *dir;
+ cyg_uint16 reclen, len;
+ cyg_uint32 offset;
+
+#if DEBUG_E2FS > 0
+ diag_dump_buf(blkbuf, e2fs->blocksize);
+#endif
+ offset = 0;
+ while (offset < e2fs->blocksize) {
+ dir = (e2fs_dir_entry_t *)((char *)blkbuf + offset);
+ reclen = SWAB_LE16(dir->reclen);
+ offset += reclen;
+ len = dir->namelen;
+
+ // terminate on anything which doesn't make sense
+ if (reclen < 8 || (len + 8) > reclen || offset > (e2fs->blocksize + 1))
+ return NULL;
+
+ if (dir->inode && len == namelen && !strncmp(dir->name, name, len))
+ return dir;
+ }
+ return NULL;
+}
+
+
+// Look in the given directory for an entry with the given name.
+// If found, return a pointer to that entry. Return NULL if not
+// found.
+//
+static e2fs_dir_entry_t *
+e2fs_dir_lookup(e2fs_desc_t *e2fs, cyg_uint32 dir_ino,
+ const char *name, int namelen)
+{
+ e2fs_inode_t inode;
+ e2fs_dir_entry_t *dir;
+ cyg_uint32 nblocks, last_block_size, i, block_nr, nbytes;
+
+#if DEBUG_E2FS > 0
+ diag_printf("%s: looking for %s [%d] in ino[%d]\n",
+ __FUNCTION__, name, namelen, dir_ino);
+#endif
+
+ if (!e2fs_get_inode(e2fs, dir_ino, &inode)) {
+#if DEBUG_E2FS > 0
+ diag_printf("%s: e2fs_get_inode [%d] failed\n", __FUNCTION__, dir_ino);
+#endif
+ return NULL;
+ }
+
+ nbytes = SWAB_LE32(inode.size);
+ nblocks = (nbytes + e2fs->blocksize - 1) / e2fs->blocksize;
+
+ last_block_size = nbytes % e2fs->blocksize;
+ if (last_block_size == 0)
+ last_block_size = e2fs->blocksize;
+
+ for (i = 0; i < nblocks; i++) {
+ if (!e2fs_inode_block(e2fs, &inode, i, &block_nr))
+ return NULL;
+
+ if (block_nr) {
+ if (!__READ_BLOCK(block_nr))
+ return NULL;
+ } else
+ memset(blockbuf, 0, e2fs->blocksize);
+
+ dir = search_dir_block(e2fs, blockbuf, name, namelen);
+
+ if (dir != NULL)
+ return dir;
+ }
+ return NULL;
+}
+
+typedef struct ino_info {
+ cyg_uint32 ino;
+ cyg_uint32 parent_ino;
+ cyg_uint8 filetype;
+} ino_info_t;
+
+static int e2fs_inode_lookup(e2fs_desc_t *e2fs, cyg_uint32 dir_ino,
+ const char *pathname, ino_info_t *info);
+
+// Starting from the given directory, find the inode number, filetype, and
+// parent inode for the file pointed to by the given symbolic link inode.
+// If successful, fills out ino_info_t and return true.
+//
+static int
+e2fs_follow_symlink(e2fs_desc_t *e2fs, cyg_uint32 dir_ino, cyg_uint32 sym_ino, ino_info_t *info)
+{
+#define MAX_SYMLINK_NAME 255
+ char symlink[MAX_SYMLINK_NAME+1];
+ int pathlen;
+ cyg_uint32 block_nr;
+ e2fs_inode_t inode;
+
+ if (!e2fs_get_inode(e2fs, sym_ino, &inode)) {
+#if DEBUG_E2FS > 0
+ diag_printf("%s: e2fs_get_inode [%d] failed\n", __FUNCTION__, sym_ino);
+#endif
+ return 0;
+ }
+
+ pathlen = SWAB_LE32(inode.size);
+ if (pathlen > MAX_SYMLINK_NAME)
+ return 0;
+
+ if (inode.blocks) {
+ if (!e2fs_inode_block(e2fs, &inode, 0, &block_nr))
+ return 0;
+ if (block_nr) {
+ if (!PARTITION_READ(e2fs->part, E2FS_BLOCK_TO_SECTOR(e2fs, block_nr),
+ blockbuf, e2fs->blocksize/SECTOR_SIZE))
+ return 0;
+ memcpy(symlink, blockbuf, pathlen);
+ } else
+ return 0;
+ } else {
+ // small enough path to fit in inode struct
+ memcpy(symlink, (char *)&inode.block[0], pathlen);
+ }
+ symlink[pathlen] = 0;
+
+ return e2fs_inode_lookup(e2fs, dir_ino, symlink, info);
+}
+
+
+// Starting from the given directory, find the inode number, filetype, and
+// parent inode for the given file pathname.
+// If successful, fills out ino_info_t and return true.
+//
+static int
+e2fs_inode_lookup(e2fs_desc_t *e2fs, cyg_uint32 dir_ino, const char *pathname, ino_info_t *info)
+{
+ int len, pathlen;
+ const char *p;
+ e2fs_dir_entry_t *dir = NULL;
+
+ if (!pathname || (pathlen = strlen(pathname)) == 0)
+ return 0;
+
+ if (*pathname == '/') {
+ if (--pathlen == 0) {
+ info->ino = info->parent_ino = E2FS_ROOT_INO;
+ info->filetype = E2FS_FTYPE_DIR;
+ return 1;
+ }
+ ++pathname;
+ dir_ino = E2FS_ROOT_INO;
+ }
+
+ while (pathlen) {
+ // find next delimiter in path.
+ for (p = pathname, len = 0; len < pathlen; len++, p++) {
+ // skip delimiter if found.
+ if (*p == '/') {
+ ++p;
+ --pathlen;
+ break;
+ }
+ }
+ dir = e2fs_dir_lookup(e2fs, dir_ino, pathname, len);
+ if (dir == NULL)
+ return 0;
+
+ pathlen -= len;
+ pathname = p;
+
+ switch (dir->filetype) {
+ case E2FS_FTYPE_SYMLINK:
+ // follow the symbolic link (this will cause recursion)
+ if (!e2fs_follow_symlink(e2fs, dir_ino, SWAB_LE32(dir->inode), info))
+ return 0;
+ if (pathlen == 0)
+ return 1;
+ // must be a dir if we want to continue
+ if (info->filetype != E2FS_FTYPE_DIR)
+ return 0;
+ dir_ino = info->ino;
+ break;
+
+ case E2FS_FTYPE_DIR:
+ if (pathlen)
+ dir_ino = SWAB_LE32(dir->inode);
+ break;
+
+ case E2FS_FTYPE_REG_FILE:
+ if (pathlen)
+ return 0; // regular file embedded in middle of path
+ break;
+
+ case E2FS_FTYPE_UNKNOWN:
+ case E2FS_FTYPE_CHRDEV:
+ case E2FS_FTYPE_BLKDEV:
+ case E2FS_FTYPE_FIFO:
+ case E2FS_FTYPE_SOCK:
+ default:
+ return 0;
+ }
+ }
+ info->ino = SWAB_LE32(dir->inode);
+ info->parent_ino = dir_ino;
+ info->filetype = dir->filetype;
+ return 1;
+}
+
+struct read_info {
+ e2fs_desc_t e2fs_desc;
+ e2fs_inode_t inode;
+ cyg_uint32 fsize;
+ cyg_uint32 fpos;
+};
+
+static void *
+e2fs_open(partition_t *p, const char *filepath)
+{
+ static struct read_info rinfo;
+ ino_info_t ino_info;
+
+ // mount partition
+ if (e2fs_mount(p, &rinfo.e2fs_desc) != 0) {
+ diag_printf("mount failed.\n");
+ return NULL;
+ }
+
+ // find file inode
+ if (!e2fs_inode_lookup(&rinfo.e2fs_desc, E2FS_ROOT_INO, filepath, &ino_info)) {
+ diag_printf("%s: e2fs_inode_lookup failed\n", __FUNCTION__);
+ return NULL;
+ }
+
+ // read inode
+ if (!e2fs_get_inode(&rinfo.e2fs_desc, ino_info.ino, &rinfo.inode)) {
+ diag_printf("%s: e2fs_get_inode failed for ino[%d]\n", __FUNCTION__, ino_info.ino);
+ return NULL;
+ }
+
+ rinfo.fsize = SWAB_LE32(rinfo.inode.size);
+ rinfo.fpos = 0;
+
+ return &rinfo;
+}
+
+static int
+e2fs_read(void *fp, char *buf, cyg_uint32 nbytes)
+{
+ struct read_info *info = fp;
+ e2fs_desc_t *e2fs;
+ cyg_uint32 nread = 0, rem, block_nr, bindex, to_read;
+
+ if ((info->fpos + nbytes) > info->fsize)
+ nbytes = info->fsize - info->fpos;
+
+ e2fs = &info->e2fs_desc;
+
+ // see if we need to copy leftover data from last read call
+ rem = e2fs->blocksize - (info->fpos % e2fs->blocksize);
+ if (rem != e2fs->blocksize) {
+ char *p = (char *)blockbuf + e2fs->blocksize - rem;
+
+ if (rem > nbytes)
+ rem = nbytes;
+
+ memcpy(buf, p, rem);
+
+ nread += rem;
+ buf += rem;
+ info->fpos += rem;
+ }
+
+ // now loop through blocks if we're not done
+ bindex = info->fpos / e2fs->blocksize;
+ while (nread < nbytes) {
+ if (!e2fs_inode_block(e2fs, &info->inode, bindex, &block_nr))
+ return -1;
+
+ if (block_nr) {
+ if (!PARTITION_READ(e2fs->part, E2FS_BLOCK_TO_SECTOR(e2fs, block_nr),
+ blockbuf, e2fs->blocksize/SECTOR_SIZE))
+ return 0;
+ } else
+ memset(blockbuf, 0, e2fs->blocksize);
+
+ to_read = nbytes - nread;
+ if (to_read > e2fs->blocksize)
+ to_read = e2fs->blocksize;
+
+ memcpy(buf, blockbuf, to_read);
+
+ nread += to_read;
+ buf += to_read;
+ info->fpos += to_read;
+ ++bindex;
+ }
+
+ return nread;
+}
+
+#if DEBUG_E2FS > 4
+static void dump_sb(struct e2fs_super_block *s)
+{
+ diag_printf("inode_count: %d\n", SWAB_LE32(s->inodes_count));
+ diag_printf("blocks_count: %d\n", SWAB_LE32(s->blocks_count));
+ diag_printf("r_blocks_count: %d\n", SWAB_LE32(s->r_blocks_count));
+ diag_printf("free_blocks_count: %d\n", SWAB_LE32(s->free_blocks_count));
+ diag_printf("free_inodes_count: %d\n", SWAB_LE32(s->free_inodes_count));
+ diag_printf("first_data_block: %d\n", SWAB_LE32(s->first_data_block));
+ diag_printf("log_block_size: %d\n", SWAB_LE32(s->log_block_size));
+ diag_printf("log_frag_size: %d\n", SWAB_LE32(s->log_frag_size));
+ diag_printf("blocks_per_group: %d\n", SWAB_LE32(s->blocks_per_group));
+ diag_printf("frags_per_group: %d\n", SWAB_LE32(s->frags_per_group));
+ diag_printf("inodes_per_group: %d\n", SWAB_LE32(s->inodes_per_group));
+ diag_printf("mnt_count: %d\n", SWAB_LE16(s->mnt_count));
+ diag_printf("max_mnt_count: %d\n", SWAB_LE16(s->max_mnt_count));
+ diag_printf("magic: %d\n", SWAB_LE16(s->magic));
+ diag_printf("state: %d\n", SWAB_LE16(s->state));
+ diag_printf("errors: %d\n", SWAB_LE16(s->errors));
+ diag_printf("minor_rev_level: %d\n", SWAB_LE16(s->minor_rev_level));
+ diag_printf("lastcheck: %d\n", SWAB_LE32(s->lastcheck));
+ diag_printf("checkinterval: %d\n", SWAB_LE32(s->checkinterval));
+ diag_printf("creator_os: %d\n", SWAB_LE32(s->creator_os));
+ diag_printf("rev_level: %d\n", SWAB_LE32(s->rev_level));
+}
+
+static void dump_inode(struct e2fs_inode *i)
+{
+ int j, n;
+
+ diag_printf("mode: %o\n", SWAB_LE16(i->mode));
+ diag_printf("uid: %o\n", SWAB_LE16(i->uid));
+ diag_printf("size: %d\n", SWAB_LE32(i->size));
+ diag_printf("gid: %o\n", SWAB_LE16(i->gid));
+ diag_printf("links: %d\n", SWAB_LE16(i->links_count));
+ diag_printf("blocks: %d\n", SWAB_LE32(i->blocks));
+
+ n = i->blocks;
+ if (n > E2FS_N_BLOCKS)
+ n = E2FS_N_BLOCKS;
+
+ for (j = 0; j < n; j++)
+ diag_printf(" block: %d\n", SWAB_LE32(i->block[j]));
+}
+#endif
+
+
diff --git a/ecos/packages/redboot/current/src/fs/fileio.c b/ecos/packages/redboot/current/src/fs/fileio.c
new file mode 100644
index 0000000000..98d6576e54
--- /dev/null
+++ b/ecos/packages/redboot/current/src/fs/fileio.c
@@ -0,0 +1,311 @@
+//==========================================================================
+//
+// fileio.c
+//
+// RedBoot fileio support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002, 2003, 2004 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): dwmw2, msalter
+// Date: 2003-11-27
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// Shoot me. But I don't want struct timeval because redboot provides it.
+#define _POSIX_SOURCE
+#include <time.h>
+#undef _POSIX_SOURCE
+
+#include <redboot.h>
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef CYGPKG_IO_FLASH
+#include <cyg/io/io.h>
+#include <cyg/io/flash.h>
+#include <cyg/io/config_keys.h>
+#endif
+#include <cyg/fileio/fileio.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+static void do_mount(int argc, char *argv[]);
+static void do_umount(int argc, char *argv[]);
+
+#ifdef CYGPKG_IO_FLASH_BLOCK_DEVICE
+#define FLASHPART "[-f <partition>] "
+#else
+#define FLASHPART
+#endif
+
+RedBoot_cmd("mount",
+ "Mount file system",
+ FLASHPART "[-d <device>] -t fstype",
+ do_mount
+ );
+RedBoot_cmd("umount",
+ "Unmount file system",
+ "",
+ do_umount
+ );
+
+int fileio_mounted = 0;
+
+// Mount disk/filesystem
+static void
+do_mount(int argc, char *argv[])
+{
+ char *part_str, *dev_str, *type_str;
+ bool part_set = false, dev_set = false, type_set = false;
+ struct option_info opts[3];
+ int err, num_opts = 2;
+
+ init_opts(&opts[0], 'd', true, OPTION_ARG_TYPE_STR,
+ (void *)&dev_str, &dev_set, "device");
+ init_opts(&opts[1], 't', true, OPTION_ARG_TYPE_STR,
+ (void *)&type_str, &type_set, "fstype");
+#ifdef CYGPKG_IO_FLASH_BLOCK_DEVICE
+ init_opts(&opts[2], 'f', true, OPTION_ARG_TYPE_STR,
+ (void *)&part_str, &part_set, "partition");
+ num_opts++;
+#endif
+
+ CYG_ASSERT(num_opts <= NUM_ELEMS(opts), "Too many options");
+
+ if (!scan_opts(argc, argv, 1, opts, num_opts, NULL, 0, NULL))
+ return;
+
+ if (!type_set) {
+ diag_printf("Must specify file system type\n");
+ return;
+ }
+ if (fileio_mounted) {
+ diag_printf("A file system is already mounted\n");
+ return;
+ }
+#ifdef CYGPKG_IO_FLASH_BLOCK_DEVICE
+ if (part_set) {
+ int len;
+ cyg_io_handle_t h;
+
+ if (dev_set && strcmp(dev_str, CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1)) {
+ diag_printf("May only set one of <device> or <partition>\n");
+ return;
+ }
+
+ dev_str = CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1;
+ len = strlen(part_str);
+
+ err = cyg_io_lookup(dev_str, &h);
+ if (err < 0) {
+ diag_printf("cyg_io_lookup of \"%s\" returned %d\n", err);
+ return;
+ }
+ err = cyg_io_set_config(h, CYG_IO_SET_CONFIG_FLASH_FIS_NAME,
+ part_str, &len);
+ if (err < 0) {
+ diag_printf("FIS partition \"%s\" not found\n",
+ part_str);
+ return;
+ }
+ }
+#endif
+ err = mount(dev_str, "/", type_str);
+
+ if (err) {
+ diag_printf("Mount failed %d\n", err);
+ } else {
+// diag_printf("Mount %s file system succeeded\n", type_str);
+ fileio_mounted = 1;
+#ifdef CYGBLD_REDBOOT_FILEIO_WITH_LS
+ chdir("/");
+#endif
+ }
+}
+
+static void
+do_umount(int argc, char *argv[])
+{
+ if (!fileio_mounted) {
+ return;
+ }
+ umount ("/");
+ fileio_mounted = 0;
+}
+
+#ifdef CYGBLD_REDBOOT_FILEIO_WITH_LS
+#include <dirent.h>
+
+static char rwx[8][4] = { "---", "r--", "-w-", "rw-", "--x", "r-x", "-wx", "rwx" };
+
+static void
+do_ls(int argc, char * argv[])
+{
+ char * dir_str;
+ struct option_info opts[1];
+ bool dir_set = false;
+ DIR *dirp;
+ char cwd[PATH_MAX];
+ char filename[PATH_MAX];
+ struct stat sbuf;
+ int err;
+
+ init_opts(&opts[0], 'd', true, OPTION_ARG_TYPE_STR,
+ (void *)&dir_str, &dir_set, "directory");
+
+ if (!fileio_mounted) {
+ diag_printf("No filesystem mounted\n");
+ return;
+ }
+
+ if (!scan_opts(argc, argv, 1, opts, 1, NULL, 0, NULL))
+ return;
+
+ if (!dir_set) {
+ getcwd(cwd,sizeof(cwd));
+ dir_str = cwd;
+ }
+
+ diag_printf("directory %s\n",dir_str);
+ dirp = opendir(dir_str);
+ if (dirp==NULL) {
+ diag_printf("no such directory %s\n",dir_str);
+ return;
+ }
+
+ for (;;) {
+ struct dirent *entry = readdir(dirp);
+
+ if( entry == NULL )
+ break;
+
+ strcpy(filename, dir_str);
+ strcat(filename, "/");
+ strcat(filename, entry->d_name);
+
+ err = stat(filename, &sbuf);
+ if (err < 0) {
+ diag_printf("Unable to stat file %s\n", filename);
+ continue;
+ }
+ diag_printf("%4d ", sbuf.st_ino);
+ if (S_ISDIR(sbuf.st_mode)) diag_printf("d");
+ if (S_ISCHR(sbuf.st_mode)) diag_printf("c");
+ if (S_ISBLK(sbuf.st_mode)) diag_printf("b");
+ if (S_ISREG(sbuf.st_mode)) diag_printf("-");
+ if (S_ISLNK(sbuf.st_mode)) diag_printf("l");
+ diag_printf("%s%s%s", // Ho, humm, have to hard code the shifts
+ rwx[(sbuf.st_mode & S_IRWXU) >> 16],
+ rwx[(sbuf.st_mode & S_IRWXG) >> 19],
+ rwx[(sbuf.st_mode & S_IRWXO) >> 22]);
+ diag_printf(" %2d size %6d %s\n",
+ sbuf.st_nlink,sbuf.st_size,
+ entry->d_name);
+ }
+
+ closedir(dirp);
+ return;
+}
+
+RedBoot_cmd("ls",
+ "list directory contents",
+ "[-d directory]",
+ do_ls
+ );
+
+#endif // CYGBLD_REDBOOT_FILEIO_WITH_LS
+static int fd;
+
+externC int
+fileio_stream_open(connection_info_t *info, int *err)
+{
+ char *filename = info->filename;
+
+ if (!fileio_mounted) {
+ diag_printf("No file system mounted\n");
+ return -1;
+ }
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ diag_printf("Open failed, error %d\n", errno);
+ return -1;
+ }
+ return 0;
+}
+
+externC int
+fileio_stream_read(char *buf, int size, int *err)
+{
+ int nread;
+
+ if ((nread = read(fd, buf, size)) < 0) {
+ *err = errno;
+ return -1;
+ }
+ return nread;
+}
+
+externC void
+fileio_stream_close(int *err)
+{
+ close(fd);
+}
+
+externC char *
+fileio_error(int err)
+{
+ static char myerr[10];
+
+ diag_sprintf(myerr, "error %d\n", err);
+ return myerr;
+}
+
+//
+// RedBoot interface
+//
+GETC_IO_FUNCS(fileio_io, fileio_stream_open, fileio_stream_close,
+ 0, fileio_stream_read, fileio_error);
+RedBoot_load(file, fileio_io, true, true, 0);
+
diff --git a/ecos/packages/redboot/current/src/fs/ide.c b/ecos/packages/redboot/current/src/fs/ide.c
new file mode 100644
index 0000000000..1b361e335c
--- /dev/null
+++ b/ecos/packages/redboot/current/src/fs/ide.c
@@ -0,0 +1,529 @@
+//==========================================================================
+//
+// ide.c
+//
+// RedBoot IDE support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas <gary@mind.be>
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): msalter
+// Contributors: msalter
+// Date: 2001-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <cyg/hal/hal_io.h>
+#include <fs/disk.h>
+#include <fs/ide.h>
+
+static int ide_read(struct disk *d,
+ cyg_uint32 start_sector,
+ cyg_uint32 *buf,
+ cyg_uint8 nr_sectors);
+
+static disk_funs_t ide_funs = { ide_read };
+
+static struct ide_priv ide_privs[HAL_IDE_NUM_CONTROLLERS * 2];
+
+static inline void
+__wait_for_ready(int ctlr)
+{
+ cyg_uint8 status;
+ do {
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
+ } while (status & (IDE_STAT_BSY | IDE_STAT_DRQ));
+}
+
+static inline int
+__wait_for_drq(int ctlr)
+{
+ cyg_uint8 status;
+ cyg_ucount32 tries;
+
+ CYGACC_CALL_IF_DELAY_US(10);
+ for (tries=0; tries<1000000; tries++) {
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
+ if (!(status & IDE_STAT_BSY)) {
+ if (status & IDE_STAT_DRQ)
+ return 1;
+ else
+ return 0;
+ }
+ }
+}
+
+static int
+ide_reset(int ctlr)
+{
+ cyg_uint8 status;
+ int delay;
+//
+// VMware note:
+// VMware virtual IDE device handler obviously expects that
+// the reset and setup functions were already done
+// by it's bios and complais if one uses reset here...
+//
+#ifndef CYGSEM_REDBOOT_DISK_IDE_VMWARE
+ HAL_IDE_WRITE_CONTROL(ctlr, 6); // polled mode, reset asserted
+ CYGACC_CALL_IF_DELAY_US(5000);
+ HAL_IDE_WRITE_CONTROL(ctlr, 2); // polled mode, reset cleared
+ CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
+#endif
+
+ // wait 30 seconds max for not busy and drive ready
+ for (delay = 0; delay < 300; ++delay) {
+ CYGACC_CALL_IF_DELAY_US((cyg_uint32)100000);
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
+ if (!(status & IDE_STAT_BSY)) {
+ if (status & IDE_STAT_DRDY) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+// Return true if any devices attached to controller
+static int
+ide_presence_detect(int ctlr)
+{
+ cyg_uint8 sel, val;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ sel = (i << 4) | 0xA0;
+ CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, sel);
+ CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_DEVICE, val);
+ if (val == sel) {
+#ifndef CYGSEM_REDBOOT_DISK_IDE_VMWARE
+ if (i)
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, 0);
+#endif
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+ide_ident(int ctlr, int dev, int is_packet_dev, cyg_uint16 *buf)
+{
+ int i;
+
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, is_packet_dev ? 0xA1 : 0xEC);
+ CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
+
+ if (!__wait_for_drq(ctlr))
+ return 0;
+
+ for (i = 0; i < (SECTOR_SIZE / sizeof(cyg_uint16)); i++, buf++)
+ HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
+
+ return 1;
+}
+
+static int
+ide_read_sectors(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf)
+{
+ int i, j;
+ cyg_uint16 *p;
+
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, count);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >> 8) & 0xff);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI, (start >> 16) & 0xff);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE,
+ ((start >> 24) & 0xf) | (dev << 4) | 0x40);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x20);
+
+ for(p = buf, i = 0; i < count; i++) {
+
+ if (!__wait_for_drq(ctlr)) {
+ diag_printf("%s: NO DRQ for ide%d, device %d.\n",
+ __FUNCTION__, ctlr, dev);
+ return 0;
+ }
+
+ for (j = 0; j < (SECTOR_SIZE / sizeof(cyg_uint16)); j++, p++)
+ HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *p);
+ }
+ return 1;
+}
+
+// max number of sectors to xfer during a single packet command
+#define MAX_CD_XFER 16
+
+static inline int
+send_packet_command(int ctlr, int dev, cyg_uint16 len, cyg_uint16 *pkt, int pktlen)
+{
+ int i;
+ cyg_uint8 status, reason;
+
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_FEATURES, 0);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 0);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, 0);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, len & 0xff);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI, (len >> 8) & 0xff);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
+ HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0xA0);
+
+ if (!__wait_for_drq(ctlr)) {
+ diag_printf("%s: NO DRQ for ide%d, device %d.\n",
+ __FUNCTION__, ctlr, dev);
+ return 0;
+ }
+
+ // send packet
+ for (i = 0; i < (pktlen/sizeof(cyg_uint16)); i++)
+ HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, pkt[i]);
+
+ // wait for not busy transferring packet
+ do {
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason);
+
+ if ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ)
+ if (reason & IDE_REASON_COD)
+ continue; // still wanting packet data (should timeout here)
+
+ } while (status & IDE_STAT_BSY);
+
+ return 1;
+}
+
+#define READ_COUNT(x) \
+ { unsigned char tmp; \
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_LBAMID, tmp); \
+ (x) = tmp; \
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_LBAHI, tmp); \
+ (x) = (x) | (tmp << 8); \
+ }
+
+
+// Read the sense data
+static int
+request_sense(int ctlr, int dev, cyg_uint16 count, cyg_uint16 *buf)
+{
+ int i;
+ cyg_uint16 cdcount, pkt[6];
+ unsigned char status, *cpkt = (unsigned char *)pkt;
+
+
+ // Fill in REQUEST SENSE packet command block
+ memset(cpkt, 0, sizeof(pkt));
+ cpkt[0] = 0x03;
+ cpkt[4] = 254; // allocation length
+
+ if (!send_packet_command(ctlr, dev, count, pkt, sizeof(pkt)))
+ return 0;
+
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
+ if (!(status & IDE_STAT_DRQ)) {
+ if (status & IDE_STAT_SERVICE) {
+ unsigned char reason;
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason);
+ diag_printf("%s: SERVICE request for ide%d, device %d, status[%02x], reason[%02x].\n",
+ __FUNCTION__, ctlr, dev, status, reason);
+ }
+ return 0;
+ }
+
+ READ_COUNT(cdcount);
+ if (cdcount != count)
+ diag_printf("%s: ide%d, dev%d: his cnt[%d] our count[%d].\n",
+ __FUNCTION__, ctlr, dev, cdcount, count);
+
+ for(i = 0; i < (cdcount / sizeof(*buf)); i++, buf++)
+ HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
+
+ // wait for not busy transferring data
+ do {
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
+ } while ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ);
+
+ return cdcount;
+}
+
+// Interpret the sense data
+static int
+handle_sense(int ctlr, int dev, cyg_uint8 count, cyg_uint16 *buf)
+{
+#if 0
+ unsigned char *p = (char *)buf;
+
+ diag_printf("%s: %d bytes:\n", __FUNCTION__, count);
+ diag_printf("sense key[%02x] additional sense[%02x]\n",
+ p[2], p[12]);
+#endif
+ return 1;
+}
+
+static int
+do_packet_read(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf)
+{
+ int i, retry_cnt;
+ cyg_uint16 cdcount, pkt[6], sense[127];
+ unsigned char status, *cpkt = (unsigned char *)pkt;
+
+ // get count number of whole cdrom sectors
+ while (count) {
+
+ retry_cnt = 3;
+
+ i = (count > MAX_CD_XFER) ? MAX_CD_XFER : count;
+
+ retry:
+ // Fill in READ(10) packet command block
+ memset(cpkt, 0, sizeof(pkt));
+ cpkt[0] = 0x28; // READ(10)
+ cpkt[2] = (start >> 24) & 0xff;
+ cpkt[3] = (start >> 16) & 0xff;
+ cpkt[4] = (start >> 8) & 0xff;
+ cpkt[5] = (start >> 0) & 0xff;
+ cpkt[7] = (i >> 8) & 0xff;
+ cpkt[8] = i & 0xff;
+
+ if (!send_packet_command(ctlr, dev, i * CDROM_SECTOR_SIZE,
+ pkt, sizeof(pkt)))
+ return 0;
+
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
+ if (!(status & IDE_STAT_DRQ)) {
+ if (status & IDE_STAT_SERVICE) {
+ unsigned char reason;
+ int sense_count;
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_REASON, reason);
+#if 1
+ diag_printf("%s: SERVICE request for ide%d, device %d, status[%02x], reason[%02x].\n",
+ __FUNCTION__, ctlr, dev, status, reason);
+#endif
+ sense_count = request_sense(ctlr, dev, sizeof(sense), sense);
+ if (sense_count) {
+ handle_sense(ctlr, dev, sense_count, sense);
+ if (retry_cnt--)
+ goto retry;
+ }
+ }
+ return 0;
+ }
+
+ count -= i;
+ start += i;
+
+ READ_COUNT(cdcount);
+ if (cdcount != (i * CDROM_SECTOR_SIZE))
+ diag_printf("%s: ide%d, dev%d: his cnt[%d] our count[%d].\n",
+ __FUNCTION__, ctlr, dev,
+ cdcount, i * CDROM_SECTOR_SIZE);
+
+ for(i = 0; i < (cdcount / sizeof(*buf)); i++, buf++)
+ HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
+
+ // wait for not busy transferring data
+ do {
+ HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
+ } while ((status & (IDE_STAT_BSY | IDE_STAT_DRQ)) == IDE_STAT_DRQ);
+ }
+ return 1;
+}
+
+
+static int
+ide_packet_read_sectors(int ctlr, int dev, cyg_uint32 start, cyg_uint8 count, cyg_uint16 *buf)
+{
+ int i, extra;
+ cyg_uint32 cdstart;
+ static cyg_uint16 cdsec_buf[CDROM_SECTOR_SIZE/sizeof(cyg_uint16)];
+
+ cdstart = (start + SECTORS_PER_CDROM_SECTOR-1) / SECTORS_PER_CDROM_SECTOR;
+
+ // align to cdrom sector boundary.
+ if (start % SECTORS_PER_CDROM_SECTOR) {
+ if (!ide_packet_read_sectors(ctlr, dev,
+ cdstart * SECTORS_PER_CDROM_SECTOR,
+ SECTORS_PER_CDROM_SECTOR, cdsec_buf))
+ return 0;
+
+ i = SECTORS_PER_CDROM_SECTOR - (start % SECTORS_PER_CDROM_SECTOR);
+ if (i > count)
+ i = count;
+ memcpy(buf, cdsec_buf + ((start % CDROM_SECTOR_SIZE) * SECTOR_SIZE),
+ i * SECTOR_SIZE);
+
+ count -= i;
+ buf += (i * SECTOR_SIZE) / sizeof(*buf);
+ ++cdstart;
+ }
+
+ extra = count % SECTORS_PER_CDROM_SECTOR;
+ count /= SECTORS_PER_CDROM_SECTOR;
+
+ if (count) {
+ if (!do_packet_read(ctlr, dev, cdstart, count, buf))
+ return 0;
+ buf += count * SECTORS_PER_CDROM_SECTOR * SECTOR_SIZE;
+ }
+
+ if (extra) {
+ // read cdrom sector
+ if (!ide_packet_read_sectors(ctlr, dev,
+ cdstart * SECTORS_PER_CDROM_SECTOR,
+ extra, cdsec_buf))
+ return 0;
+ memcpy(buf, cdsec_buf, extra * SECTOR_SIZE);
+ }
+
+ return 1;
+}
+
+static int
+ide_read(struct disk *d,
+ cyg_uint32 start_sec, cyg_uint32 *buf, cyg_uint8 nr_secs)
+{
+ struct ide_priv *p = (struct ide_priv *)(d->private);
+
+ if (p->flags & IDE_DEV_PACKET)
+ return ide_packet_read_sectors(p->controller, p->drive,
+ start_sec, nr_secs, (cyg_uint16 *)buf);
+
+ return ide_read_sectors(p->controller, p->drive,
+ start_sec, nr_secs, (cyg_uint16 *)buf);
+}
+
+
+static void
+ide_init(void)
+{
+ cyg_uint32 buf[SECTOR_SIZE/sizeof(cyg_uint32)], u32;
+ cyg_uint16 u16;
+ cyg_uint8 u8;
+ int i, j, num_controllers;
+ disk_t disk;
+ struct ide_priv *priv;
+
+#define DEV_INIT_VAL ((j << 4) | 0xA0)
+
+ num_controllers = HAL_IDE_INIT();
+
+ CYGACC_CALL_IF_DELAY_US(5);
+
+ priv = ide_privs;
+ for (i = 0; i < num_controllers; i++) {
+
+ if (!ide_presence_detect(i)) {
+ diag_printf("No devices on IDE controller %d\n", i);
+ continue;
+ }
+
+ // soft reset the devices on this controller
+ if (!ide_reset(i))
+ continue;
+
+ // 2 devices per controller
+ for (j = 0; j < 2; j++, priv++) {
+
+ priv->controller = i;
+ priv->drive = j;
+ priv->flags = 0;
+
+ // This is reminiscent of a memory test. We write a value
+ // to a certain location (device register), then write a
+ // different value somewhere else so that the first value
+ // is not hanging on the bus, then we read back the first
+ // value to see if the write was succesful.
+ //
+ HAL_IDE_WRITE_UINT8(i, IDE_REG_DEVICE, DEV_INIT_VAL);
+ HAL_IDE_WRITE_UINT8(i, IDE_REG_FEATURES, 0);
+ CYGACC_CALL_IF_DELAY_US(50000);
+ HAL_IDE_READ_UINT8(i, IDE_REG_DEVICE, u8);
+ if (u8 != DEV_INIT_VAL) {
+ diag_printf("IDE failed to identify unit %d - wrote: %x, read: %x\n",
+ i, DEV_INIT_VAL, u8);
+ continue;
+ }
+
+ // device present
+ priv->flags |= IDE_DEV_PRESENT;
+
+ if (ide_ident(i, j, 0, (cyg_uint16 *)buf) <= 0) {
+ if (ide_ident(i, j, 1, (cyg_uint16 *)buf) <= 0) {
+ priv->flags = 0;
+ continue; // can't identify device
+ } else {
+ u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_GENCONFIG);
+ if (((u16 >> 8) & 0x1f) != 5) {
+ diag_printf("Non-CDROM ATAPI device #%d - skipped\n", i);
+ continue;
+ }
+ priv->flags |= IDE_DEV_PACKET;
+ }
+ }
+
+ memset(&disk, 0, sizeof(disk));
+ disk.funs = &ide_funs;
+ disk.private = priv;
+
+ disk.kind = DISK_IDE_HD; // until proven otherwise
+
+ if (priv->flags & IDE_DEV_PACKET) {
+ u16 = *(cyg_uint16 *)((char *)buf + IDE_DEVID_GENCONFIG);
+ if (((u16 >> 8) & 0x1f) == 5)
+ disk.kind = DISK_IDE_CDROM;
+ } else {
+ u32 = *(cyg_uint32 *)((char *)buf + IDE_DEVID_LBA_CAPACITY);
+ disk.nr_sectors = u32;
+ }
+
+ if (!disk_register(&disk))
+ return;
+ }
+ }
+}
+
+RedBoot_init(ide_init, RedBoot_INIT_FIRST);
+
diff --git a/ecos/packages/redboot/current/src/io.c b/ecos/packages/redboot/current/src/io.c
new file mode 100644
index 0000000000..4d6cfa0c07
--- /dev/null
+++ b/ecos/packages/redboot/current/src/io.c
@@ -0,0 +1,760 @@
+//==========================================================================
+//
+// io.c
+//
+// RedBoot I/O support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+// Copyright (C) 2002, 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas,hmt,jlarmour
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include "redboot.h"
+
+#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+// GDB interface functions
+extern void ungetDebugChar(char c);
+#endif
+
+static void
+do_channel(int argc, char *argv[]);
+
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+RedBoot_cmd("channel",
+ "Display/switch console channel",
+ "[-1|<channel number>]",
+ do_channel
+ );
+#else
+RedBoot_cmd("channel",
+ "Display/switch console channel",
+ "[<channel number>]",
+ do_channel
+ );
+#endif
+
+static void
+do_channel(int argc, char *argv[])
+{
+ int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+
+ if (argc == 2) {
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+ if (strcmp( argv[1], "-1") == 0) {
+ console_selected = false;
+ console_echo = true;
+ } else
+#endif
+ {
+ unsigned long chan;
+ if ( !parse_num( argv[1], &chan, NULL, NULL) ) {
+ diag_printf("** Error: invalid channel '%s'\n", argv[1]);
+ } else {
+ if (chan < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) {
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);
+ CYGACC_CALL_IF_SET_DEBUG_COMM(chan);
+ if (chan != cur)
+ console_echo = true;
+ }
+ else {
+ diag_printf("**Error: bad channel number '%s'\n", argv[1]);
+ }
+ }
+ }
+ }
+ /* else display */
+ else {
+ diag_printf("Current console channel id: ");
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+ if (!console_selected)
+ diag_printf("-1\n");
+ else
+#endif
+ diag_printf("%d\n", cur);
+ }
+}
+
+void
+mon_write_char(char c)
+{
+ hal_virtual_comm_table_t *__chan;
+
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+ if (!console_selected) {
+ int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ int i;
+ // Send output to all channels
+ for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++) {
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
+ __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+ CYGACC_COMM_IF_PUTC(*__chan, c);
+ }
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
+ } else
+#endif
+ {
+ __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+ if (__chan)
+ CYGACC_COMM_IF_PUTC(*__chan, c);
+ else {
+ __chan = CYGACC_CALL_IF_DEBUG_PROCS();
+ CYGACC_COMM_IF_PUTC(*__chan, c);
+ }
+ }
+}
+
+static void
+mon_read_char(char *c)
+{
+ hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+
+ if (__chan)
+ *c = CYGACC_COMM_IF_GETC(*__chan);
+ else {
+ __chan = CYGACC_CALL_IF_DEBUG_PROCS();
+ *c = CYGACC_COMM_IF_GETC(*__chan);
+ }
+}
+
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+static int _mon_timeout;
+#endif
+
+static bool
+mon_read_char_with_timeout(char *c)
+{
+ bool res = false;
+ hal_virtual_comm_table_t *__chan;
+
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+ if (!console_selected) {
+ int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ int i, j, tot;
+ // Try input from all channels
+ tot = 0;
+ while (tot < _mon_timeout) {
+ for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++, tot++) {
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
+ __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+ res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c);
+ if (res) {
+ // Input available on this channel, make it be the console
+ if (*c != '\0') {
+ // Don't chose this unless real data have arrived
+ console_selected = true;
+ CYGACC_CALL_IF_SET_DEBUG_COMM(i);
+ // Disable interrupts on all channels but this one
+ for (j = 0; j < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; j++) {
+ if (i != j) {
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(j);
+ __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+ CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_DISABLE);
+ }
+ }
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
+ return res;
+ }
+ }
+ }
+ }
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
+ } else
+#endif
+ {
+ __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+ if (__chan)
+ res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c);
+ else {
+ __chan = CYGACC_CALL_IF_DEBUG_PROCS();
+ res = CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, c);
+ }
+ }
+ return res;
+}
+
+static void
+mon_set_read_char_timeout(int ms)
+{
+ hal_virtual_comm_table_t *__chan;
+
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+ if (!console_selected) {
+ int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ int i;
+ // Set timeout to minimum on each channel; total amounts to desired value
+ _mon_timeout = ms;
+ ms = 1;
+ for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++) {
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
+ if ((__chan = CYGACC_CALL_IF_CONSOLE_PROCS()) != 0) {
+ CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms);
+ }
+ }
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
+ } else
+#endif
+ {
+ if ((__chan = CYGACC_CALL_IF_CONSOLE_PROCS()) != 0) {
+ CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms);
+ }
+ if ((__chan = CYGACC_CALL_IF_DEBUG_PROCS()) != 0) {
+ CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, ms);
+ }
+ }
+}
+
+//
+// Test for ^C on the console. CAUTION! discards all console input
+//
+bool
+_rb_break(int timeout)
+{
+ char c;
+ mon_set_read_char_timeout(timeout);
+ if (mon_read_char_with_timeout(&c)) {
+ if (c == 0x03) { // Test for ^C
+ return true;
+ }
+ }
+ return false;
+}
+
+#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
+#define __STRINGIFY(x) #x
+#define _STRINGIFY(x) __STRINGIFY(x)
+#define _STARTUP_STR _STRINGIFY(CYG_HAL_STARTUP) "}"
+
+//
+// Read a character from script.
+// Return true if script character found, false if not.
+//
+static int
+getc_script(char *cp)
+{
+ static bool newline = true;
+ bool skip;
+
+ while (script && *script) {
+ if (newline && *script == '{') {
+ skip = false;
+ ++script;
+
+ // skip if it isn't for this startup type
+ if (strncmp(script, _STARTUP_STR, strlen(_STARTUP_STR)))
+ skip = true;
+
+ // skip past "{...}"
+ while (*script && *script++ != '}')
+ ;
+
+ // skip script line if neccessary
+ if (skip) {
+ while (*script && *script++ != '\n')
+ ;
+ } else
+ newline = false;
+
+ } else {
+ *cp = *script++;
+ if (*cp == '\n') {
+ newline = true;
+ } else {
+ newline = false;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
+#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
+#define _CL_NUM_LINES CYGNUM_REDBOOT_CMD_LINE_EDITING // Number of lines to keep
+static char _cl_lines[_CL_NUM_LINES][CYGPKG_REDBOOT_MAX_CMD_LINE];
+static int _cl_index = -1; // Last known command line
+static int _cl_max_index = -1; // Last command in buffers
+
+#ifdef CYGBLD_REDBOOT_CMD_LINE_HISTORY
+static void expand_history(char *);
+#endif
+#endif
+
+//
+// Read a line of input from the user
+// Return:
+// _GETS_OK: 'n' valid characters received
+// _GETS_GDB: '$' (GDB lead-in)
+// _GETS_TIMEOUT: No input before timeout
+// _GETS_CTRLC: ^C typed
+//
+// if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
+// Command line history support
+// ^P - Select previous line from history
+// ^N - Select next line from history
+// ^A - Move insertion [cursor] to start of line
+// ^E - Move cursor to end of line
+// ^B - Move cursor back [previous character]
+// ^F - Move cursor forward [next character]
+//
+int
+_rb_gets_preloaded(char *buf, int buflen, int timeout)
+{
+ char *ip = buf; // Insertion point
+ char *eol = buf; // End of line
+ char c;
+ bool res = false;
+ static char last_ch = '\0';
+ int _timeout;
+#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
+ int _index = _cl_index; // Last saved line
+ char *xp;
+#endif
+
+ // Display current buffer data
+ while (*eol) {
+ mon_write_char(*eol++);
+ }
+ ip = eol;
+
+ while (true) {
+#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
+ if (getc_script(&c))
+ do_idle(false);
+ else
+#endif
+ if ((timeout > 0) && (eol == buf)) {
+#define MIN_TIMEOUT 50
+ _timeout = timeout > MIN_TIMEOUT ? MIN_TIMEOUT : timeout;
+ mon_set_read_char_timeout(_timeout);
+ while (timeout > 0) {
+ res = mon_read_char_with_timeout(&c);
+ if (res) {
+ // Got a character
+ do_idle(false);
+ break;
+ }
+ timeout -= _timeout;
+ }
+ if (res == false) {
+ do_idle(true);
+ return _GETS_TIMEOUT; // Input timed out
+ }
+ } else {
+ mon_read_char(&c);
+ }
+ *eol = '\0';
+ switch (c) {
+#define CTRL(c) ((c)&0x1F)
+#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
+ case CTRL('P'):
+ // Fetch the previous line into the buffer
+ if (_index >= 0) {
+ // Erase the previous line [crude]
+ while (ip != buf) {
+ mon_write_char('\b');
+ mon_write_char(' ');
+ mon_write_char('\b');
+ ip--;
+ }
+ strcpy(buf, _cl_lines[_index]);
+ while (*ip) {
+ mon_write_char(*ip++);
+ }
+ eol = ip;
+ // Move to previous line
+ _index--;
+ if (_index < 0) {
+ _index = _cl_max_index;
+ }
+ } else {
+ mon_write_char(0x07); // Audible bell on most devices
+ }
+ break;
+ case CTRL('N'):
+ // Fetch the next line into the buffer
+ if (_index >= 0) {
+ if (++_index > _cl_max_index) _index = 0;
+ // Erase the previous line [crude]
+ while (ip != buf) {
+ mon_write_char('\b');
+ mon_write_char(' ');
+ mon_write_char('\b');
+ ip--;
+ }
+ strcpy(buf, _cl_lines[_index]);
+ while (*ip) {
+ mon_write_char(*ip++);
+ }
+ eol = ip;
+ } else {
+ mon_write_char(0x07); // Audible bell on most devices
+ }
+ break;
+ case CTRL('B'):
+ // Move insertion point backwards
+ if (ip != buf) {
+ mon_write_char('\b');
+ ip--;
+ }
+ break;
+ case CTRL('F'):
+ // Move insertion point forwards
+ if (ip != eol) {
+ mon_write_char(*ip++);
+ }
+ break;
+ case CTRL('E'):
+ // Move insertion point to end of line
+ while (ip != eol) {
+ mon_write_char(*ip++);
+ }
+ break;
+ case CTRL('A'):
+ // Move insertion point to beginning of line
+ if (ip != buf) {
+ xp = ip;
+ while (xp-- != buf) {
+ mon_write_char('\b');
+ }
+ }
+ ip = buf;
+ break;
+ case CTRL('K'):
+ // Kill to the end of line
+ if (ip != eol) {
+ xp = ip;
+ while (xp++ != eol) {
+ mon_write_char(' ');
+ }
+ while (--xp != ip) {
+ mon_write_char('\b');
+ }
+ eol = ip;
+ }
+ break;
+ case CTRL('D'):
+ // Erase the character under the cursor
+ if (ip != eol) {
+ xp = ip;
+ eol--;
+ while (xp != eol) {
+ *xp = *(xp+1);
+ mon_write_char(*xp++);
+ }
+ mon_write_char(' '); // Erases last character
+ mon_write_char('\b');
+ while (xp-- != ip) {
+ mon_write_char('\b');
+ }
+ }
+ break;
+#endif // CYGNUM_REDBOOT_CMD_LINE_EDITING
+ case CTRL('C'): // ^C
+ // Abort current input
+ diag_printf("^C\n");
+ *buf = '\0'; // Nothing useful in buffer
+ return _GETS_CTRLC;
+ case '\n':
+ case '\r':
+ // If previous character was the "other" end-of-line, ignore this one
+ if (((c == '\n') && (last_ch == '\r')) ||
+ ((c == '\r') && (last_ch == '\n'))) {
+ c = '\0';
+ break;
+ }
+ // End of line
+ if (console_echo) {
+ mon_write_char('\r');
+ mon_write_char('\n');
+ }
+ last_ch = c;
+#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
+ if (cmd_history) {
+ // History handling - only when enabled
+#ifdef CYGBLD_REDBOOT_CMD_LINE_HISTORY
+ expand_history(buf);
+#endif
+ if (*buf != '\0') {
+ if (++_cl_index == _CL_NUM_LINES) _cl_index = 0;
+ if (_cl_index > _cl_max_index) _cl_max_index = _cl_index;
+ strcpy(_cl_lines[_cl_index], buf);
+ }
+ }
+#endif
+ return _GETS_OK;
+ case '\b':
+ case 0x7F: // DEL
+ if (ip != buf) {
+#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
+ if (ip != eol) {
+ ip--;
+ mon_write_char('\b');
+ xp = ip;
+ while (xp != (eol-1)) {
+ *xp = *(xp+1);
+ mon_write_char(*xp++);
+ }
+ mon_write_char(' '); // Erases last character
+ mon_write_char('\b');
+ while (xp-- != ip) {
+ mon_write_char('\b');
+ }
+ } else {
+ if (console_echo) {
+ mon_write_char('\b');
+ mon_write_char(' ');
+ mon_write_char('\b');
+ }
+ ip--;
+ }
+ eol--;
+#else
+ if (console_echo) {
+ mon_write_char('\b');
+ mon_write_char(' ');
+ mon_write_char('\b');
+ }
+ ip--;
+ eol--;
+#endif
+ }
+ break;
+#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+ case '+': // fall through
+ case '$':
+ if (ip == buf || last_ch != '\\')
+ {
+ // Give up and try GDB protocol
+ ungetDebugChar(c); // Push back character so stubs will see it
+ return _GETS_GDB;
+ }
+ if (last_ch == '\\') {
+#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
+ if (ip == eol) {
+ // Just save \$ as $
+ eol = --ip;
+ } else {
+ mon_write_char('\b');
+ *--ip = c;
+ mon_write_char(c);
+ break;
+ }
+#else
+ ip--; // Save \$ as $
+#endif
+ }
+ // else fall through
+#endif
+ default:
+#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
+ // If the insertion point is not at the end of line, make space for it
+ if (ip != eol) {
+ xp = eol;
+ *++eol = '\0';
+ while (xp != ip) {
+ *xp = *(xp-1);
+ xp--;
+ }
+ }
+#endif
+ if (console_echo) {
+ mon_write_char(c);
+ }
+ if (ip == eol) {
+ // Advance both pointers
+ *ip++ = c;
+ eol = ip;
+#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
+ } else {
+ // Just insert the character
+ *ip++ = c;
+ xp = ip;
+ while (xp != eol) {
+ mon_write_char(*xp++);
+ }
+ while (xp-- != ip) {
+ mon_write_char('\b');
+ }
+#endif
+ }
+ }
+ last_ch = c;
+ if (ip == buf + buflen - 1) { // Buffer full
+ *ip = '\0';
+ return buflen;
+ }
+ }
+}
+
+int
+_rb_gets(char *buf, int buflen, int timeout)
+{
+ *buf = '\0'; // Empty buffer
+ return _rb_gets_preloaded(buf, buflen, timeout);
+}
+
+static bool
+_verify_action(int timeout, char *fmt, va_list ap)
+{
+ char ans[8];
+ int ret;
+#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
+ // Don't ask if we're executing a script
+ if (script && *script)
+ return 1;
+#endif
+
+ diag_vprintf(fmt, ap);
+ diag_printf(" - continue (y/n)? ");
+ if ((ret = _rb_gets(ans, sizeof(ans), timeout)) > 0) {
+ return ((ans[0] == 'y') || (ans[0] == 'Y'));
+ } else {
+ if (ret == _GETS_TIMEOUT) {
+ diag_printf(" ** Timed out!\n");
+ }
+ return 0; // Timed out or ^C
+ }
+}
+
+bool
+verify_action(char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ return _verify_action(0, fmt, ap);
+}
+
+bool
+verify_action_with_timeout(int timeout, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ return _verify_action(timeout, fmt, ap);
+}
+
+
+#ifdef CYGBLD_REDBOOT_CMD_LINE_HISTORY
+// parse for history index number. Return number or -1 if not
+// an index number.
+static int
+parse_history_index(char *s)
+{
+ int val = 0;
+
+ while ('0' <= *s && *s <= '9')
+ val = (val * 10) + (*s++ - '0');
+
+ if (*s)
+ return -1;
+
+ return val;
+}
+
+// Check input line to see if it needs history expansion. If so,
+// try to find matching command and replace buffer as appropriate.
+static void
+expand_history(char *buf)
+{
+ int ncmds = _cl_max_index + 1;
+ int i, index, len;
+
+ if (buf[0] != '!' || buf[1] == '\0')
+ return;
+
+ if (ncmds > 0) {
+ if (!strcmp(buf, "!!")) {
+ strcpy(buf, _cl_lines[_cl_index]);
+ return;
+ }
+ if ((index = parse_history_index(buf + 1)) >= 0) {
+ if (index <= _cl_max_index) {
+ strcpy(buf, _cl_lines[index]);
+ return;
+ }
+ }
+ len = strlen(buf + 1);
+ for (i = 0, index = _cl_index; i < ncmds; i++) {
+ if (!strncmp(_cl_lines[index], buf+1, len)) {
+ strcpy(buf, _cl_lines[index]);
+ return;
+ }
+ if (--index < 0)
+ index = _cl_max_index;
+ }
+ }
+
+ diag_printf("%s: event not found\n", buf);
+ *buf = '\0';
+}
+
+static void
+do_history(int argc, char *argv[])
+{
+ int ncmds = _cl_max_index + 1;
+ int i, index;
+
+ if (_cl_index == _cl_max_index) {
+ // history has not wrapped around
+ for (i = 0; i < ncmds; i++)
+ diag_printf("%3d %s\n", i, _cl_lines[i]);
+ } else {
+ for (i = 0, index = _cl_index + 1; i < ncmds; i++) {
+ diag_printf("%3d %s\n", i, _cl_lines[index++]);
+ if (index > _cl_max_index)
+ index = 0;
+ }
+ }
+}
+
+RedBoot_cmd("history",
+ "Display command history",
+ "",
+ do_history
+ );
+#endif // CYGBLD_REDBOOT_CMD_LINE_HISTORY
diff --git a/ecos/packages/redboot/current/src/iomem.c b/ecos/packages/redboot/current/src/iomem.c
new file mode 100644
index 0000000000..d79ffb6128
--- /dev/null
+++ b/ecos/packages/redboot/current/src/iomem.c
@@ -0,0 +1,171 @@
+//==========================================================================
+//
+// iomem.c
+//
+// RedBoot I/O memory peek and poke
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004 eCosCentric Ltd
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): icampbell
+// Contributors: icampbell
+// Date: 2004-11-09
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <cyg/hal/hal_io.h>
+
+RedBoot_cmd("iopeek",
+ "Read I/O location",
+ "[-b <location>] [-1|2|4]",
+ do_iopeek
+ );
+RedBoot_cmd("iopoke",
+ "Write I/O location",
+ "[-b <location>] [-1|2|4] -v <value>",
+ do_iopoke
+ );
+
+void
+do_iopoke(int argc, char *argv[])
+{
+ struct option_info opts[5];
+ unsigned long base;
+ bool base_set, value_set;
+ bool set_32bit = false;
+ bool set_16bit = false;
+ bool set_8bit = false;
+ cyg_uint32 value;
+ int size = 1;
+
+ init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+ &base, &base_set, "base address");
+ init_opts(&opts[1], 'v', true, OPTION_ARG_TYPE_NUM,
+ &value, &value_set, "valuex");
+ init_opts(&opts[2], '4', false, OPTION_ARG_TYPE_FLG,
+ &set_32bit, 0, "output 32 bit units");
+ init_opts(&opts[3], '2', false, OPTION_ARG_TYPE_FLG,
+ &set_16bit, 0, "output 16 bit units");
+ init_opts(&opts[4], '1', false, OPTION_ARG_TYPE_FLG,
+ &set_8bit, 0, "output 8 bit units");
+ if (!scan_opts(argc, argv, 1, opts, 5, 0, 0, "")) {
+ return;
+ }
+ if (!base_set) {
+ diag_printf("iopoke what <location>?\n");
+ return;
+ }
+ if (!value_set) {
+ diag_printf("iopoke what <value>?\n");
+ return;
+ }
+ if (set_32bit) {
+ size = 4;
+ } else if (set_16bit) {
+ size = 2;
+ } else if (set_8bit) {
+ size = 1;
+ }
+
+ switch (size) {
+ case 4:
+ HAL_WRITE_UINT32 ( base, value );
+ break;
+ case 2:
+ HAL_WRITE_UINT16 ( base, value );
+ break;
+ case 1:
+ HAL_WRITE_UINT8 ( base, value );
+ break;
+ }
+}
+
+void
+do_iopeek(int argc, char *argv[])
+{
+ struct option_info opts[4];
+ unsigned long base;
+ bool base_set;
+ bool set_32bit = false;
+ bool set_16bit = false;
+ bool set_8bit = false;
+ int size = 1, value;
+
+ init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+ &base, &base_set, "base address");
+ init_opts(&opts[1], '4', false, OPTION_ARG_TYPE_FLG,
+ &set_32bit, 0, "output 32 bit units");
+ init_opts(&opts[2], '2', false, OPTION_ARG_TYPE_FLG,
+ &set_16bit, 0, "output 16 bit units");
+ init_opts(&opts[3], '1', false, OPTION_ARG_TYPE_FLG,
+ &set_8bit, 0, "output 8 bit units");
+ if (!scan_opts(argc, argv, 1, opts, 5, 0, 0, "")) {
+ return;
+ }
+ if (!base_set) {
+ diag_printf("iopeek what <location>?\n");
+ return;
+ }
+ if (set_32bit) {
+ size = 4;
+ } else if (set_16bit) {
+ size = 2;
+ } else if (set_8bit) {
+ size = 1;
+ }
+
+ switch (size) {
+ case 4:
+ HAL_READ_UINT32 ( base, value );
+ diag_printf("0x%04lx = 0x%08x\n", base, value );
+ break;
+ case 2:
+ HAL_READ_UINT16 ( base, value );
+ diag_printf("0x%04lx = 0x%04x\n", base, value );
+ break;
+ case 1:
+ HAL_READ_UINT8 ( base, value );
+ diag_printf("0x%04lx = 0x%02x\n", base, value );
+ break;
+ }
+}
diff --git a/ecos/packages/redboot/current/src/load.c b/ecos/packages/redboot/current/src/load.c
new file mode 100644
index 0000000000..d50cfb00ba
--- /dev/null
+++ b/ecos/packages/redboot/current/src/load.c
@@ -0,0 +1,820 @@
+//==========================================================================
+//
+// load.c
+//
+// RedBoot file/image loader
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002, 2003, 2004 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas, tsmith
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <elf.h>
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_XYZMODEM
+#include <xyzModem.h>
+#endif
+#ifdef CYGPKG_REDBOOT_DISK
+#include <fs/disk.h>
+#endif
+#ifdef CYGPKG_REDBOOT_FILEIO
+#include <fs/fileio.h>
+#endif
+#ifdef CYGPKG_REDBOOT_NETWORKING
+#ifdef CYGSEM_REDBOOT_NET_TFTP_DOWNLOAD
+#include <net/tftp_support.h>
+#endif
+#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD
+#include <net/http.h>
+#endif
+#endif
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+static char usage[] = "[-r] [-v] "
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
+ "[-d] "
+#endif
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ "[-h <host>] [-p <TCP port>]"
+#endif
+ "[-m <varies>] "
+#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
+ "[-c <channel_number>] "
+#endif
+ "\n [-b <base_address>] <file_name>";
+
+// Exported CLI function
+RedBoot_cmd("load",
+ "Load a file",
+ usage,
+ do_load
+ );
+
+//
+// Stream I/O support
+//
+
+// Table describing the various I/O methods
+CYG_HAL_TABLE_BEGIN( __RedBoot_LOAD_TAB__, RedBoot_load );
+CYG_HAL_TABLE_END( __RedBoot_LOAD_TAB_END__, RedBoot_load );
+extern struct load_io_entry __RedBoot_LOAD_TAB__[], __RedBoot_LOAD_TAB_END__;
+
+// Buffers, data used by redboot_getc
+#define BUF_SIZE CYGNUM_REDBOOT_GETC_BUFFER
+struct {
+ getc_io_funcs_t *io;
+ int (*fun)(char *, int len, int *err);
+ unsigned char buf[BUF_SIZE];
+ unsigned char *bufp;
+ int avail, len, err;
+ int verbose, decompress, tick;
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
+ int (*raw_fun)(char *, int len, int *err);
+ _pipe_t load_pipe;
+ unsigned char _buffer[CYGNUM_REDBOOT_LOAD_ZLIB_BUFFER];
+#endif
+} getc_info;
+
+typedef int (*getc_t)(void);
+
+//
+// Read the next data byte from the stream.
+// Returns:
+// >= 0 - actual data
+// -1 - error or EOF, status in getc_info.err
+//
+static int
+redboot_getc(void)
+{
+ static char spin[] = "|/-\\|-";
+ if (getc_info.avail < 0) {
+ return -1;
+ }
+ if (getc_info.avail == 0) {
+ if (getc_info.verbose) {
+ diag_printf("%c\b", spin[getc_info.tick++]);
+ if (getc_info.tick >= sizeof(spin)) {
+ getc_info.tick = 0;
+ }
+ }
+ if (getc_info.len < BUF_SIZE) {
+ // No more data available
+ if (getc_info.verbose) diag_printf("\n");
+ return -1;
+ }
+ getc_info.bufp = getc_info.buf;
+ getc_info.len = (*getc_info.fun)(getc_info.bufp, BUF_SIZE, &getc_info.err);
+ if ((getc_info.avail = getc_info.len) <= 0) {
+ if (getc_info.len < 0) {
+ diag_printf("I/O error: %s\n", (getc_info.io->error)(getc_info.err));
+ }
+ if (getc_info.verbose) diag_printf("\n");
+ return -1;
+ }
+ }
+ getc_info.avail--;
+ return *getc_info.bufp++;
+}
+
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
+//
+// Called to fetch a new chunk of data and decompress it
+//
+static int
+_decompress_stream(char *buf, int len, int *err)
+{
+ _pipe_t* p = &getc_info.load_pipe;
+ int res, total;
+
+ total = 0;
+ while (len > 0) {
+ if (p->in_avail == 0) {
+ p->in_buf = &getc_info._buffer[0];
+ res = (*getc_info.raw_fun)(p->in_buf, CYGNUM_REDBOOT_LOAD_ZLIB_BUFFER,
+ &getc_info.err);
+ if ((p->in_avail = res) <= 0) {
+ // No more data
+ return total;
+ }
+ }
+ p->out_buf = buf;
+ p->out_size = 0;
+ p->out_max = len;
+ res = (*_dc_inflate)(p);
+ if (res != 0) {
+ *err = res;
+ return total;
+ }
+ len -= p->out_size;
+ buf += p->out_size;
+ total += p->out_size;
+ }
+ return total;
+}
+#endif
+
+static int
+redboot_getc_init(connection_info_t *info, getc_io_funcs_t *funcs,
+ int verbose, int decompress)
+{
+ int res;
+
+ res = (funcs->open)(info, &getc_info.err);
+ if (res < 0) {
+ diag_printf("Can't load '%s': %s\n", info->filename, (funcs->error)(getc_info.err));
+ return res;
+ }
+ getc_info.io = funcs;
+ getc_info.fun = funcs->read;
+ getc_info.avail = 0;
+ getc_info.len = BUF_SIZE;
+ getc_info.verbose = verbose;
+ getc_info.decompress = decompress;
+ getc_info.tick = 0;
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
+ if (decompress) {
+ _pipe_t* p = &getc_info.load_pipe;
+ p->out_buf = &getc_info.buf[0];
+ p->out_size = 0;
+ p->in_avail = 0;
+ getc_info.raw_fun = getc_info.fun;
+ getc_info.fun = _decompress_stream;
+ getc_info.err = (*_dc_init)(p);
+ if (0 != getc_info.err && p->msg) {
+ diag_printf("open decompression error: %s\n", p->msg);
+ }
+ }
+#endif
+ return 0;
+}
+
+static void
+redboot_getc_rewind(void)
+{
+ getc_info.bufp = getc_info.buf;
+ getc_info.avail = getc_info.len;
+}
+
+static void
+redboot_getc_terminate(bool abort)
+{
+ if (getc_info.io->terminate) {
+ (getc_info.io->terminate)(abort, redboot_getc);
+ }
+}
+
+static void
+redboot_getc_close(void)
+{
+ (getc_info.io->close)(&getc_info.err);
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
+ if (getc_info.decompress) {
+ _pipe_t* p = &getc_info.load_pipe;
+ int err = getc_info.err;
+ if (0 != err && p->msg) {
+ diag_printf("decompression error: %s\n", p->msg);
+ }
+ err = (*_dc_close)(p, getc_info.err);
+ }
+#endif
+}
+
+#ifdef CYGSEM_REDBOOT_ELF
+//
+// Support function - used to read bytes into a buffer
+// Returns the number of bytes read (stops short on errors)
+//
+static int
+_read(int (*getc)(void), unsigned char *buf, int len)
+{
+ int total = 0;
+ int ch;
+ while (len-- > 0) {
+ ch = (*getc)();
+ if (ch < 0) {
+ // EOF or error
+ break;
+ }
+ *buf++ = ch;
+ total++;
+ }
+ return total;
+}
+#endif
+
+//
+// Load an ELF [binary] image
+//
+static unsigned long
+load_elf_image(getc_t getc, unsigned long base)
+{
+#ifdef CYGSEM_REDBOOT_ELF
+ Elf32_Ehdr ehdr;
+#define MAX_PHDR 8
+ Elf32_Phdr phdr[MAX_PHDR];
+ unsigned long offset = 0;
+ int phx, len, ch;
+ unsigned char *addr;
+ unsigned long addr_offset = 0;
+ unsigned long highest_address = 0;
+ unsigned long lowest_address = 0xFFFFFFFF;
+ unsigned char *SHORT_DATA = "Short data reading ELF file\n";
+
+ // Read the header
+ if (_read(getc, (unsigned char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr)) {
+ diag_printf("Can't read ELF header\n");
+ return 0;
+ }
+ offset += sizeof(ehdr);
+#if 0 // DEBUG
+ diag_printf("Type: %d, Machine: %d, Version: %d, Entry: %p, PHoff: %p/%d/%d, SHoff: %p/%d/%d\n",
+ ehdr.e_type, ehdr.e_machine, ehdr.e_version, ehdr.e_entry,
+ ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_phnum,
+ ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shnum);
+#endif
+ if (ehdr.e_type != ET_EXEC) {
+ diag_printf("Only absolute ELF images supported\n");
+ return 0;
+ }
+ if (ehdr.e_phnum > MAX_PHDR) {
+ diag_printf("Too many program headers\n");
+ return 0;
+ }
+ while (offset < ehdr.e_phoff) {
+ if ((*getc)() < 0) {
+ diag_printf(SHORT_DATA);
+ return 0;
+ }
+ offset++;
+ }
+ for (phx = 0; phx < ehdr.e_phnum; phx++) {
+ if (_read(getc, (unsigned char *)&phdr[phx], sizeof(phdr[0])) != sizeof(phdr[0])) {
+ diag_printf("Can't read ELF program header\n");
+ return 0;
+ }
+#if 0 // DEBUG
+ diag_printf("Program header: type: %d, off: %p, va: %p, pa: %p, len: %d/%d, flags: %d\n",
+ phdr[phx].p_type, phdr[phx].p_offset, phdr[phx].p_vaddr, phdr[phx].p_paddr,
+ phdr[phx].p_filesz, phdr[phx].p_memsz, phdr[phx].p_flags);
+#endif
+ offset += sizeof(phdr[0]);
+ }
+ if (base) {
+ // Set address offset based on lowest address in file.
+ addr_offset = 0xFFFFFFFF;
+ for (phx = 0; phx < ehdr.e_phnum; phx++) {
+#ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS
+ if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_vaddr < addr_offset)) {
+ addr_offset = phdr[phx].p_vaddr;
+#else
+ if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_paddr < addr_offset)) {
+ addr_offset = phdr[phx].p_paddr;
+#endif
+ }
+ }
+ addr_offset = (unsigned long)base - addr_offset;
+ } else {
+ addr_offset = 0;
+ }
+ for (phx = 0; phx < ehdr.e_phnum; phx++) {
+ if (phdr[phx].p_type == PT_LOAD) {
+ // Loadable segment
+#ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS
+ addr = (unsigned char *)phdr[phx].p_vaddr;
+#else
+ addr = (unsigned char *)phdr[phx].p_paddr;
+#endif
+ len = phdr[phx].p_filesz;
+ if ((unsigned long)addr < lowest_address) {
+ lowest_address = (unsigned long)addr;
+ }
+ addr += addr_offset;
+ if (offset > phdr[phx].p_offset) {
+ if ((phdr[phx].p_offset + len) < offset) {
+ diag_printf("Can't load ELF file - program headers out of order\n");
+ return 0;
+ }
+ addr += offset - phdr[phx].p_offset;
+ } else {
+ while (offset < phdr[phx].p_offset) {
+ if ((*getc)() < 0) {
+ diag_printf(SHORT_DATA);
+ return 0;
+ }
+ offset++;
+ }
+ }
+
+ // Copy data into memory
+ while (len-- > 0) {
+#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
+ if (!valid_address(addr)) {
+ redboot_getc_terminate(true);
+ diag_printf("*** Abort! Attempt to load ELF data to address: %p which is not in RAM\n", (void*)addr);
+ return 0;
+ }
+#endif
+ if ((ch = (*getc)()) < 0) {
+ diag_printf(SHORT_DATA);
+ return 0;
+ }
+ *addr++ = ch;
+ offset++;
+ if ((unsigned long)(addr-addr_offset) > highest_address) {
+ highest_address = (unsigned long)(addr - addr_offset);
+ }
+ }
+ }
+ }
+
+ // Save load base/top and entry
+ if (base) {
+ load_address = base;
+ load_address_end = base + (highest_address - lowest_address);
+ entry_address = base + (ehdr.e_entry - lowest_address);
+ } else {
+ load_address = lowest_address;
+ load_address_end = highest_address;
+ entry_address = ehdr.e_entry;
+ }
+
+ redboot_getc_terminate(false);
+ if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset);
+ diag_printf("Entry point: %p, address range: %p-%p\n",
+ (void*)entry_address, (void *)load_address, (void *)load_address_end);
+ return 1;
+#else // CYGSEM_REDBOOT_ELF
+ diag_printf("Loading ELF images not supported\n");
+ return 0;
+#endif // CYGSEM_REDBOOT_ELF
+}
+
+
+//
+// Scan a string of hex bytes and update the checksum
+//
+static long
+_hex2(int (*getc)(void), int len, long *sum)
+{
+ int val, byte;
+ char c1, c2;
+
+ val = 0;
+ while (len-- > 0) {
+ c1 = (*getc)();
+ c2 = (*getc)();
+ if (_is_hex(c1) && _is_hex(c2)) {
+ val <<= 8;
+ byte = (_from_hex(c1)<<4) | _from_hex(c2);
+ val |= byte;
+ if (sum) {
+ *sum += byte;
+ }
+ } else {
+ return (-1);
+ }
+ }
+ return (val);
+}
+
+//
+// Process a set of S-records, loading the contents into memory.
+// Note: if a "base" value is provided, the data will be relocated
+// relative to that location. Of course, this can only work for
+// the first section of the data, so if there are non-contiguous
+// pieces of data, they will end up relocated in the same fashion.
+// Because of this, "base" probably only makes sense for a set of
+// data which has only one section, e.g. a ROM image.
+//
+static unsigned long
+load_srec_image(getc_t getc, unsigned long base)
+{
+ int c;
+ long offset = 0, count, sum, val, cksum;
+ unsigned char *addr, *base_addr;
+ char type;
+ bool first_addr = true;
+ unsigned long addr_offset = 0;
+ unsigned long highest_address = 0;
+ unsigned long lowest_address = 0xFFFFFFFF;
+
+ while ((c = (*getc)()) > 0) {
+ // Start of line
+ if (c != 'S') {
+ redboot_getc_terminate(true);
+ diag_printf("Invalid S-record at offset %p, input: %c\n",
+ (void *)offset, c);
+ return 0;
+ }
+ type = (*getc)();
+ offset += 2;
+ sum = 0;
+ if ((count = _hex2(getc, 1, &sum)) < 0) {
+ redboot_getc_terminate(true);
+ diag_printf("Bad S-record count at offset %p\n", (void *)offset);
+ return 0;
+ }
+ offset += 1;
+ switch (type) {
+ case '0':
+ break;
+ case '1':
+ case '2':
+ case '3':
+ base_addr = addr = (unsigned char *)_hex2(getc, (type-'1'+2), &sum);
+ offset += (type-'1'+2);
+ if (first_addr) {
+ if (base) {
+ addr_offset = (unsigned long)base - (unsigned long)addr;
+ } else {
+ addr_offset = 0;
+ }
+ first_addr = false;
+ }
+ addr += addr_offset;
+ if ((unsigned long)(addr-addr_offset) < lowest_address) {
+ lowest_address = (unsigned long)(addr - addr_offset);
+ }
+#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
+ if (!valid_address(addr)) {
+ // Only if there is no need to stop the download before printing
+ // output can we ask confirmation questions.
+ redboot_getc_terminate(true);
+ diag_printf("*** Abort! Attempt to load S-record to address: %p, which is not in RAM\n",(void*)addr);
+ return 0;
+ }
+#endif
+ count -= ((type-'1'+2)+1);
+ offset += count;
+ while (count-- > 0) {
+ val = _hex2(getc, 1, &sum);
+ *addr++ = val;
+ }
+ cksum = _hex2(getc, 1, 0);
+ offset += 1;
+ sum = sum & 0xFF;
+ cksum = (~cksum & 0xFF);
+ if (cksum != sum) {
+ redboot_getc_terminate(true);
+ diag_printf("*** Warning! Checksum failure - Addr: %lx, %02lX <> %02lX\n",
+ (unsigned long)base_addr, sum, cksum);
+ return 0;
+ }
+ if ((unsigned long)(addr-addr_offset) > highest_address) {
+ highest_address = (unsigned long)(addr - addr_offset);
+ }
+ break;
+ case '7':
+ case '8':
+ case '9':
+ addr = (unsigned char *)_hex2(getc, ('9'-type+2), &sum);
+ offset += ('9'-type+2);
+ // Save load base/top, entry address
+ if (base) {
+ load_address = base;
+ load_address_end = base + (highest_address - lowest_address);
+ entry_address = (unsigned long)(base + (addr - lowest_address));
+ } else {
+ load_address = lowest_address;
+ load_address_end = highest_address;
+ entry_address = (unsigned long)addr;
+ }
+ redboot_getc_terminate(false);
+ if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset);
+ diag_printf("Entry point: %p, address range: %p-%p\n",
+ (void*)entry_address, (void *)load_address, (void *)load_address_end);
+
+ return load_address_end;
+ default:
+ redboot_getc_terminate(true);
+ diag_printf("Invalid S-record at offset 0x%lx, type: %x\n",
+ (unsigned long)offset, type);
+ return 0;
+ }
+ while ((c = (*getc)()) != '\n') offset++;
+ }
+ return 0;
+}
+
+//
+// 'load' CLI command processing
+// -b - specify a load [base] address
+// -m - specify an I/O stream/method
+// -c - Alternate serial I/O channel
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
+// -d - Decompress data [packed via 'zlib']
+#endif
+//
+void
+do_load(int argc, char *argv[])
+{
+ int res, num_options;
+ int i, err;
+ bool verbose, raw;
+ bool base_addr_set, mode_str_set;
+ char *mode_str;
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ struct sockaddr_in host;
+ bool hostname_set, port_set;
+ unsigned int port; // int because it's an OPTION_ARG_TYPE_NUM,
+ // but will be cast to short
+ char *hostname;
+#endif
+ bool decompress = false;
+ int chan = -1;
+#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
+ bool chan_set;
+#endif
+ unsigned long base = 0;
+ unsigned long end = 0;
+ char type[4];
+ char *filename = 0;
+ struct option_info opts[8];
+ connection_info_t info;
+ getc_io_funcs_t *io = NULL;
+ struct load_io_entry *io_tab;
+#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
+ bool spillover_ok = false;
+#endif
+
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ memset((char *)&host, 0, sizeof(host));
+ host.sin_len = sizeof(host);
+ host.sin_family = AF_INET;
+ host.sin_addr = my_bootp_info.bp_siaddr;
+ host.sin_port = 0;
+#endif
+
+ init_opts(&opts[0], 'v', false, OPTION_ARG_TYPE_FLG,
+ (void *)&verbose, 0, "verbose");
+ init_opts(&opts[1], 'r', false, OPTION_ARG_TYPE_FLG,
+ (void *)&raw, 0, "load raw data");
+ init_opts(&opts[2], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&base, (bool *)&base_addr_set, "load address");
+ init_opts(&opts[3], 'm', true, OPTION_ARG_TYPE_STR,
+ (void *)&mode_str, (bool *)&mode_str_set, "download mode (TFTP, xyzMODEM, or disk)");
+ num_options = 4;
+#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
+ init_opts(&opts[num_options], 'c', true, OPTION_ARG_TYPE_NUM,
+ (void *)&chan, (bool *)&chan_set, "I/O channel");
+ num_options++;
+#endif
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ init_opts(&opts[num_options], 'h', true, OPTION_ARG_TYPE_STR,
+ (void *)&hostname, (bool *)&hostname_set, "host name or IP address");
+ num_options++;
+ init_opts(&opts[num_options], 'p', true, OPTION_ARG_TYPE_NUM,
+ (void *)&port, (bool *)&port_set, "TCP port");
+ num_options++;
+#endif
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
+ init_opts(&opts[num_options], 'd', false, OPTION_ARG_TYPE_FLG,
+ (void *)&decompress, 0, "decompress");
+ num_options++;
+#endif
+
+ CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options");
+
+ if (!scan_opts(argc, argv, 1, opts, num_options,
+ (void *)&filename, OPTION_ARG_TYPE_STR, "file name")) {
+ return;
+ }
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ if (hostname_set) {
+ ip_route_t rt;
+ if (!_gethostbyname(hostname, (in_addr_t *)&host)) {
+ diag_printf("Invalid host: %s\n", hostname);
+ return;
+ }
+ /* check that the host can be accessed */
+ if (__arp_lookup((ip_addr_t *)&host.sin_addr, &rt) < 0) {
+ diag_printf("Unable to reach host %s (%s)\n",
+ hostname, inet_ntoa((in_addr_t *)&host));
+ return;
+ }
+ }
+ if (port_set)
+ host.sin_port = port;
+#endif
+ if (chan >= CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) {
+ diag_printf("Invalid I/O channel: %d\n", chan);
+ return;
+ }
+ if (mode_str_set) {
+ for (io_tab = __RedBoot_LOAD_TAB__;
+ io_tab != &__RedBoot_LOAD_TAB_END__; io_tab++) {
+ if (strncasecmp(&mode_str[0], io_tab->name, strlen(&mode_str[0])) == 0) {
+ io = io_tab->funcs;
+ break;
+ }
+ }
+ if (!io) {
+ diag_printf("Invalid 'mode': %s. Valid modes are:", mode_str);
+ for (io_tab = __RedBoot_LOAD_TAB__;
+ io_tab != &__RedBoot_LOAD_TAB_END__; io_tab++) {
+ diag_printf(" %s", io_tab->name);
+ }
+ diag_printf("\n");
+ }
+ if (!io) {
+ return;
+ }
+ verbose &= io_tab->can_verbose;
+ if (io_tab->need_filename && !filename) {
+ diag_printf("File name required\n");
+ diag_printf("usage: load %s\n", usage);
+ return;
+ }
+ } else {
+ char *which;
+ io_tab = (struct load_io_entry *)NULL; // Default
+#ifdef CYGPKG_REDBOOT_NETWORKING
+#ifdef CYGSEM_REDBOOT_NET_TFTP_DOWNLOAD
+ which = "TFTP";
+ io = &tftp_io;
+#elif defined(CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD)
+ which = "HTTP";
+ io = &http_io;
+#endif
+#endif
+#ifdef CYGPKG_REDBOOT_FILEIO
+ // Make file I/O default if mounted
+ if (fileio_mounted) {
+ which = "file";
+ io = &fileio_io;
+ }
+#endif
+ if (!io) {
+#ifdef CYGBLD_BUILD_REDBOOT_WITH_XYZMODEM
+ which = "Xmodem";
+ io = &xyzModem_io;
+ verbose = false;
+#else
+ diag_printf("No default protocol!\n");
+ return;
+#endif
+ }
+ diag_printf("Using default protocol (%s)\n", which);
+ }
+#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
+ if (base_addr_set && !valid_address((unsigned char *)base)) {
+ if (!verify_action("Specified address (%p) is not believed to be in RAM", (void*)base))
+ return;
+ spillover_ok = true;
+ }
+#endif
+ if (raw && !base_addr_set) {
+ diag_printf("Raw load requires a memory address\n");
+ return;
+ }
+ info.filename = filename;
+ info.chan = chan;
+ info.mode = io_tab ? io_tab->mode : 0;
+#ifdef CYGPKG_REDBOOT_NETWORKING
+ info.server = &host;
+#endif
+ res = redboot_getc_init(&info, io, verbose, decompress);
+ if (res < 0) {
+ return;
+ }
+
+ // Stream open, process the data
+ if (raw) {
+ unsigned char *mp = (unsigned char *)base;
+ err = 0;
+ while ((res = redboot_getc()) >= 0) {
+#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
+ if (!valid_address(mp) && !spillover_ok) {
+ // Only if there is no need to stop the download
+ // before printing output can we ask confirmation
+ // questions.
+ redboot_getc_terminate(true);
+ diag_printf("*** Abort! RAW data spills over limit of user RAM at %p\n",(void*)mp);
+ err = -1;
+ break;
+ }
+#endif
+ *mp++ = res;
+ }
+ end = (unsigned long) mp;
+
+ // Save load base/top
+ load_address = base;
+ load_address_end = end;
+ entry_address = base; // best guess
+
+ redboot_getc_terminate(false);
+ if (0 == err)
+ diag_printf("Raw file loaded %p-%p, assumed entry at %p\n",
+ (void *)base, (void *)(end - 1), (void*)base);
+ } else {
+ // Read initial header - to determine file [image] type
+ for (i = 0; i < sizeof(type); i++) {
+ if ((res = redboot_getc()) < 0) {
+ err = getc_info.err;
+ break;
+ }
+ type[i] = res;
+ }
+ if (res >= 0) {
+ redboot_getc_rewind(); // Restore header to stream
+ // Treat data as some sort of executable image
+ if (strncmp(&type[1], "ELF", 3) == 0) {
+ end = load_elf_image(redboot_getc, base);
+ } else if ((type[0] == 'S') &&
+ ((type[1] >= '0') && (type[1] <= '9'))) {
+ end = load_srec_image(redboot_getc, base);
+ } else {
+ redboot_getc_terminate(true);
+ diag_printf("Unrecognized image type: 0x%lx\n", *(unsigned long *)type);
+ }
+ }
+ }
+
+ redboot_getc_close(); // Clean up
+ return;
+}
diff --git a/ecos/packages/redboot/current/src/main.c b/ecos/packages/redboot/current/src/main.c
new file mode 100644
index 0000000000..28fc2f558a
--- /dev/null
+++ b/ecos/packages/redboot/current/src/main.c
@@ -0,0 +1,758 @@
+//==========================================================================
+//
+// main.c
+//
+// RedBoot main routine
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
+// Copyright (C) 2002, 2003, 2004 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas, tkoeller
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#define DEFINE_VARS
+#include <redboot.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/hal_if.h>
+#include <cyg/hal/hal_cache.h>
+#include CYGHWR_MEMORY_LAYOUT_H
+
+#ifdef CYGPKG_IO_ETH_DRIVERS
+#include <cyg/io/eth/eth_drv.h> // Logical driver interfaces
+#endif
+
+#include <cyg/hal/hal_tables.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/infra/cyg_type.h>
+#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+#ifdef CYGBLD_HAL_PLATFORM_STUB_H
+#include CYGBLD_HAL_PLATFORM_STUB_H
+#else
+#include <cyg/hal/plf_stub.h>
+#endif
+// GDB interfaces
+extern void breakpoint(void);
+#endif
+
+// Builtin Self Test (BIST)
+externC void bist(void);
+
+// Path to code run from a go command or to GDB stubs
+static void trampoline(unsigned long entry);
+
+// Return path for code run from a go command or for GDB stubs
+static void return_to_redboot(int status);
+
+// Address of area where current context is saved before executing
+// trampoline procedure
+static void * saved_context;
+
+// Status returned after trampoline execution
+static int return_status;
+
+
+// CLI command processing (defined in this file)
+RedBoot_cmd("version",
+ "Display RedBoot version information",
+ "",
+ do_version
+ );
+RedBoot_cmd("help",
+ "Help about help?",
+ "[<topic>]",
+ do_help
+ );
+
+static char go_usage[] = "[-w <timeout>] [-c] "
+#ifdef CYGPKG_IO_ETH_DRIVERS
+ "[-n] "
+#endif
+ "[entry]";
+
+RedBoot_cmd("go",
+ "Execute code at a location",
+ go_usage,
+ do_go
+ );
+#ifdef HAL_PLATFORM_RESET
+RedBoot_cmd("reset",
+ "Reset the system",
+ "",
+ do_reset
+ );
+#endif
+#ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
+RedBoot_cmd("baudrate",
+ "Set/Query the system console baud rate",
+ "[-b <rate>]",
+ do_baud_rate
+ );
+#endif
+
+// Define table boundaries
+CYG_HAL_TABLE_BEGIN( __RedBoot_INIT_TAB__, RedBoot_inits );
+CYG_HAL_TABLE_END( __RedBoot_INIT_TAB_END__, RedBoot_inits );
+extern struct init_tab_entry __RedBoot_INIT_TAB__[], __RedBoot_INIT_TAB_END__;
+
+CYG_HAL_TABLE_BEGIN( __RedBoot_CMD_TAB__, RedBoot_commands );
+CYG_HAL_TABLE_END( __RedBoot_CMD_TAB_END__, RedBoot_commands );
+extern struct cmd __RedBoot_CMD_TAB__[], __RedBoot_CMD_TAB_END__;
+
+CYG_HAL_TABLE_BEGIN( __RedBoot_IDLE_TAB__, RedBoot_idle );
+CYG_HAL_TABLE_END( __RedBoot_IDLE_TAB_END__, RedBoot_idle );
+extern struct idle_tab_entry __RedBoot_IDLE_TAB__[], __RedBoot_IDLE_TAB_END__;
+
+#ifdef HAL_ARCH_PROGRAM_NEW_STACK
+extern void HAL_ARCH_PROGRAM_NEW_STACK(void *fun);
+#endif
+
+//
+// [Null] Builtin [Power On] Self Test
+//
+void bist(void) CYGBLD_ATTRIB_WEAK;
+
+void
+bist(void)
+{
+}
+
+//
+// 'version' command
+//
+void
+do_version(int argc, char *argv[])
+{
+#if CYGBLD_REDBOOT_MAX_MEM_SEGMENTS > 1
+ int seg;
+#endif
+#ifdef CYGPKG_REDBOOT_FLASH
+ externC void _flash_info(void);
+#endif
+ char *version = CYGACC_CALL_IF_MONITOR_VERSION();
+
+ diag_printf(version);
+#ifdef HAL_PLATFORM_CPU
+ diag_printf("Platform: %s (%s) %s\n", HAL_PLATFORM_BOARD, HAL_PLATFORM_CPU, HAL_PLATFORM_EXTRA);
+#endif
+ diag_printf("Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.\n\n");
+ diag_printf("RAM: %p-%p, ", (void*)ram_start, (void*)ram_end);
+ diag_printf("[%p-%p]", mem_segments[0].start, mem_segments[0].end);
+ diag_printf(" available\n");
+#if CYGBLD_REDBOOT_MAX_MEM_SEGMENTS > 1
+ for (seg = 1; seg < CYGBLD_REDBOOT_MAX_MEM_SEGMENTS; seg++) {
+ if (mem_segments[seg].start != NO_MEMORY) {
+ diag_printf(" %p-%p, ", mem_segments[seg].start, mem_segments[seg].end);
+ diag_printf("[%p-%p]", mem_segments[seg].start, mem_segments[seg].end);
+ diag_printf(" available\n");
+ }
+ }
+#endif
+#ifdef CYGPKG_REDBOOT_FLASH
+ _flash_info();
+#endif
+}
+
+//
+// This function is called when RedBoot is idle (waiting for user
+// input). It will call any registered "idle" routines, e.g. scan
+// for incoming network connections, blank an LCD screen, etc.
+//
+void
+do_idle(bool is_idle)
+{
+ struct idle_tab_entry *idle_entry;
+
+ for (idle_entry = __RedBoot_IDLE_TAB__;
+ idle_entry != &__RedBoot_IDLE_TAB_END__; idle_entry++) {
+ (*idle_entry->fun)(is_idle);
+ }
+}
+
+// Wrapper used by diag_printf()
+static void
+_mon_write_char(char c, void **param)
+{
+ if (c == '\n') {
+ mon_write_char('\r');
+ }
+ mon_write_char(c);
+}
+
+//
+// Handle illegal memory accesses (and other abort conditions)
+//
+static hal_jmp_buf error_jmpbuf;
+#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+externC
+#endif
+ void* volatile __mem_fault_handler;
+
+static void error_handler(void)
+{
+ hal_longjmp(error_jmpbuf, 1);
+}
+
+
+//
+// This is the main entry point for RedBoot
+//
+
+void
+cyg_start(void)
+{
+ int res = 0;
+ bool prompt = true;
+ static char line[CYGPKG_REDBOOT_MAX_CMD_LINE];
+ char *command;
+ struct cmd *cmd;
+ int cur;
+ struct init_tab_entry *init_entry;
+ extern char RedBoot_version[];
+#if CYGBLD_REDBOOT_MAX_MEM_SEGMENTS > 1
+ int seg;
+#endif
+
+ // Export version information
+ CYGACC_CALL_IF_MONITOR_VERSION_SET(RedBoot_version);
+
+ CYGACC_CALL_IF_MONITOR_RETURN_SET(return_to_redboot);
+
+ // Make sure the channels are properly initialized.
+ diag_init_putc(_mon_write_char);
+ hal_if_diag_init();
+
+ // Force console to output raw text - but remember the old setting
+ // so it can be restored if interaction with a debugger is
+ // required.
+ cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL);
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+ console_selected = false;
+#endif
+ console_echo = true;
+ CYGACC_CALL_IF_DELAY_US((cyg_int32)2*100000);
+
+ ram_start = (unsigned char *)CYGMEM_REGION_ram;
+ ram_end = (unsigned char *)(CYGMEM_REGION_ram+CYGMEM_REGION_ram_SIZE);
+#ifdef HAL_MEM_REAL_REGION_TOP
+ {
+ unsigned char *ram_end_tmp = ram_end;
+ ram_end = HAL_MEM_REAL_REGION_TOP( ram_end_tmp );
+ }
+#endif
+#ifdef CYGMEM_SECTION_heap1
+ workspace_start = (unsigned char *)CYGMEM_SECTION_heap1;
+ workspace_end = (unsigned char *)(CYGMEM_SECTION_heap1+CYGMEM_SECTION_heap1_SIZE);
+#else
+ workspace_start = (unsigned char *)CYGMEM_REGION_ram;
+ workspace_end = (unsigned char *)(CYGMEM_REGION_ram+CYGMEM_REGION_ram_SIZE);
+#endif
+
+ if ( ram_end < workspace_end ) {
+ // when *less* SDRAM is installed than the possible maximum,
+ // but the heap1 region remains greater...
+ workspace_end = ram_end;
+ }
+
+ // Nothing has ever been loaded into memory
+ entry_address = (unsigned long)NO_MEMORY;
+
+ bist();
+
+#if defined(CYGPRI_REDBOOT_ZLIB_FLASH) && defined(CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER)
+ fis_zlib_common_buffer =
+ workspace_end -= CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE;
+#endif
+
+#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
+ script_timeout = CYGNUM_REDBOOT_BOOT_SCRIPT_DEFAULT_TIMEOUT;
+#endif
+
+ for (init_entry = __RedBoot_INIT_TAB__; init_entry != &__RedBoot_INIT_TAB_END__; init_entry++) {
+ (*init_entry->fun)();
+ }
+
+ mem_segments[0].start = workspace_start;
+ mem_segments[0].end = workspace_end;
+#if CYGBLD_REDBOOT_MAX_MEM_SEGMENTS > 1
+ for (seg = 1; seg < CYGBLD_REDBOOT_MAX_MEM_SEGMENTS; seg++) {
+ cyg_plf_memory_segment(seg, &mem_segments[seg].start, &mem_segments[seg].end);
+ }
+#endif
+
+#ifdef CYGSEM_REDBOOT_PLF_STARTUP
+
+ cyg_plf_redboot_startup();
+#endif
+ do_version(0,0);
+
+#ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
+# ifdef CYGDAT_REDBOOT_DEFAULT_BOOT_SCRIPT
+ if (!script) {
+ script = CYGDAT_REDBOOT_DEFAULT_BOOT_SCRIPT;
+ }
+# endif
+ if (script) {
+ // Give the guy a chance to abort any boot script
+ unsigned char *hold_script = script;
+ int script_timeout_ms = script_timeout * CYGNUM_REDBOOT_BOOT_SCRIPT_TIMEOUT_RESOLUTION;
+ diag_printf("== Executing boot script in %d.%03d seconds - enter ^C to abort\n",
+ script_timeout_ms/1000, script_timeout_ms%1000);
+ script = (unsigned char *)0;
+ res = _GETS_CTRLC; // Treat 0 timeout as ^C
+ while (script_timeout_ms >= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT) {
+ res = _rb_gets(line, sizeof(line), CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT);
+ if (res >= _GETS_OK) {
+ diag_printf("== Executing boot script in %d.%03d seconds - enter ^C to abort\n",
+ script_timeout_ms/1000, script_timeout_ms%1000);
+ continue; // Ignore anything but ^C
+ }
+ if (res != _GETS_TIMEOUT) break;
+ script_timeout_ms -= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT;
+ }
+ if (res == _GETS_CTRLC) {
+ script = (unsigned char *)0; // Disable script
+ } else {
+ script = hold_script; // Re-enable script
+ }
+ }
+#endif
+
+ while (true) {
+ if (prompt) {
+ diag_printf("RedBoot> ");
+ prompt = false;
+ }
+#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
+ cmd_history = true; // Enable history collection
+#endif
+ res = _rb_gets(line, sizeof(line), CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT);
+#if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
+ cmd_history = false; // Enable history collection
+#endif
+ if (res == _GETS_TIMEOUT) {
+ // No input arrived
+ } else {
+#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+ if (res == _GETS_GDB) {
+ int dbgchan;
+ hal_virtual_comm_table_t *__chan;
+ int i;
+ // Special case of '$' - need to start GDB protocol
+ gdb_active = true;
+ // Mask interrupts on all channels
+ for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS; i++) {
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
+ __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+ CYGACC_COMM_IF_CONTROL( *__chan, __COMMCTL_IRQ_DISABLE );
+ }
+
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
+
+ // set up a temporary context that will take us to the trampoline
+ HAL_THREAD_INIT_CONTEXT((CYG_ADDRWORD)workspace_end,
+ breakpoint, trampoline,0);
+
+ // switch context to trampoline (get GDB stubs started)
+ HAL_THREAD_SWITCH_CONTEXT(&saved_context, &workspace_end);
+
+ gdb_active = false;
+
+ dbgchan = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(dbgchan);
+ } else
+#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+ {
+ expand_aliases(line, sizeof(line));
+ command = (char *)&line;
+ if ((*command == '#') || (*command == '=')) {
+ // Special cases
+ if (*command == '=') {
+ // Print line on console
+ diag_printf("%s\n", &line[2]);
+ }
+ } else {
+ while (strlen(command) > 0) {
+ if ((cmd = parse(&command, &argc, &argv[0])) != (struct cmd *)0) {
+ // Try to handle aborts - messy because of the stack unwinding...
+ __mem_fault_handler = error_handler;
+ if (hal_setjmp(error_jmpbuf)) {
+ diag_printf("** command abort - illegal memory access?\n");
+ } else {
+ (cmd->fun)(argc, argv);
+ }
+ __mem_fault_handler = 0;
+ } else {
+ diag_printf("** Error: Illegal command: \"%s\"\n", argv[0]);
+ }
+ }
+ }
+ prompt = true;
+ }
+ }
+ }
+}
+
+void
+show_help(struct cmd *cmd, struct cmd *cmd_end, char *which, char *pre)
+{
+ bool show;
+ int len = 0;
+
+ if (which) {
+ len = strlen(which);
+ }
+ while (cmd != cmd_end) {
+ show = true;
+ if (which && (strncasecmp(which, cmd->str, len) != 0)) {
+ show = false;
+ }
+ if (show) {
+ diag_printf("%s\n %s %s %s\n", cmd->help, pre, cmd->str, cmd->usage);
+ if ((cmd->sub_cmds != (struct cmd *)0) && (which != (char *)0)) {
+ show_help(cmd->sub_cmds, cmd->sub_cmds_end, 0, cmd->str);
+ }
+ }
+ cmd++;
+ }
+}
+
+void
+do_help(int argc, char *argv[])
+{
+ struct cmd *cmd;
+ char *which = (char *)0;
+
+ if (!scan_opts(argc, argv, 1, 0, 0, (void *)&which, OPTION_ARG_TYPE_STR, "<topic>")) {
+ diag_printf("Invalid argument\n");
+ return;
+ }
+ cmd = __RedBoot_CMD_TAB__;
+ show_help(cmd, &__RedBoot_CMD_TAB_END__, which, "");
+ return;
+}
+
+static void
+trampoline(unsigned long entry)
+{
+ typedef void code_fun(void);
+ code_fun *fun = (code_fun *)entry;
+ unsigned long oldints;
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+
+#ifdef HAL_ARCH_PROGRAM_NEW_STACK
+ HAL_ARCH_PROGRAM_NEW_STACK(fun);
+#else
+ (*fun)();
+#endif
+
+ HAL_THREAD_LOAD_CONTEXT(&saved_context);
+}
+
+static void
+return_to_redboot(int status)
+{
+ CYGARC_HAL_SAVE_GP();
+
+ return_status = status;
+ HAL_THREAD_LOAD_CONTEXT(&saved_context);
+ // never returns
+
+ // need this to balance above CYGARC_HAL_SAVE_GP on
+ // some platforms. It will never run, though.
+ CYGARC_HAL_RESTORE_GP();
+}
+
+void
+do_go(int argc, char *argv[])
+{
+ int i, cur, num_options;
+ unsigned long entry;
+ unsigned long oldints;
+ bool wait_time_set;
+ int wait_time, res;
+ bool cache_enabled = false;
+#ifdef CYGPKG_IO_ETH_DRIVERS
+ bool stop_net = false;
+#endif
+ struct option_info opts[3];
+ char line[8];
+ hal_virtual_comm_table_t *__chan;
+
+ __mem_fault_handler = 0; // Let GDB handle any faults directly
+ entry = entry_address; // Default from last 'load' operation
+ init_opts(&opts[0], 'w', true, OPTION_ARG_TYPE_NUM,
+ (void *)&wait_time, (bool *)&wait_time_set, "wait timeout");
+ init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG,
+ (void *)&cache_enabled, (bool *)0, "go with caches enabled");
+ num_options = 2;
+#ifdef CYGPKG_IO_ETH_DRIVERS
+ init_opts(&opts[2], 'n', false, OPTION_ARG_TYPE_FLG,
+ (void *)&stop_net, (bool *)0, "go with network driver stopped");
+ num_options++;
+#endif
+
+ CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options");
+
+ if (!scan_opts(argc, argv, 1, opts, num_options, (void *)&entry, OPTION_ARG_TYPE_NUM, "starting address"))
+ {
+ return;
+ }
+ if (entry == (unsigned long)NO_MEMORY) {
+ diag_printf("No entry point known - aborted\n");
+ return;
+ }
+ if (wait_time_set) {
+ int script_timeout_ms = wait_time * 1000;
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ unsigned char *hold_script = script;
+ script = (unsigned char *)0;
+#endif
+ diag_printf("About to start execution at %p - abort with ^C within %d seconds\n",
+ (void *)entry, wait_time);
+ while (script_timeout_ms >= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT) {
+ res = _rb_gets(line, sizeof(line), CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT);
+ if (res == _GETS_CTRLC) {
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ script = hold_script; // Re-enable script
+#endif
+ return;
+ }
+ script_timeout_ms -= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT;
+ }
+ }
+
+ // Mask interrupts on all channels
+ cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS; i++) {
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
+ __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+ CYGACC_COMM_IF_CONTROL( *__chan, __COMMCTL_IRQ_DISABLE );
+ }
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
+
+ __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+ CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_ENABLE_LINE_FLUSH);
+
+#ifdef CYGPKG_IO_ETH_DRIVERS
+ if (stop_net)
+ eth_drv_stop();
+#endif
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ if (!cache_enabled) {
+ HAL_ICACHE_DISABLE();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ }
+ HAL_ICACHE_INVALIDATE_ALL();
+ HAL_DCACHE_INVALIDATE_ALL();
+ // set up a temporary context that will take us to the trampoline
+ HAL_THREAD_INIT_CONTEXT((CYG_ADDRWORD)workspace_end,
+ entry, trampoline, 0);
+
+ // switch context to trampoline
+ HAL_THREAD_SWITCH_CONTEXT(&saved_context, &workspace_end);
+
+ // we get back here by way of return_to_redboot()
+
+ // undo the changes we made before switching context
+ if (!cache_enabled) {
+ HAL_ICACHE_ENABLE();
+ HAL_DCACHE_ENABLE();
+ }
+
+ CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_DISABLE_LINE_FLUSH);
+
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ diag_printf("\nProgram completed with status %d\n", return_status);
+}
+
+#ifdef HAL_PLATFORM_RESET
+void
+do_reset(int argc, char *argv[])
+{
+ diag_printf("... Resetting.");
+ CYGACC_CALL_IF_DELAY_US(2*100000);
+ diag_printf("\n");
+ CYGACC_CALL_IF_RESET();
+ diag_printf("!! oops, RESET not working on this platform\n");
+}
+#endif
+
+#ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+#include <flash_config.h>
+#endif
+
+static int
+set_comm_baud_rate(hal_virtual_comm_table_t *chan, int rate)
+{
+ int current_rate;
+
+ current_rate = CYGACC_COMM_IF_CONTROL(*chan, __COMMCTL_GETBAUD);
+ if (rate != current_rate)
+ return CYGACC_COMM_IF_CONTROL(*chan, __COMMCTL_SETBAUD, rate);
+
+ return 0;
+}
+
+int
+set_console_baud_rate(int rate)
+{
+ int ret = -1;
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+ if (!console_selected) {
+ int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ int i;
+ // Set baud for all channels
+ for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS; i++) {
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
+ ret = set_comm_baud_rate(CYGACC_CALL_IF_CONSOLE_PROCS(), rate);
+ if (ret < 0)
+ break;
+ }
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
+ } else
+#endif
+ ret = set_comm_baud_rate(CYGACC_CALL_IF_CONSOLE_PROCS(), rate);
+
+ if (ret < 0)
+ diag_printf("Setting console baud rate to %d failed\n", rate);
+
+ return ret;
+}
+
+static void
+_sleep(int ms)
+{
+ int i;
+ for (i = 0; i < ms; i++) {
+ CYGACC_CALL_IF_DELAY_US((cyg_int32)1000);
+ }
+}
+
+void
+do_baud_rate(int argc, char *argv[])
+{
+ int new_rate, ret, old_rate;
+ bool new_rate_set;
+ hal_virtual_comm_table_t *__chan;
+ struct option_info opts[1];
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ struct config_option opt;
+#endif
+
+ init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&new_rate, (bool *)&new_rate_set, "new baud rate");
+ if (!scan_opts(argc, argv, 1, opts, 1, 0, 0, "")) {
+ return;
+ }
+ __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+ if (new_rate_set) {
+ diag_printf("Baud rate will be changed to %d - update your settings\n", new_rate);
+ _sleep(500); // Give serial time to flush
+ old_rate = CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_GETBAUD);
+ ret = set_console_baud_rate(new_rate);
+ if (ret < 0) {
+ if (old_rate > 0) {
+ // Try to restore
+ set_console_baud_rate(old_rate);
+ _sleep(500); // Give serial time to flush
+ diag_printf("\nret = %d\n", ret);
+ }
+ return; // Couldn't set the desired rate
+ }
+ // Make sure this new rate works or back off to previous value
+ // Sleep for a few seconds, then prompt to see if it works
+ _sleep(3000); // Give serial time to flush
+ if (!verify_action_with_timeout(5000, "Baud rate changed to %d", new_rate)) {
+ _sleep(500); // Give serial time to flush
+ set_console_baud_rate(old_rate);
+ _sleep(500); // Give serial time to flush
+ return;
+ }
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ opt.type = CONFIG_INT;
+ opt.enable = (char *)0;
+ opt.enable_sense = 1;
+ opt.key = "console_baud_rate";
+ opt.dflt = new_rate;
+ flash_add_config(&opt, true);
+#endif
+ } else {
+ ret = CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_GETBAUD);
+ diag_printf("Baud rate = ");
+ if (ret <= 0) {
+ diag_printf("unknown\n");
+ } else {
+ diag_printf("%d\n", ret);
+ }
+ }
+}
+#endif
+
+//
+// Validate an address to see if it is within any known RAM area
+//
+bool
+valid_address(unsigned char *addr)
+{
+ int seg;
+
+ for (seg = 0; seg < CYGBLD_REDBOOT_MAX_MEM_SEGMENTS; seg++) {
+ if (mem_segments[seg].start != NO_MEMORY) {
+ if ((addr >= mem_segments[seg].start) && (addr < mem_segments[seg].end)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/ecos/packages/redboot/current/src/mcmp.c b/ecos/packages/redboot/current/src/mcmp.c
new file mode 100644
index 0000000000..97f02770fc
--- /dev/null
+++ b/ecos/packages/redboot/current/src/mcmp.c
@@ -0,0 +1,135 @@
+//==========================================================================
+//
+// mcmp.c
+//
+// RedBoot memory compare (mcmp) routine
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2002-08-06
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+
+RedBoot_cmd("mcmp",
+ "Compare two blocks of memory",
+ "-s <location> -d <location> -l <length> [-1|-2|-4]",
+ do_mcmp
+ );
+
+void
+do_mcmp(int argc, char *argv[])
+{
+ // Fill a region of memory with a pattern
+ struct option_info opts[6];
+ unsigned long src_base, dst_base;
+ long len;
+ bool src_base_set, dst_base_set, len_set;
+ bool set_32bit, set_16bit, set_8bit;
+
+ init_opts(&opts[0], 's', true, OPTION_ARG_TYPE_NUM,
+ (void *)&src_base, (bool *)&src_base_set, "base address");
+ init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&len, (bool *)&len_set, "length");
+ init_opts(&opts[2], 'd', true, OPTION_ARG_TYPE_NUM,
+ (void *)&dst_base, (bool *)&dst_base_set, "base address");
+ init_opts(&opts[3], '4', false, OPTION_ARG_TYPE_FLG,
+ (void *)&set_32bit, (bool *)0, "fill 32 bit units");
+ init_opts(&opts[4], '2', false, OPTION_ARG_TYPE_FLG,
+ (void *)&set_16bit, (bool *)0, "fill 16 bit units");
+ init_opts(&opts[5], '1', false, OPTION_ARG_TYPE_FLG,
+ (void *)&set_8bit, (bool *)0, "fill 8 bit units");
+ if (!scan_opts(argc, argv, 1, opts, 6, 0, 0, "")) {
+ return;
+ }
+ if (!src_base_set || !dst_base_set || !len_set) {
+ diag_printf("usage: mcmp -s <addr> -d <addr> -l <length> [-1|-2|-4]\n");
+ return;
+ }
+
+
+
+ if (set_8bit) {
+ cyg_uint8 *s = (cyg_uint8 *)src_base;
+ cyg_uint8 *d = (cyg_uint8 *)dst_base;
+ while ((len -= sizeof(cyg_uint8)) >= 0) {
+ if (*s++ != *d++) {
+ s--;
+ d--;
+ diag_printf("Buffers don't match - %p=0x%02x, %p=0x%02x\n",
+ s, *s, d, *d);
+ return;
+ }
+
+ }
+ } else if (set_16bit) {
+ cyg_uint16 *s = (cyg_uint16 *)src_base;
+ cyg_uint16 *d = (cyg_uint16 *)dst_base;
+ while ((len -= sizeof(cyg_uint16)) >= 0) {
+ if (*s++ != *d++) {
+ s--;
+ d--;
+ diag_printf("Buffers don't match - %p=0x%04x, %p=0x%04x\n",
+ s, *s, d, *d);
+ return;
+ }
+
+ }
+ } else {
+ cyg_uint32 *s = (cyg_uint32 *)src_base;
+ cyg_uint32 *d = (cyg_uint32 *)dst_base;
+ while ((len -= sizeof(cyg_uint32)) >= 0) {
+ if (*s++ != *d++) {
+ s--;
+ d--;
+ diag_printf("Buffers don't match - %p=0x%08x, %p=0x%08x\n",
+ s, *s, d, *d);
+ return;
+ }
+ }
+ }
+}
diff --git a/ecos/packages/redboot/current/src/mcopy.c b/ecos/packages/redboot/current/src/mcopy.c
new file mode 100644
index 0000000000..d343f12d84
--- /dev/null
+++ b/ecos/packages/redboot/current/src/mcopy.c
@@ -0,0 +1,134 @@
+//==========================================================================
+//
+// mcopy.c
+//
+// RedBoot memory copy (mcopy) routine
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): msalter
+// Contributors: msalter
+// Date: 2003-07-01
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+
+static void
+do_mcopy(int argc, char *argv[])
+{
+ struct option_info opts[6];
+ unsigned long src, dst, len, end;
+ bool src_set, dst_set, len_set;
+ bool sz32, sz16, sz8;
+ int incr = 1;
+
+ init_opts(&opts[0], 's', true, OPTION_ARG_TYPE_NUM,
+ (void *)&src, (bool *)&src_set, "base address");
+ init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&len, (bool *)&len_set, "length");
+ init_opts(&opts[2], 'd', true, OPTION_ARG_TYPE_NUM,
+ (void *)&dst, (bool *)&dst_set, "base address");
+ init_opts(&opts[3], '4', false, OPTION_ARG_TYPE_FLG,
+ (void *)&sz32, (bool *)0, "copy 32 bit data");
+ init_opts(&opts[4], '2', false, OPTION_ARG_TYPE_FLG,
+ (void *)&sz16, (bool *)0, "copy 16 bit data");
+ init_opts(&opts[5], '1', false, OPTION_ARG_TYPE_FLG,
+ (void *)&sz8, (bool *)0, "copy 8 bit data");
+ if (!scan_opts(argc, argv, 1, opts, 6, 0, 0, "")) {
+ return;
+ }
+
+ // Must have src, dst, len. No more than one size specifier.
+ if (!src_set || !dst_set || !len_set || (sz32 + sz16 + sz8) > 1) {
+ diag_printf("usage: mcopy -s <addr> -d <addr> -l <length> [-1|-2|-4]\n");
+ return;
+ }
+
+ // adjust incr and len for data size
+ if (sz16) {
+ len = (len + 1) & ~1;
+ incr = 2;
+ } else if (sz32 || !sz8) {
+ len = (len + 3) & ~3;
+ incr = 4;
+ }
+
+ end = src + len;
+
+ // If overlapping areas, must copy backwards.
+ if (dst > src && dst < (src + len)) {
+ end = src - incr;
+ src += (len - incr);
+ dst += (len - incr);
+ incr = -incr;
+ }
+
+ if (sz8) {
+ while (src != end) {
+ *(cyg_uint8 *)dst = *(cyg_uint8 *)src;
+ src += incr;
+ dst += incr;
+ }
+ } else if (sz16) {
+ while (src != end) {
+ *(cyg_uint16 *)dst = *(cyg_uint16 *)src;
+ src += incr;
+ dst += incr;
+ }
+ } else {
+ // Default - 32 bits
+ while (src != end) {
+ *(cyg_uint32 *)dst = *(cyg_uint32 *)src;
+ src += incr;
+ dst += incr;
+ }
+ }
+}
+
+
+RedBoot_cmd("mcopy",
+ "Copy memory from one address to another",
+ "-s <location> -d <location> -l <length> [-1|-2|-4]",
+ do_mcopy
+ );
diff --git a/ecos/packages/redboot/current/src/mfill.c b/ecos/packages/redboot/current/src/mfill.c
new file mode 100644
index 0000000000..7f53353d1a
--- /dev/null
+++ b/ecos/packages/redboot/current/src/mfill.c
@@ -0,0 +1,113 @@
+//==========================================================================
+//
+// mfill.c
+//
+// RedBoot memory fill (mfill) routine
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2002-08-06
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+
+RedBoot_cmd("mfill",
+ "Fill a block of memory with a pattern",
+ "-b <location> -l <length> -p <pattern> [-1|-2|-4]",
+ do_mfill
+ );
+
+void
+do_mfill(int argc, char *argv[])
+{
+ // Fill a region of memory with a pattern
+ struct option_info opts[6];
+ unsigned long base, pat;
+ long len;
+ bool base_set, len_set, pat_set;
+ bool set_32bit, set_16bit, set_8bit;
+
+ init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
+ (void *)&base, (bool *)&base_set, "base address");
+ init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&len, (bool *)&len_set, "length");
+ init_opts(&opts[2], 'p', true, OPTION_ARG_TYPE_NUM,
+ (void *)&pat, (bool *)&pat_set, "pattern");
+ init_opts(&opts[3], '4', false, OPTION_ARG_TYPE_FLG,
+ (void *)&set_32bit, (bool *)0, "fill 32 bit units");
+ init_opts(&opts[4], '2', false, OPTION_ARG_TYPE_FLG,
+ (void *)&set_16bit, (bool *)0, "fill 16 bit units");
+ init_opts(&opts[5], '1', false, OPTION_ARG_TYPE_FLG,
+ (void *)&set_8bit, (bool *)0, "fill 8 bit units");
+ if (!scan_opts(argc, argv, 1, opts, 6, 0, 0, "")) {
+ return;
+ }
+ if (!base_set || !len_set) {
+ diag_printf("usage: mfill -b <addr> -l <length> [-p <pattern>] [-1|-2|-4]\n");
+ return;
+ }
+ if (!pat_set) {
+ pat = 0;
+ }
+ // No checks here
+
+ if (set_8bit) {
+ cyg_uint8 *p = (cyg_uint8 *)base;
+ while ((len -= sizeof(cyg_uint8)) >= 0)
+ *p++ = (cyg_uint8)pat;
+ } else if (set_16bit) {
+ cyg_uint16 *p = (cyg_uint16 *)base;
+ while ((len -= sizeof(cyg_uint16)) >= 0)
+ *p++ = (cyg_uint16)pat;
+ } else {
+ cyg_uint32 *p = (cyg_uint32 *)base;
+ while ((len -= sizeof(cyg_uint32)) >= 0)
+ *p++ = (cyg_uint32)pat;
+ }
+
+}
+
diff --git a/ecos/packages/redboot/current/src/misc_funs.c b/ecos/packages/redboot/current/src/misc_funs.c
new file mode 100644
index 0000000000..a4cda45529
--- /dev/null
+++ b/ecos/packages/redboot/current/src/misc_funs.c
@@ -0,0 +1,81 @@
+//==========================================================================
+//
+// misc_funs.c
+//
+// Miscellaneous [library] functions for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+
+int
+strcasecmp(const char *s1, const char *s2)
+{
+ char c1, c2;
+ while ((c1 = _tolower(*s1++)) == (c2 = _tolower(*s2++)))
+ if (c1 == 0)
+ return (0);
+ return ((unsigned char)c1 - (unsigned char)c2);
+}
+
+int
+strncasecmp(const char *s1, const char *s2, size_t len)
+{
+ char c1, c2;
+
+ if (len == 0)
+ return 0;
+ do {
+ if ((c1 = _tolower(*s1++)) != (c2 = _tolower(*s2++)))
+ return ((unsigned char)c1 - (unsigned char)c2);
+ if (c1 == 0)
+ break;
+ } while (--len != 0);
+ return 0;
+}
diff --git a/ecos/packages/redboot/current/src/net/arp.c b/ecos/packages/redboot/current/src/net/arp.c
new file mode 100644
index 0000000000..58b3fd2291
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/arp.c
@@ -0,0 +1,212 @@
+//==========================================================================
+//
+// net/arp.c
+//
+// Stand-alone ARP support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002, 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <net/net.h>
+
+static struct {
+ int waiting;
+ char *eth;
+ char *ip;
+} arp_req;
+
+/*
+ * Handle incoming ARP packets.
+ */
+void
+__arp_handler(pktbuf_t *pkt)
+{
+ arp_header_t *arp = pkt->arp_hdr;
+ int hw_type, protocol;
+
+ /*
+ * Only handle ethernet hardware and IP protocol.
+ */
+ protocol = ntohs(arp->protocol);
+ hw_type = ntohs(arp->hw_type);
+ if ((hw_type == ARP_HW_ETHER) && (protocol == ETH_TYPE_IP)) {
+ /*
+ * Handle requests for our ethernet address.
+ */
+ if (!memcmp(arp->target_ip, __local_ip_addr, 4)) {
+ if (ntohs(arp->opcode) == ARP_REQUEST) {
+ /* format response. */
+ arp->opcode = htons(ARP_REPLY);
+ memcpy(arp->target_ip, arp->sender_ip,
+ sizeof(ip_addr_t));
+ memcpy(arp->target_enet, arp->sender_enet,
+ sizeof(enet_addr_t));
+ memcpy(arp->sender_ip, __local_ip_addr,
+ sizeof(ip_addr_t));
+ memcpy(arp->sender_enet, __local_enet_addr,
+ sizeof(enet_addr_t));
+ pkt->pkt_bytes = sizeof(arp_header_t);
+ __enet_send(pkt, &arp->target_enet, ETH_TYPE_ARP);
+
+ } else if (ntohs(arp->opcode) == ARP_REPLY && arp_req.waiting) {
+ if (!memcmp(arp_req.ip, arp->sender_ip, sizeof(ip_addr_t))) {
+ memcpy(arp_req.eth, arp->sender_enet, sizeof(enet_addr_t));
+ arp_req.waiting = 0;
+ }
+ }
+ }
+ }
+ __pktbuf_free(pkt);
+}
+
+
+/*
+ * Find the ethernet address of the machine with the given
+ * ip address.
+ * Return 0 and fills in 'eth_addr' if successful,
+ * -1 if unsuccessful.
+ */
+int
+__arp_request(ip_addr_t *ip_addr, enet_addr_t *eth_addr, int allow_self)
+{
+ pktbuf_t *pkt;
+ arp_header_t *arp;
+ unsigned long retry_start;
+ enet_addr_t bcast_addr;
+ int retry;
+
+ if (!allow_self) {
+ // Special case request for self
+ if (!memcmp(ip_addr, __local_ip_addr, 4)) {
+ memcpy(eth_addr, __local_enet_addr, sizeof(enet_addr_t));
+ return 0;
+ }
+ }
+
+ /* just fail if can't get a buffer */
+ if ((pkt = __pktbuf_alloc(ARP_PKT_SIZE)) == NULL)
+ return -1;
+
+ arp = pkt->arp_hdr;
+ arp->opcode = htons(ARP_REQUEST);
+ arp->hw_type = htons(ARP_HW_ETHER);
+ arp->protocol = htons(0x800);
+ arp->hw_len = sizeof(enet_addr_t);
+ arp->proto_len = sizeof(ip_addr_t);
+
+ memcpy(arp->sender_ip, __local_ip_addr, sizeof(ip_addr_t));
+ memcpy(arp->sender_enet, __local_enet_addr, sizeof(enet_addr_t));
+ memcpy(arp->target_ip, ip_addr, sizeof(ip_addr_t));
+
+ bcast_addr[0] = 255;
+ bcast_addr[1] = 255;
+ bcast_addr[2] = 255;
+ bcast_addr[3] = 255;
+ bcast_addr[4] = 255;
+ bcast_addr[5] = 255;
+
+ arp_req.eth = (char *)eth_addr;
+ arp_req.ip = (char *)ip_addr;
+ arp_req.waiting = 1;
+
+ retry = 8;
+ while (retry-- > 0) {
+
+ /* send the packet */
+ pkt->pkt_bytes = sizeof(arp_header_t);
+ __enet_send(pkt, &bcast_addr, ETH_TYPE_ARP);
+
+ retry_start = MS_TICKS();
+ while ((MS_TICKS_DELAY() - retry_start) < 250) {
+ __enet_poll();
+ if (!arp_req.waiting) {
+ __pktbuf_free(pkt);
+ return 0;
+ }
+ }
+ }
+ __pktbuf_free(pkt);
+ return -1;
+}
+
+#define NUM_ARP 16
+static ip_route_t routes[NUM_ARP];
+
+int
+__arp_lookup(ip_addr_t *host, ip_route_t *rt)
+{
+ int i;
+ static int next_arp = 0;
+
+ for (i = 0; i < NUM_ARP; i++) {
+ if (memcmp(host, &routes[i].ip_addr, sizeof(*host)) == 0) {
+ // This is a known host
+ memcpy(rt, &routes[i], sizeof(*rt));
+ return 0;
+ }
+ }
+ memcpy(&rt->ip_addr, host, sizeof(*host));
+ if (((*host)[0] == 0xFF) && ((*host)[1] == 0xFF) && ((*host)[2] == 0xFF)) {
+ memset(&rt->enet_addr, 0xFF, sizeof(rt->enet_addr));
+ return 0;
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+ } else if (!__ip_addr_local(host)) {
+ // non-local IP address -- look up Gateway's Ethernet address
+ host = &__local_ip_gate;
+#endif
+ }
+ if (__arp_request(host, &rt->enet_addr, 0) < 0) {
+ return -1;
+ } else {
+ memcpy(&routes[next_arp], rt, sizeof(*rt));
+ if (++next_arp == NUM_ARP) next_arp = 0;
+ return 0;
+ }
+}
+
diff --git a/ecos/packages/redboot/current/src/net/bootp.c b/ecos/packages/redboot/current/src/net/bootp.c
new file mode 100644
index 0000000000..046017f4b0
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/bootp.c
@@ -0,0 +1,344 @@
+//==========================================================================
+//
+// net/bootp.c
+//
+// Stand-alone minimal BOOTP support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002, 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+#include <net/bootp.h>
+
+#define SHOULD_BE_RANDOM 0x12345555
+
+/* How many milliseconds to wait before retrying the request */
+#define RETRY_TIME 2000
+#define MAX_RETRIES 8
+
+static bootp_header_t *bp_info;
+
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+static const unsigned char dhcpCookie[] = {99,130,83,99};
+static const unsigned char dhcpEnd[] = {255};
+static const unsigned char dhcpDiscover[] = {53,1,1};
+static const unsigned char dhcpRequest[] = {53,1,3};
+static const unsigned char dhcpRequestIP[] = {50,4};
+static const unsigned char dhcpParamRequestList[] = {55,3,1,3,6};
+static enum {
+ DHCP_NONE = 0,
+ DHCP_DISCOVER,
+ DHCP_OFFER,
+ DHCP_REQUEST,
+ DHCP_ACK
+} dhcpState;
+#endif
+
+static void
+bootp_handler(udp_socket_t *skt, char *buf, int len,
+ ip_route_t *src_route, word src_port)
+{
+ bootp_header_t *b;
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+ unsigned char *p, expected = 0;
+#endif
+
+ b = (bootp_header_t *)buf;
+ if (bp_info) {
+ memset(bp_info,0,sizeof *bp_info);
+ if (len > sizeof *bp_info)
+ len = sizeof *bp_info;
+ memcpy(bp_info, b, len);
+ }
+
+ // Only accept pure REPLY responses
+ if (b->bp_op != BOOTREPLY)
+ return;
+
+ // Must be sent to me, as well!
+ if (memcmp(b->bp_chaddr, __local_enet_addr, 6))
+ return;
+
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+ p = b->bp_vend;
+ if (memcmp(p, dhcpCookie, sizeof(dhcpCookie)))
+ return;
+ p += 4;
+
+ // Find the DHCP Message Type tag
+ while (*p != TAG_DHCP_MESS_TYPE) {
+ p += p[1] + 2;
+ if (p >= (unsigned char*)b + sizeof(*bp_info))
+ return;
+ }
+
+ p += 2;
+
+ switch (dhcpState) {
+ case DHCP_DISCOVER:
+ // The discover message has been sent, only accept an offer reply
+ if (*p == DHCP_MESS_TYPE_OFFER) {
+ dhcpState = DHCP_OFFER;
+ return;
+ } else {
+ expected = DHCP_MESS_TYPE_OFFER;
+ }
+ break;
+ case DHCP_REQUEST:
+ // The request message has been sent, only accept an ack reply
+ if (*p == DHCP_MESS_TYPE_ACK) {
+ dhcpState = DHCP_ACK;
+ return;
+ } else {
+ expected = DHCP_MESS_TYPE_ACK;
+ }
+ break;
+ case DHCP_NONE:
+ case DHCP_OFFER:
+ case DHCP_ACK:
+ // Quitely ignore these - they indicate repeated message from server
+ return;
+ }
+ // See if we've been NAK'd - if so, give up and try again
+ if (*p == DHCP_MESS_TYPE_NAK) {
+ dhcpState = DHCP_NONE;
+ return;
+ }
+ diag_printf("DHCP reply: %d, not %d\n", (int)*p, (int)expected);
+ return;
+#else
+ // Simple BOOTP - this is all there is!
+ memcpy(__local_ip_addr, &b->bp_yiaddr, 4);
+#endif
+}
+
+#define AddOption(p,d) do {memcpy(p,d,sizeof d); p += sizeof d;} while (0)
+
+/*
+ * Find our IP address and copy to __local_ip_addr.
+ * Return zero if successful, -1 if not.
+ */
+int
+__bootp_find_local_ip(bootp_header_t *info)
+{
+ udp_socket_t udp_skt;
+ bootp_header_t b;
+ ip_route_t r;
+ int retry;
+ unsigned long start;
+ ip_addr_t saved_ip_addr;
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+ unsigned char *p;
+ int oldState;
+#endif
+ int txSize;
+ bool abort = false;
+ static int xid = SHOULD_BE_RANDOM;
+
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+ dhcpState = DHCP_NONE;
+#endif
+
+ // Where we want the results saved
+ bp_info = info;
+ // Preserve any IP address we currently have, just in case
+ memcpy(saved_ip_addr, __local_ip_addr, sizeof(__local_ip_addr));
+
+ // fill out route for a broadcast
+ r.ip_addr[0] = 255;
+ r.ip_addr[1] = 255;
+ r.ip_addr[2] = 255;
+ r.ip_addr[3] = 255;
+ r.enet_addr[0] = 255;
+ r.enet_addr[1] = 255;
+ r.enet_addr[2] = 255;
+ r.enet_addr[3] = 255;
+ r.enet_addr[4] = 255;
+ r.enet_addr[5] = 255;
+
+ // setup a socket listener for bootp replies
+ __udp_install_listener(&udp_skt, IPPORT_BOOTPC, bootp_handler);
+
+ retry = MAX_RETRIES;
+ do {
+ start = MS_TICKS();
+
+ // Build up the BOOTP/DHCP request
+ memset(&b, 0, sizeof(b));
+ b.bp_op = BOOTREQUEST;
+ b.bp_htype = HTYPE_ETHERNET;
+ b.bp_hlen = 6;
+ b.bp_xid = xid++;
+ memcpy(b.bp_chaddr, __local_enet_addr, 6);
+ memset(__local_ip_addr, 0, sizeof(__local_ip_addr));
+
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+ p = b.bp_vend;
+ switch (dhcpState) {
+ case DHCP_NONE:
+ case DHCP_DISCOVER:
+ AddOption(p,dhcpCookie);
+ AddOption(p,dhcpDiscover);
+ AddOption(p,dhcpParamRequestList);
+ AddOption(p,dhcpEnd);
+ dhcpState = DHCP_DISCOVER;
+ break;
+ case DHCP_OFFER:
+ retry = MAX_RETRIES;
+ case DHCP_REQUEST:
+ b.bp_xid = bp_info->bp_xid; // Match what server sent
+ AddOption(p,dhcpCookie);
+ AddOption(p,dhcpRequest);
+ AddOption(p,dhcpRequestIP);
+ memcpy(p, &bp_info->bp_yiaddr, 4); p += 4; // Ask for the address just given
+ AddOption(p,dhcpParamRequestList);
+ AddOption(p,dhcpEnd);
+ dhcpState = DHCP_REQUEST;
+ memset(&b.bp_yiaddr, 0xFF, 4);
+ memset(&b.bp_siaddr, 0xFF, 4);
+ memset(&b.bp_yiaddr, 0x00, 4);
+ memset(&b.bp_siaddr, 0x00, 4);
+ break;
+ case DHCP_ACK:
+ // Ignore these states (they won't happen)
+ break;
+ }
+
+ // Some servers insist on a minimum amount of "vendor" data
+ if (p < &b.bp_vend[BP_MIN_VEND_SIZE]) p = &b.bp_vend[BP_MIN_VEND_SIZE];
+ txSize = p - (unsigned char*)&b;
+ oldState = dhcpState;
+#else
+ txSize = sizeof(b);
+#endif
+
+ __udp_send((char *)&b, txSize, &r, IPPORT_BOOTPS, IPPORT_BOOTPC);
+
+ // If we're retrying, inform the user
+ if (retry == (MAX_RETRIES-1))
+ diag_printf("... waiting for BOOTP information\n");
+
+ do {
+ __enet_poll();
+#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
+ if (dhcpState != oldState) {
+ if (dhcpState == DHCP_ACK) {
+ unsigned char *end;
+ int optlen;
+ // Address information has now arrived!
+ memcpy(__local_ip_addr, &bp_info->bp_yiaddr, 4);
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+ memcpy(__local_ip_gate, &bp_info->bp_giaddr, 4);
+#endif
+ p = bp_info->bp_vend+4;
+ end = (unsigned char *)bp_info+sizeof(*bp_info);
+ while (p < end) {
+ unsigned char tag = *p;
+ if (tag == TAG_END)
+ break;
+ if (tag == TAG_PAD)
+ optlen = 1;
+ else {
+ optlen = p[1];
+ p += 2;
+ switch (tag) {
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+ case TAG_SUBNET_MASK: // subnet mask
+ memcpy(__local_ip_mask,p,4);
+ break;
+ case TAG_GATEWAY: // router
+ memcpy(__local_ip_gate,p,4);
+ break;
+#endif
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ case TAG_DOMAIN_SERVER:
+// diag_printf(" DNS server found!\n");
+ memcpy(&__bootp_dns_addr, p, 4);
+ __bootp_dns_set = 1;
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+ p += optlen;
+ }
+ __udp_remove_listener(IPPORT_BOOTPC);
+ return 0;
+ } else {
+ break; // State changed, handle it
+ }
+ }
+#else
+ // All done, if address response has arrived
+ if (__local_ip_addr[0] || __local_ip_addr[1] ||
+ __local_ip_addr[2] || __local_ip_addr[3]) {
+ /* success */
+ __udp_remove_listener(IPPORT_BOOTPC);
+ return 0;
+ }
+#endif
+ if (_rb_break(1)) {
+ // The user typed ^C on the console
+ abort = true;
+ break;
+ }
+ MS_TICKS_DELAY(); // Count for ^C test
+ } while ((MS_TICKS_DELAY() - start) < RETRY_TIME);
+ } while (!abort && (retry-- > 0));
+
+ // timed out
+ __udp_remove_listener(IPPORT_BOOTPC);
+ // Restore any previous IP address
+ memcpy(__local_ip_addr, saved_ip_addr, sizeof(__local_ip_addr));
+ return -1;
+}
+
+
diff --git a/ecos/packages/redboot/current/src/net/cksum.c b/ecos/packages/redboot/current/src/net/cksum.c
new file mode 100644
index 0000000000..6ccf5894e8
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/cksum.c
@@ -0,0 +1,124 @@
+//==========================================================================
+//
+// net/cksum.c
+//
+// Stand-alone network checksum support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <net/net.h>
+
+/*
+ * Do a one's complement checksum.
+ * The data being checksum'd is in network byte order.
+ * The returned checksum is in network byte order.
+ */
+unsigned short
+__sum(word *w, int len, int init_sum)
+{
+ int sum = init_sum;
+
+ union {
+ volatile unsigned char c[2];
+ volatile unsigned short s;
+ } su;
+
+ union {
+ volatile unsigned short s[2];
+ volatile int i;
+ } iu;
+
+ while ((len -= 2) >= 0)
+ sum += *w++;
+
+ if (len == -1) {
+ su.c[0] = *(char *)w;
+ su.c[1] = 0;
+ sum += su.s;
+ }
+
+ iu.i = sum;
+ sum = iu.s[0] + iu.s[1];
+ if (sum > 65535)
+ sum -= 65535;
+
+ su.s = ~sum;
+
+ return (su.c[0] << 8) | su.c[1];
+}
+
+
+/*
+ * Compute a partial checksum for the UDP/TCP pseudo header.
+ */
+int
+__pseudo_sum(ip_header_t *ip)
+{
+ int sum;
+ word *p;
+
+ union {
+ volatile unsigned char c[2];
+ volatile unsigned short s;
+ } su;
+
+ p = (word *)ip->source;
+ sum = *p++;
+ sum += *p++;
+ sum += *p++;
+ sum += *p++;
+
+ su.c[0] = 0;
+ su.c[1] = ip->protocol;
+ sum += su.s;
+
+ sum += ip->length;
+
+ return sum;
+}
diff --git a/ecos/packages/redboot/current/src/net/dns.c b/ecos/packages/redboot/current/src/net/dns.c
new file mode 100644
index 0000000000..c6cf392fbe
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/dns.c
@@ -0,0 +1,287 @@
+//=============================================================================
+//
+// dns.c
+//
+// DNS client code
+//
+//=============================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//=============================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): jskov
+// Contributors:jskov
+// Date: 2001-09-26
+// Description: Provides DNS lookup as per RFC 1034/1035.
+//
+// Note: This is a stripped down clone of dns.c from the CYGPKG_NS_DNS
+// package which does not use malloc/free and has been tweaked to
+// use UDP via RedBoot's network stack. Also adds commands
+// to set the DNS server IP at runtime.
+//
+//####DESCRIPTIONEND####
+//
+//=============================================================================
+
+#include <cyg/hal/drv_api.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_trac.h> /* Tracing support */
+
+#include <net/net.h>
+#include <redboot.h>
+/* #include <cyg/ns/dns/dns.h> - it's been moved to redboot.h */
+#include <cyg/ns/dns/dns_priv.h>
+
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+#include <flash_config.h>
+
+RedBoot_config_option("DNS server IP address",
+ dns_ip,
+ ALWAYS_ENABLED, true,
+ CONFIG_IP,
+ 0
+ );
+#endif
+
+/* So we remember which ports have been used */
+static int get_port = 7700;
+
+#define DOMAIN_PORT 53
+
+/* Some magic to make dns_impl.inl compile under RedBoot */
+#define sprintf diag_sprintf
+
+/* DNS server address possibly returned from bootp */
+struct in_addr __bootp_dns_addr;
+cyg_bool __bootp_dns_set = false;
+
+struct sockaddr_in server;
+
+/* static buffers so we can make do without malloc */
+static struct hostent _hent;
+static char* _h_addr_list[2];
+static struct in_addr _h_addr_list0;
+static int _hent_alloc = 0;
+
+#define _STRING_COUNT 2
+#define _STRING_LENGTH 64
+static char _strings[_STRING_COUNT][_STRING_LENGTH];
+static int _strings_alloc = 0;
+
+/* as in dns.c proper */
+static short id = 0; /* ID of the last query */
+static int s = -1; /* Socket to the DNS server */
+static cyg_drv_mutex_t dns_mutex; /* Mutex to stop multiple queries as once */
+static char * domainname=NULL; /* Domain name used for queries */
+
+
+/* Allocate space for string of length (len). Return NULL on
+ failure. */
+static char*
+alloc_string(int len)
+{
+ int i;
+
+ if (len > _STRING_LENGTH)
+ return NULL;
+
+ for (i = 0; i < _STRING_COUNT; i++) {
+ if (_strings_alloc & (1 << i)) continue;
+ _strings_alloc |= (1<<i);
+ return _strings[i];
+ }
+ return NULL;
+}
+
+static void
+free_string(char* s)
+{
+ int i;
+ for (i = 0; i < _STRING_COUNT; i++) {
+ if (_strings[i] == s) {
+ _strings_alloc &= ~(1<<i);
+ break;
+ }
+ }
+}
+
+/* Deallocate the memory taken to hold a hent structure */
+static void
+free_hent(struct hostent * hent)
+{
+ if (hent->h_name) {
+ free_string(hent->h_name);
+ }
+ _hent_alloc = 0;
+}
+
+/* Allocate hent structure with room for one in_addr. Returns NULL on
+ failure. */
+static struct hostent*
+alloc_hent(void)
+{
+ struct hostent *hent;
+
+ if (_hent_alloc) return NULL;
+
+ hent = &_hent;
+ memset(hent, 0, sizeof(struct hostent));
+ hent->h_addr_list = _h_addr_list;
+ hent->h_addr_list[0] = (char*)&_h_addr_list0;
+ hent->h_addr_list[1] = NULL;
+ _hent_alloc = 1;
+
+ return hent;
+}
+
+static __inline__ void
+free_stored_hent(void)
+{
+ free_hent( &_hent );
+}
+
+static __inline__ void
+store_hent(struct hostent *hent)
+{
+ hent=hent; // avoid warning
+}
+
+/* Send the query to the server and read the response back. Return -1
+ if it fails, otherwise put the response back in msg and return the
+ length of the response. */
+static int
+send_recv(char * msg, int len, int msglen)
+{
+ struct dns_header *dns_hdr;
+ int finished = false;
+ int read = 0;
+
+ dns_hdr = (struct dns_header *) msg;
+
+ do {
+ int len_togo = len;
+ struct timeval timeout;
+ struct sockaddr_in local_addr, from_addr;
+
+ memset((char *)&local_addr, 0, sizeof(local_addr));
+ local_addr.sin_family = AF_INET;
+ local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ local_addr.sin_port = htons(get_port++);
+
+ if (__udp_sendto(msg, len_togo, &server, &local_addr) < 0)
+ return -1;
+
+ memset((char *)&from_addr, 0, sizeof(from_addr));
+
+ timeout.tv_sec = CYGNUM_REDBOOT_NETWORKING_DNS_TIMEOUT;
+ timeout.tv_usec = 0;
+
+ read = __udp_recvfrom(msg, len, &from_addr, &local_addr, &timeout);
+ if (read < 0)
+ return -1;
+
+ /* Reply to an old query. Ignore it */
+ if (ntohs(dns_hdr->id) != (id-1)) {
+ continue;
+ }
+ finished = true;
+ } while (!finished);
+
+ return read;
+}
+
+void
+set_dns(char* new_ip)
+{
+ in_addr_t dns_ip;
+
+ memset(&server.sin_addr, 0, sizeof(server.sin_addr));
+ if (!inet_aton(new_ip, &dns_ip)) {
+ diag_printf("Bad DNS server address: %s\n", new_ip);
+ } else {
+ memcpy(&server.sin_addr, &dns_ip, sizeof(dns_ip));
+ /* server config is valid */
+ s = 0;
+ }
+}
+
+void
+show_dns(void)
+{
+ diag_printf(", DNS server IP: %s", inet_ntoa((in_addr_t *)&server.sin_addr));
+ if (0 == server.sin_addr.s_addr) {
+ s = -1;
+ }
+}
+
+/* Initialise the resolver. Open a socket and bind it to the address
+ of the server. return -1 if something goes wrong, otherwise 0 */
+int
+redboot_dns_res_init(void)
+{
+ memset((char *)&server, 0, sizeof(server));
+ server.sin_len = sizeof(server);
+ server.sin_family = AF_INET;
+ server.sin_port = htons(DOMAIN_PORT);
+ cyg_drv_mutex_init(&dns_mutex);
+
+ /* If we got a DNS server address from the DHCP/BOOTP, then use that address */
+ if ( __bootp_dns_set ) {
+ memcpy(&server.sin_addr, &__bootp_dns_addr, sizeof(__bootp_dns_addr) );
+ s = 0;
+ }
+ else {
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ {
+ ip_addr_t dns_ip;
+
+ flash_get_config("dns_ip", &dns_ip, CONFIG_IP);
+ if (dns_ip[0] == 0 && dns_ip[1] == 0 && dns_ip[2] == 0 && dns_ip[3] == 0)
+ return -1;
+ memcpy(&server.sin_addr, &dns_ip, sizeof(dns_ip));
+ /* server config is valid */
+ s = 0;
+ }
+#else
+ // Use static configuration
+ set_dns(__Xstr(CYGPKG_REDBOOT_NETWORKING_DNS_IP));
+#endif
+ }
+
+ return 0;
+}
+
+/* Include the DNS client implementation code */
+#include <cyg/ns/dns/dns_impl.inl>
diff --git a/ecos/packages/redboot/current/src/net/enet.c b/ecos/packages/redboot/current/src/net/enet.c
new file mode 100644
index 0000000000..6301c17ee6
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/enet.c
@@ -0,0 +1,248 @@
+//==========================================================================
+//
+// net/enet.c
+//
+// Stand-alone ethernet [link-layer] support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+#include <cyg/io/eth/eth_drv.h> // Logical driver interfaces
+
+//#define ENET_STATS 1
+
+#ifdef ENET_STATS
+static int num_ip = 0;
+static int num_arp = 0;
+#ifdef NET_SUPPORT_RARP
+static int num_rarp = 0;
+#endif
+static int num_received = 0;
+static int num_transmitted = 0;
+#endif
+
+//
+// Support for user handlers of additional ethernet packets (nonIP)
+//
+
+#define NUM_EXTRA_HANDLERS 4
+static struct {
+ int type;
+ pkt_handler_t handler;
+} eth_handlers[NUM_EXTRA_HANDLERS];
+
+pkt_handler_t
+__eth_install_listener(int eth_type, pkt_handler_t handler)
+{
+ int i, empty;
+ pkt_handler_t old;
+
+ if (eth_type > 0x800 || handler != (pkt_handler_t)0) {
+ empty = -1;
+ for (i = 0; i < NUM_EXTRA_HANDLERS; i++) {
+ if (eth_handlers[i].type == eth_type) {
+ // Replace existing handler
+ old = eth_handlers[i].handler;
+ eth_handlers[i].handler = handler;
+ return old;
+ }
+ if (eth_handlers[i].type == 0) {
+ empty = i;
+ }
+ }
+ if (empty >= 0) {
+ // Found a free slot
+ eth_handlers[empty].type = eth_type;
+ eth_handlers[empty].handler = handler;
+ return (pkt_handler_t)0;
+ }
+ }
+ diag_printf("** Warning: can't install listener for ethernet type 0x%02x\n", eth_type);
+ return (pkt_handler_t)0;
+}
+
+void
+__eth_remove_listener(int eth_type)
+{
+ int i;
+
+ for (i = 0; i < NUM_EXTRA_HANDLERS; i++) {
+ if (eth_handlers[i].type == eth_type) {
+ eth_handlers[i].type = 0;
+ }
+ }
+}
+
+/*
+ * Non-blocking poll of ethernet link. Process packets until no more
+ * are available.
+ */
+void
+__enet_poll(void)
+{
+ pktbuf_t *pkt;
+ eth_header_t eth_hdr;
+ int i, type;
+#ifdef DEBUG_PKT_EXHAUSTION
+ static bool was_exhausted = false;
+#endif
+
+ while (true) {
+ /*
+ * Try to get a free pktbuf and return if none
+ * are available.
+ */
+ if ((pkt = __pktbuf_alloc(ETH_MAX_PKTLEN)) == NULL) {
+#ifdef DEBUG_PKT_EXHAUSTION
+ if (!was_exhausted) {
+ int old = start_console(); // Force output to standard port
+ diag_printf("__enet_poll: no more buffers\n");
+ __pktbuf_dump();
+ was_exhausted = true;
+ end_console(old);
+ }
+#endif
+ return;
+ }
+#ifdef DEBUG_PKT_EXHAUSTION
+ was_exhausted = false; // Report the next time we're out of buffers
+#endif
+
+ if ((pkt->pkt_bytes = eth_drv_read((char *)&eth_hdr, (char *)pkt->buf,
+ ETH_MAX_PKTLEN)) > 0) {
+#ifdef ENET_STATS
+ ++num_received;
+#endif
+ switch (type = ntohs(eth_hdr.type)) {
+
+ case ETH_TYPE_IP:
+#ifdef ENET_STATS
+ ++num_ip;
+#endif
+ pkt->ip_hdr = (ip_header_t *)pkt->buf;
+ __ip_handler(pkt, &eth_hdr.source);
+ break;
+
+ case ETH_TYPE_ARP:
+#ifdef ENET_STATS
+ ++num_arp;
+#endif
+ pkt->arp_hdr = (arp_header_t *)pkt->buf;
+ __arp_handler(pkt);
+ break;
+
+#ifdef NET_SUPPORT_RARP
+ case ETH_TYPE_RARP:
+#ifdef ENET_STATS
+ ++num_rarp;
+#endif
+ pkt->arp_hdr = (arp_header_t *)pkt->buf;
+ __rarp_handler(pkt);
+ break;
+#endif
+
+ default:
+ if (type > 0x800) {
+ for (i = 0; i < NUM_EXTRA_HANDLERS; i++) {
+ if (eth_handlers[i].type == type) {
+ (eth_handlers[i].handler)(pkt, &eth_hdr);
+ }
+ }
+ }
+ __pktbuf_free(pkt);
+ break;
+ }
+ } else {
+ __pktbuf_free(pkt);
+ break;
+ }
+ }
+}
+
+
+
+/*
+ * Send an ethernet packet.
+ */
+void
+__enet_send(pktbuf_t *pkt, enet_addr_t *dest, int eth_type)
+{
+ eth_header_t eth_hdr;
+
+ // Set up ethernet header
+ memcpy(&eth_hdr.destination, dest, sizeof(enet_addr_t));
+ memcpy(&eth_hdr.source, __local_enet_addr, sizeof(enet_addr_t));
+ eth_hdr.type = htons(eth_type);
+
+ eth_drv_write((char *)&eth_hdr, (char *)pkt->buf, pkt->pkt_bytes);
+#ifdef ENET_STATS
+ ++num_transmitted;
+#endif
+}
+
+#ifdef __LITTLE_ENDIAN__
+
+unsigned long
+ntohl(unsigned long x)
+{
+ return (((x & 0x000000FF) << 24) |
+ ((x & 0x0000FF00) << 8) |
+ ((x & 0x00FF0000) >> 8) |
+ ((x & 0xFF000000) >> 24));
+}
+
+unsigned short
+ntohs(unsigned short x)
+{
+ return (((x & 0x00FF) << 8) |
+ ((x & 0xFF00) >> 8));
+}
+
+#endif
diff --git a/ecos/packages/redboot/current/src/net/http_client.c b/ecos/packages/redboot/current/src/net/http_client.c
new file mode 100644
index 0000000000..47bb480517
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/http_client.c
@@ -0,0 +1,255 @@
+//==========================================================================
+//
+// net/http_client.c
+//
+// Stand-alone HTTP support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002, 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2002-05-22
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// HTTP client support
+
+#include <redboot.h> // have_net
+#include <net/net.h>
+#include <net/http.h>
+
+// So we remember which ports have been used
+static int get_port = 7800;
+
+static struct _stream{
+ bool open;
+ int avail, actual_len, pos, filelen;
+ char data[4096];
+ char *bufp;
+ tcp_socket_t sock;
+} http_stream;
+
+static __inline__ int
+min(int a, int b)
+{
+ if (a < b)
+ return a;
+ else
+ return b;
+}
+
+int
+http_stream_open(connection_info_t *info, int *err)
+{
+ int res;
+ struct _stream *s = &http_stream;
+
+ if (!info->server->sin_port)
+ info->server->sin_port = 80; // HTTP port
+ if ((res = __tcp_open(&s->sock, info->server, get_port++, 5000, err)) < 0) {
+ *err = HTTP_OPEN;
+ return -1;
+ }
+ diag_sprintf(s->data, "GET %s HTTP/1.0\r\n\r\n", info->filename);
+ __tcp_write_block(&s->sock, s->data, strlen(s->data));
+ s->avail = 0;
+ s->open = true;
+ s->pos = 0;
+ return 0;
+}
+
+void
+http_stream_close(int *err)
+{
+ struct _stream *s = &http_stream;
+
+ if (s->open) {
+ __tcp_abort(&s->sock,1);
+ s->open = false;
+ }
+}
+
+int
+http_stream_read(char *buf,
+ int len,
+ int *err)
+{
+ struct _stream *s = &http_stream;
+ int total = 0;
+ int cnt, code;
+
+ if (!s->open) {
+ return -1; // Shouldn't happen, but...
+ }
+ while (len) {
+ while (s->avail == 0) {
+ // Need to wait for some data to arrive
+ __tcp_poll();
+ if (s->sock.state != _ESTABLISHED) {
+ if (s->sock.state == _CLOSE_WAIT) {
+ // This connection is breaking
+ if (s->sock.data_bytes == 0 && s->sock.rxcnt == 0) {
+ __tcp_close(&s->sock);
+ return total;
+ }
+ } else if (s->sock.state == _CLOSED) {
+ // The connection is gone
+ s->open = false;
+ return -1;
+ } else {
+ *err = HTTP_IO;
+ return -1;
+ }
+ }
+ s->actual_len = __tcp_read(&s->sock, s->data, sizeof(s->data));
+ if (s->actual_len > 0) {
+ s->bufp = s->data;
+ s->avail = s->actual_len;
+ if (s->pos == 0) {
+ // First data - need to scan HTTP response header
+ if (strncmp(s->bufp, "HTTP/", 5) == 0) {
+ // Should look like "HTTP/1.1 200 OK"
+ s->bufp += 5;
+ s->avail -= 5;
+ // Find first space
+ while ((s->avail > 0) && (*s->bufp != ' ')) {
+ s->bufp++;
+ s->avail--;
+ }
+ // Now the integer response
+ code = 0;
+ while ((s->avail > 0) && (*s->bufp == ' ')) {
+ s->bufp++;
+ s->avail--;
+ }
+ while ((s->avail > 0) && isdigit(*s->bufp)) {
+ code = (code * 10) + (*s->bufp - '0');
+ s->bufp++;
+ s->avail--;
+ }
+ // Make sure it says OK
+ while ((s->avail > 0) && (*s->bufp == ' ')) {
+ s->bufp++;
+ s->avail--;
+ }
+ if (strncmp(s->bufp, "OK", 2)) {
+ switch (code) {
+ case 400:
+ *err = HTTP_BADREQ;
+ break;
+ case 404:
+ *err = HTTP_NOFILE;
+ break;
+ default:
+ *err = HTTP_BADHDR;
+ break;
+ }
+ return -1;
+ }
+ // Find \r\n\r\n - end of HTTP preamble
+ while (s->avail >= 4) {
+ // This could be done faster, but not simpler
+ if (strncmp(s->bufp, "\r\n\r\n", 4) == 0) {
+ s->bufp += 4;
+ s->avail -= 4;
+#if 0 // DEBUG - show header
+ *(s->bufp-2) = '\0';
+ diag_printf(s->data);
+#endif
+ break;
+ }
+ s->avail--;
+ s->bufp++;
+ }
+ s->pos++;
+ } else {
+ // Unrecognized response
+ *err = HTTP_BADHDR;
+ return -1;
+ }
+ }
+ } else if (s->actual_len < 0) {
+ *err = HTTP_IO;
+ return -1;
+ }
+ }
+ cnt = min(len, s->avail);
+ memcpy(buf, s->bufp, cnt);
+ s->avail -= cnt;
+ s->bufp += cnt;
+ buf += cnt;
+ total += cnt;
+ len -= cnt;
+ }
+ return total;
+}
+
+char *
+http_error(int err)
+{
+ char *errmsg = "Unknown error";
+
+ switch (err) {
+ case HTTP_NOERR:
+ return "";
+ case HTTP_BADHDR:
+ return "Unrecognized HTTP response";
+ case HTTP_BADREQ:
+ return "Bad HTTP request (check file name)";
+ case HTTP_NOFILE:
+ return "No such file";
+ case HTTP_OPEN:
+ return "Can't connect to host";
+ case HTTP_IO:
+ return "I/O error";
+ }
+ return errmsg;
+}
+
+//
+// RedBoot interface
+//
+GETC_IO_FUNCS(http_io, http_stream_open, http_stream_close,
+ 0, http_stream_read, http_error);
+RedBoot_load(http, http_io, true, true, 0);
diff --git a/ecos/packages/redboot/current/src/net/icmp.c b/ecos/packages/redboot/current/src/net/icmp.c
new file mode 100644
index 0000000000..c5f5380d77
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/icmp.c
@@ -0,0 +1,126 @@
+//==========================================================================
+//
+// net/icmp.c
+//
+// Stand-alone ICMP networking support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <net/net.h>
+
+/*
+ * Handle ICMP packets.
+ */
+static void default_icmp_handler(pktbuf_t *pkt, ip_route_t *dest);
+
+static icmp_handler_t icmp_handler = default_icmp_handler;
+
+/*
+ * Install a user defined user_handler for incoming icmp packets.
+ * Returns zero if successful, -1 if the user_handler is already used.
+ */
+int
+__icmp_install_listener(icmp_handler_t user_handler)
+{
+ if (icmp_handler == user_handler) {
+ return -1;
+ }
+ icmp_handler = user_handler;
+ return 0;
+}
+
+
+/*
+ * Replace a user defined handler by the default handler.
+ */
+void
+__icmp_remove_listener(void)
+{
+ if (icmp_handler != default_icmp_handler) {
+ icmp_handler = default_icmp_handler;
+ }
+}
+
+/*
+ * ICMP entry point with an IP packet pkt and the destination dest a reply
+ * should be sent to.
+ */
+void
+__icmp_handler(pktbuf_t *pkt, ip_route_t *dest)
+{
+ (*icmp_handler)(pkt, dest);
+
+ BSPLOG(bsp_log("icmp: dest[%s] type[%d] seq[%d]\n",
+ inet_ntoa(pkt->ip_hdr->destination),
+ pkt->icmp_hdr->type,
+ pkt->icmp_hdr->seqnum));
+ __pktbuf_free(pkt);
+}
+
+
+/*
+ * The default ICMP handler only handles ICMP incoming echo request and
+ * outgoing echo reply.
+ */
+static void
+default_icmp_handler(pktbuf_t *pkt, ip_route_t *dest)
+{
+ word cksum;
+
+ if (pkt->icmp_hdr->type == ICMP_TYPE_ECHOREQUEST
+ && pkt->icmp_hdr->code == 0
+ && __sum((word *)pkt->icmp_hdr, pkt->pkt_bytes, 0) == 0) {
+
+ pkt->icmp_hdr->type = ICMP_TYPE_ECHOREPLY;
+ pkt->icmp_hdr->checksum = 0;
+ cksum = __sum((word *)pkt->icmp_hdr, pkt->pkt_bytes, 0);
+ pkt->icmp_hdr->checksum = htons(cksum);
+ __ip_send(pkt, IP_PROTO_ICMP, dest);
+ }
+}
diff --git a/ecos/packages/redboot/current/src/net/inet_addr.c b/ecos/packages/redboot/current/src/net/inet_addr.c
new file mode 100644
index 0000000000..0d4d8f1db0
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/inet_addr.c
@@ -0,0 +1,118 @@
+//==========================================================================
+//
+// net/inet_addr.c
+//
+// Stand-alone IP address parsing for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+
+bool
+inet_aton(const char *s, in_addr_t *addr)
+{
+ int i, val, radix, digit;
+ unsigned long res = 0;
+ bool first;
+ char c;
+
+ for (i = 0; i < 4; i++) {
+ // Parse next digit string
+ first = true;
+ val = 0;
+ radix = 10;
+ while ((c = *s++) != '\0') {
+ if (first && (c == '0') && (_tolower(*s) == 'x')) {
+ radix = 16;
+ s++; // Skip over 0x
+ c = *s++;
+ }
+ first = false;
+ if (_is_hex(c) && ((digit = _from_hex(c)) < radix)) {
+ // Valid digit
+ val = (val * radix) + digit;
+ } else if (c == '.' && i < 3) { // all but last terminate by '.'
+ break;
+ } else {
+ return false;
+ }
+ }
+ // merge result
+#ifdef __LITTLE_ENDIAN__
+ res |= val << ((3-i)*8); // 24, 16, 8, 0
+#else
+ res = (res << 8) | val;
+#endif
+ if ('\0' == c) {
+ if (0 == i) { // first field found end of string
+ res = val; // no shifting, use it as the whole thing
+ break; // permit entering a single number
+ }
+ if (3 > i) // we found end of string before getting 4 fields
+ return false;
+ }
+ // after that we check that it was 0..255 only
+ if (val &~0xff) return false;
+ }
+ addr->s_addr = htonl(res);
+ return true;
+}
+
+// Assumes address is in network byte order
+char *
+inet_ntoa(in_addr_t *addr)
+{
+ static char str[32];
+ unsigned char *ap;
+
+ ap = (unsigned char *)addr;
+ diag_sprintf(str, "%d.%d.%d.%d", ap[0], ap[1], ap[2], ap[3]);
+ return str;
+}
diff --git a/ecos/packages/redboot/current/src/net/ip.c b/ecos/packages/redboot/current/src/net/ip.c
new file mode 100644
index 0000000000..0e26591248
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/ip.c
@@ -0,0 +1,216 @@
+//==========================================================================
+//
+// net/ip.c
+//
+// Stand-alone IP networking support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <net/net.h>
+
+#ifndef CYGDAT_REDBOOT_DEFAULT_IP_ADDR
+# define CYGDAT_REDBOOT_DEFAULT_IP_ADDR 0, 0, 0, 0
+#endif
+#ifndef CYGDAT_REDBOOT_DEFAULT_IP_ADDR_MASK
+# define CYGDAT_REDBOOT_DEFAULT_IP_ADDR_MASK 255, 255, 255, 0
+#endif
+#ifndef CYGDAT_REDBOOT_DEFAULT_GATEWAY_IP_ADDR
+# define CYGDAT_REDBOOT_DEFAULT_GATEWAY_IP_ADDR 0, 0, 0, 0
+#endif
+
+ip_addr_t __local_ip_addr = { CYGDAT_REDBOOT_DEFAULT_IP_ADDR };
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+ip_addr_t __local_ip_mask = { CYGDAT_REDBOOT_DEFAULT_IP_ADDR_MASK };
+ip_addr_t __local_ip_gate = { CYGDAT_REDBOOT_DEFAULT_GATEWAY_IP_ADDR };
+#endif
+
+static word ip_ident;
+
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+/*
+ * See if an address is on the local network
+ */
+int
+__ip_addr_local(ip_addr_t *addr)
+{
+ return !(
+ ((__local_ip_addr[0] ^ (*addr)[0]) & __local_ip_mask[0]) |
+ ((__local_ip_addr[1] ^ (*addr)[1]) & __local_ip_mask[1]) |
+ ((__local_ip_addr[2] ^ (*addr)[2]) & __local_ip_mask[2]) |
+ ((__local_ip_addr[3] ^ (*addr)[3]) & __local_ip_mask[3]));
+}
+#endif
+
+/*
+ * Match given IP address to our address.
+ * Check for broadcast matches as well.
+ */
+static int
+ip_addr_match(ip_addr_t addr)
+{
+ if (addr[0] == 255 && addr[1] == 255 && addr[2] == 255 && addr[3] == 255)
+ return 1;
+
+ if (!memcmp(addr, __local_ip_addr, sizeof(ip_addr_t)))
+ return 1;
+
+ /*
+ * Consider it an address match if we haven't gotten our IP address yet.
+ * Some DHCP servers will address IP packets to the assigned address
+ * instead of a IP broadcast address.
+ */
+ if (__local_ip_addr[0] == 0 && __local_ip_addr[1] == 0 &&
+ __local_ip_addr[2] == 0 && __local_ip_addr[3] == 0)
+ return 1;
+
+ return 0;
+}
+
+
+extern void __tcp_handler(pktbuf_t *, ip_route_t *);
+
+/*
+ * Handle IP packets coming from the polled ethernet interface.
+ */
+void
+__ip_handler(pktbuf_t *pkt, enet_addr_t *src_enet_addr)
+{
+ ip_header_t *ip = pkt->ip_hdr;
+ ip_route_t r;
+ int hdr_bytes;
+
+ /* first make sure its ours and has a good checksum. */
+ if (!ip_addr_match(ip->destination) ||
+ __sum((word *)ip, ip->hdr_len << 2, 0) != 0) {
+ __pktbuf_free(pkt);
+ return;
+ }
+
+ memcpy(r.ip_addr, ip->source, sizeof(ip_addr_t));
+ memcpy(r.enet_addr, src_enet_addr, sizeof(enet_addr_t));
+
+ hdr_bytes = ip->hdr_len << 2;
+ pkt->pkt_bytes = ntohs(ip->length) - hdr_bytes;
+
+ switch (ip->protocol) {
+
+#if NET_SUPPORT_ICMP
+ case IP_PROTO_ICMP:
+ pkt->icmp_hdr = (icmp_header_t *)(((char *)ip) + hdr_bytes);
+ __icmp_handler(pkt, &r);
+ break;
+#endif
+
+#if NET_SUPPORT_TCP
+ case IP_PROTO_TCP:
+ pkt->tcp_hdr = (tcp_header_t *)(((char *)ip) + hdr_bytes);
+ __tcp_handler(pkt, &r);
+ break;
+#endif
+
+#if NET_SUPPORT_UDP
+ case IP_PROTO_UDP:
+ pkt->udp_hdr = (udp_header_t *)(((char *)ip) + hdr_bytes);
+ __udp_handler(pkt, &r);
+ break;
+#endif
+
+ default:
+ __pktbuf_free(pkt);
+ break;
+ }
+}
+
+
+/*
+ * Send an IP packet.
+ *
+ * The IP data field should contain pkt->pkt_bytes of data.
+ * pkt->[udp|tcp|icmp]_hdr points to the IP data field. Any
+ * IP options are assumed to be already in place in the IP
+ * options field.
+ */
+int
+__ip_send(pktbuf_t *pkt, int protocol, ip_route_t *dest)
+{
+ ip_header_t *ip = pkt->ip_hdr;
+ int hdr_bytes;
+ unsigned short cksum;
+
+ /*
+ * Figure out header length. The use udp_hdr is
+ * somewhat arbitrary, but works because it is
+ * a union with other IP protocol headers.
+ */
+ hdr_bytes = (((char *)pkt->udp_hdr) - ((char *)ip));
+
+ pkt->pkt_bytes += hdr_bytes;
+
+ ip->version = 4;
+ ip->hdr_len = hdr_bytes >> 2;
+ ip->tos = 0;
+ ip->length = htons(pkt->pkt_bytes);
+ ip->ident = htons(ip_ident);
+ ip_ident++;
+ ip->fragment = 0;
+ ip->ttl = 255;
+ ip->ttl = 64;
+ ip->protocol = protocol;
+ ip->checksum = 0;
+ memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
+ memcpy(ip->destination, dest->ip_addr, sizeof(ip_addr_t));
+ cksum = __sum((word *)ip, hdr_bytes, 0);
+ ip->checksum = htons(cksum);
+
+ __enet_send(pkt, &dest->enet_addr, ETH_TYPE_IP);
+ return 0;
+}
+
+
diff --git a/ecos/packages/redboot/current/src/net/net_io.c b/ecos/packages/redboot/current/src/net/net_io.c
new file mode 100644
index 0000000000..a8cd8ed35a
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/net_io.c
@@ -0,0 +1,899 @@
+//==========================================================================
+//
+// net/net_io.c
+//
+// Stand-alone network logical I/O support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
+// Copyright (C) 2002, 2003, 2004 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+#include <cyg/hal/hal_misc.h> // Helper functions
+#include <cyg/hal/hal_if.h> // HAL I/O interfaces
+#include <cyg/hal/drv_api.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+#include <flash_config.h>
+
+RedBoot_config_option("GDB connection port",
+ gdb_port,
+ ALWAYS_ENABLED, true,
+ CONFIG_INT,
+ CYGNUM_REDBOOT_NETWORKING_TCP_PORT
+ );
+RedBoot_config_option("Network debug at boot time",
+ net_debug,
+ ALWAYS_ENABLED, true,
+ CONFIG_BOOL,
+ false
+ );
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+RedBoot_config_option("Default network device",
+ net_device,
+ ALWAYS_ENABLED, true,
+ CONFIG_NETPORT,
+ CYGDAT_REDBOOT_DEFAULT_NETWORK_DEVICE
+ );
+#endif
+// Note: the following options are related. If 'bootp' is false, then
+// the other values are used in the configuration. Because of the way
+// that configuration tables are generated, they should have names which
+// are related. The configuration options will show up lexicographically
+// ordered, thus the peculiar naming. In this case, the 'use' option is
+// negated (if false, the others apply) which makes the names even more
+// confusing.
+
+#ifndef CYGSEM_REDBOOT_DEFAULT_NO_BOOTP
+#define CYGSEM_REDBOOT_DEFAULT_NO_BOOTP 0
+#endif
+RedBoot_config_option("Use BOOTP for network configuration",
+ bootp,
+ ALWAYS_ENABLED, true,
+ CONFIG_BOOL,
+ !CYGSEM_REDBOOT_DEFAULT_NO_BOOTP
+ );
+RedBoot_config_option("Local IP address",
+ bootp_my_ip,
+ "bootp", false,
+ CONFIG_IP,
+ 0
+ );
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+RedBoot_config_option("Local IP address mask",
+ bootp_my_ip_mask,
+ "bootp", false,
+ CONFIG_IP,
+ 0
+ );
+RedBoot_config_option("Gateway IP address",
+ bootp_my_gateway_ip,
+ "bootp", false,
+ CONFIG_IP,
+ 0
+ );
+#endif
+RedBoot_config_option("Default server IP address",
+ bootp_server_ip,
+ ALWAYS_ENABLED, true,
+ CONFIG_IP,
+ 0
+ );
+
+// Note: the following options are related too.
+RedBoot_config_option("Force console for special debug messages",
+ info_console_force,
+ ALWAYS_ENABLED, true,
+ CONFIG_BOOL,
+ false
+ );
+RedBoot_config_option("Console number for special debug messages",
+ info_console_number,
+ "info_console_force", true,
+ CONFIG_INT,
+ 0
+ );
+#endif
+
+#define TCP_CHANNEL CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS
+
+#ifdef DEBUG_TCP
+int show_tcp = 0;
+#endif
+
+static tcp_socket_t tcp_sock;
+static int state;
+static int _timeout = 500;
+static int orig_console, orig_debug;
+
+static int in_buflen = 0;
+static unsigned char in_buf[64];
+static unsigned char *in_bufp;
+static int out_buflen = 0;
+static unsigned char out_buf[1024];
+static unsigned char *out_bufp;
+static bool flush_output_lines = false;
+
+// Functions in this module
+static void net_io_flush(void);
+static void net_io_revert_console(void);
+static void net_io_putc(void*, cyg_uint8);
+
+// Special characters used by Telnet - must be interpretted here
+#define TELNET_IAC 0xFF // Interpret as command (escape)
+#define TELNET_IP 0xF4 // Interrupt process
+#define TELNET_WONT 0xFC // I Won't do it
+#define TELNET_DO 0xFD // Will you XXX
+#define TELNET_TM 0x06 // Time marker (special DO/WONT after IP)
+
+static cyg_bool
+_net_io_getc_nonblock(void* __ch_data, cyg_uint8* ch)
+{
+ if (in_buflen == 0) {
+ __tcp_poll();
+ if (tcp_sock.state == _CLOSE_WAIT) {
+ // This connection is breaking
+ if (tcp_sock.data_bytes == 0 && tcp_sock.rxcnt == 0) {
+ __tcp_close(&tcp_sock);
+ return false;
+ }
+ }
+ if (tcp_sock.state == _CLOSED) {
+ // The connection is gone
+ net_io_revert_console();
+ *ch = '\n';
+ return true;
+ }
+ in_buflen = __tcp_read(&tcp_sock, in_buf, sizeof(in_buf));
+ in_bufp = in_buf;
+#ifdef DEBUG_TCP
+ if (show_tcp && (in_buflen > 0)) {
+ int old_console;
+ old_console = start_console();
+ diag_printf("%s:%d\n", __FUNCTION__, __LINE__);
+ diag_dump_buf(in_buf, in_buflen);
+ end_console(old_console);
+ }
+#endif // DEBUG_TCP
+ }
+ if (in_buflen) {
+ *ch = *in_bufp++;
+ in_buflen--;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static cyg_bool
+net_io_getc_nonblock(void* __ch_data, cyg_uint8* ch)
+{
+ cyg_uint8 esc;
+
+ if (!_net_io_getc_nonblock(__ch_data, ch))
+ return false;
+
+ if (gdb_active || *ch != TELNET_IAC)
+ return true;
+
+ // Telnet escape - need to read/handle more
+ while (!_net_io_getc_nonblock(__ch_data, &esc)) ;
+
+ switch (esc) {
+ case TELNET_IAC:
+ // The other special case - escaped escape
+ return true;
+ case TELNET_IP:
+ // Special case for ^C == Interrupt Process
+ *ch = 0x03;
+ // Just in case the other end needs synchronizing
+ net_io_putc(__ch_data, TELNET_IAC);
+ net_io_putc(__ch_data, TELNET_WONT);
+ net_io_putc(__ch_data, TELNET_TM);
+ net_io_flush();
+ return true;
+ case TELNET_DO:
+ // Telnet DO option
+ while (!_net_io_getc_nonblock(__ch_data, &esc)) ;
+ // Respond with WONT option
+ net_io_putc(__ch_data, TELNET_IAC);
+ net_io_putc(__ch_data, TELNET_WONT);
+ net_io_putc(__ch_data, esc);
+ return false; // Ignore this whole thing!
+ default:
+ return false;
+ }
+}
+
+static cyg_uint8
+net_io_getc(void* __ch_data)
+{
+ cyg_uint8 ch;
+ int idle_timeout = 10; // 10ms
+
+ CYGARC_HAL_SAVE_GP();
+ while (true) {
+ if (net_io_getc_nonblock(__ch_data, &ch)) break;
+ if (--idle_timeout == 0) {
+ net_io_flush();
+ idle_timeout = 10;
+ }
+ }
+ CYGARC_HAL_RESTORE_GP();
+ return ch;
+}
+
+static void
+net_io_flush(void)
+{
+ int n;
+ char *bp = out_buf;
+
+#ifdef DEBUG_TCP
+ if (show_tcp) {
+ int old_console;
+ old_console = start_console();
+ diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
+ diag_dump_buf(out_buf, out_buflen);
+ end_console(old_console);
+ }
+#endif // SHOW_TCP
+ n = __tcp_write_block(&tcp_sock, bp, out_buflen);
+ if (n < 0) {
+ // The connection is gone!
+ net_io_revert_console();
+ } else {
+ out_buflen -= n;
+ bp += n;
+ }
+ out_bufp = out_buf; out_buflen = 0;
+ // Check interrupt flag
+ if (CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG()) {
+ CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG_SET(0);
+ cyg_hal_user_break(0);
+ }
+}
+
+static void
+net_io_putc(void* __ch_data, cyg_uint8 c)
+{
+ static bool have_dollar, have_hash;
+ static int hash_count;
+
+ CYGARC_HAL_SAVE_GP();
+ *out_bufp++ = c;
+ if (c == '$') have_dollar = true;
+ if (have_dollar && (c == '#')) {
+ have_hash = true;
+ hash_count = 0;
+ }
+ if ((++out_buflen == sizeof(out_buf)) ||
+ (flush_output_lines && c == '\n') ||
+ (have_hash && (++hash_count == 3))) {
+ net_io_flush();
+ have_dollar = false;
+ }
+ CYGARC_HAL_RESTORE_GP();
+}
+
+static void
+net_io_write(void* __ch_data, const cyg_uint8* __buf, cyg_uint32 __len)
+{
+ int old_console;
+
+ old_console = start_console();
+ diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
+ end_console(old_console);
+#if 0
+ CYGARC_HAL_SAVE_GP();
+
+ while(__len-- > 0)
+ net_io_putc(__ch_data, *__buf++);
+
+ CYGARC_HAL_RESTORE_GP();
+#endif
+}
+
+static void
+net_io_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
+{
+ int old_console;
+
+ old_console = start_console();
+ diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
+ end_console(old_console);
+#if 0
+ CYGARC_HAL_SAVE_GP();
+
+ while(__len-- > 0)
+ *__buf++ = net_io_getc(__ch_data);
+
+ CYGARC_HAL_RESTORE_GP();
+#endif
+}
+
+static cyg_bool
+net_io_getc_timeout(void* __ch_data, cyg_uint8* ch)
+{
+ int delay_count;
+ cyg_bool res;
+
+ CYGARC_HAL_SAVE_GP();
+ net_io_flush(); // Make sure any output has been sent
+ delay_count = _timeout;
+
+ for(;;) {
+ res = net_io_getc_nonblock(__ch_data, ch);
+ if (res || 0 == delay_count--)
+ break;
+ }
+
+ CYGARC_HAL_RESTORE_GP();
+
+ return res;
+}
+
+static int
+net_io_control(void *__ch_data, __comm_control_cmd_t __func, ...)
+{
+ static int vector = 0;
+ int ret = 0;
+ static int irq_state = 0;
+
+ CYGARC_HAL_SAVE_GP();
+
+ switch (__func) {
+ case __COMMCTL_IRQ_ENABLE:
+ irq_state = 1;
+ if (vector == 0) {
+ vector = eth_drv_int_vector();
+ }
+ HAL_INTERRUPT_UNMASK(vector);
+ break;
+ case __COMMCTL_IRQ_DISABLE:
+ ret = irq_state;
+ irq_state = 0;
+ if (vector == 0) {
+ vector = eth_drv_int_vector();
+ }
+ HAL_INTERRUPT_MASK(vector);
+ break;
+ case __COMMCTL_DBG_ISR_VECTOR:
+ ret = vector;
+ break;
+ case __COMMCTL_SET_TIMEOUT:
+ {
+ va_list ap;
+
+ va_start(ap, __func);
+
+ ret = _timeout;
+ _timeout = va_arg(ap, cyg_uint32);
+
+ va_end(ap);
+ break;
+ }
+ case __COMMCTL_FLUSH_OUTPUT:
+ net_io_flush();
+ break;
+ case __COMMCTL_ENABLE_LINE_FLUSH:
+ flush_output_lines = true;
+ break;
+ case __COMMCTL_DISABLE_LINE_FLUSH:
+ flush_output_lines = false;
+ break;
+ default:
+ break;
+ }
+ CYGARC_HAL_RESTORE_GP();
+ return ret;
+}
+
+static int
+net_io_isr(void *__ch_data, int* __ctrlc,
+ CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
+{
+ char ch;
+
+ CYGARC_HAL_SAVE_GP();
+ *__ctrlc = 0;
+ if (net_io_getc_nonblock(__ch_data, &ch)) {
+ if (ch == 0x03) {
+ *__ctrlc = 1;
+ }
+ }
+ CYGARC_HAL_RESTORE_GP();
+ return CYG_ISR_HANDLED;
+}
+
+// TEMP
+
+int
+start_console(void)
+{
+ int cur_console =
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ int i = 0;
+ if ( flash_get_config( "info_console_force", &i, CONFIG_BOOL) )
+ if ( i )
+ if ( ! flash_get_config( "info_console_number", &i, CONFIG_INT) )
+ i = 0; // the default, if that call failed.
+ if ( i )
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
+ else
+#endif
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
+
+ return cur_console;
+}
+
+void
+end_console(int old_console)
+{
+ // Restore original console
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(old_console);
+}
+// TEMP
+
+static void
+net_io_revert_console(void)
+{
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+ console_selected = false;
+#endif
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(orig_console);
+ CYGACC_CALL_IF_SET_DEBUG_COMM(orig_debug);
+ console_echo = true;
+}
+
+static void
+net_io_assume_console(void)
+{
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+ console_selected = true;
+#endif
+ console_echo = false;
+ orig_console = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(TCP_CHANNEL);
+ orig_debug = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ CYGACC_CALL_IF_SET_DEBUG_COMM(TCP_CHANNEL);
+}
+
+static void
+net_io_init(void)
+{
+ static int init = 0;
+ if (!init) {
+ hal_virtual_comm_table_t* comm;
+ int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+
+ // Setup procs in the vector table
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(TCP_CHANNEL);
+ comm = CYGACC_CALL_IF_CONSOLE_PROCS();
+ //CYGACC_COMM_IF_CH_DATA_SET(*comm, chan);
+ CYGACC_COMM_IF_WRITE_SET(*comm, net_io_write);
+ CYGACC_COMM_IF_READ_SET(*comm, net_io_read);
+ CYGACC_COMM_IF_PUTC_SET(*comm, net_io_putc);
+ CYGACC_COMM_IF_GETC_SET(*comm, net_io_getc);
+ CYGACC_COMM_IF_CONTROL_SET(*comm, net_io_control);
+ CYGACC_COMM_IF_DBG_ISR_SET(*comm, net_io_isr);
+ CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, net_io_getc_timeout);
+
+ // Disable interrupts via this interface to set static
+ // state into correct state.
+ net_io_control( comm, __COMMCTL_IRQ_DISABLE );
+
+ // Restore original console
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
+
+ init = 1;
+ gdb_active = false;
+ }
+ __tcp_listen(&tcp_sock, gdb_port);
+ state = tcp_sock.state;
+#ifdef DEBUG_TCP
+ diag_printf("show tcp = %p\n", (void *)&show_tcp);
+#endif
+}
+
+// Check for incoming TCP debug connection
+void
+net_io_test(bool is_idle)
+{
+ if (!is_idle) return; // Only care about idle case
+ if (!have_net) return;
+ __tcp_poll();
+ if (state != tcp_sock.state) {
+ // Something has changed
+ if (tcp_sock.state == _ESTABLISHED) {
+ // A new connection has arrived
+ net_io_assume_console();
+ in_bufp = in_buf; in_buflen = 1; *in_bufp = '\r';
+ out_bufp = out_buf; out_buflen = 0;
+ }
+ if (tcp_sock.state == _CLOSED) {
+ net_io_init(); // Get ready for another connection
+ }
+ }
+ state = tcp_sock.state;
+}
+
+// This schedules the 'net_io_test()' function to be run by RedBoot's
+// main command loop when idle (i.e. when no input arrives after some
+// period of time).
+RedBoot_idle(net_io_test, RedBoot_IDLE_NETIO);
+
+//
+// Network initialization
+//
+#include <cyg/io/eth/eth_drv.h>
+#include <cyg/io/eth/netdev.h>
+#include <cyg/hal/hal_tables.h>
+
+// Define table boundaries
+CYG_HAL_TABLE_BEGIN( __NETDEVTAB__, netdev );
+CYG_HAL_TABLE_END( __NETDEVTAB_END__, netdev );
+
+RedBoot_init(net_init, RedBoot_INIT_LAST);
+
+static void
+show_addrs(void)
+{
+ diag_printf("IP: %s", inet_ntoa((in_addr_t *)&__local_ip_addr));
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+ diag_printf("/%s", inet_ntoa((in_addr_t *)&__local_ip_mask));
+ diag_printf(", Gateway: %s\n", inet_ntoa((in_addr_t *)&__local_ip_gate));
+#else
+ diag_printf(", ");
+#endif
+ diag_printf("Default server: %s", inet_ntoa(&my_bootp_info.bp_siaddr));
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ show_dns();
+#endif
+ diag_printf("\n");
+}
+
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+static void
+flash_get_IP(char *id, ip_addr_t *val)
+{
+ ip_addr_t my_ip;
+ int i;
+
+ if (flash_get_config(id, &my_ip, CONFIG_IP)) {
+ if (my_ip[0] != 0 || my_ip[1] != 0 ||
+ my_ip[2] != 0 || my_ip[3] != 0) {
+ // 'id' is set to something so let it override any static IP
+ for (i=0; i<4; i++)
+ (*val)[i] = my_ip[i];
+ }
+ }
+}
+#endif
+
+static cyg_netdevtab_entry_t *
+net_devtab_entry(unsigned index)
+{
+ cyg_netdevtab_entry_t *t = &__NETDEVTAB__[index];
+
+ if (t < &__NETDEVTAB__[0] || t >= &__NETDEVTAB_END__)
+ return NULL;
+
+ return t;
+}
+
+const char *
+net_devname(unsigned index)
+{
+ cyg_netdevtab_entry_t *t = net_devtab_entry(index);
+ if (t)
+ return t->name;
+ return NULL;
+}
+
+int
+net_devindex(char *name)
+{
+ const char *devname;
+ int index;
+
+ for (index = 0; (devname = net_devname(index)) != NULL; index++)
+ if (!strcmp(name, devname))
+ return index;
+ return -1;
+}
+
+static void
+show_eth_info(void)
+{
+ diag_printf("Ethernet %s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ __local_enet_sc->dev_name,
+ __local_enet_addr[0],
+ __local_enet_addr[1],
+ __local_enet_addr[2],
+ __local_enet_addr[3],
+ __local_enet_addr[4],
+ __local_enet_addr[5]);
+}
+
+void
+net_init(void)
+{
+ cyg_netdevtab_entry_t *t;
+ unsigned index;
+ struct eth_drv_sc *primary_net = (struct eth_drv_sc *)0;
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ char *default_devname;
+ int default_index;
+#endif
+#ifdef CYGDAT_REDBOOT_DEFAULT_BOOTP_SERVER_IP_ADDR
+ char ip_addr[16];
+#endif
+
+ // Set defaults as appropriate
+#ifdef CYGSEM_REDBOOT_DEFAULT_NO_BOOTP
+ use_bootp = false;
+#else
+ use_bootp = true;
+#endif
+#ifdef CYGDBG_REDBOOT_NET_DEBUG
+ net_debug = true;
+#else
+ net_debug = false;
+#endif
+ gdb_port = CYGNUM_REDBOOT_NETWORKING_TCP_PORT;
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ // Fetch values from saved config data, if available
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ flash_get_config("net_device", &default_devname, CONFIG_NETPORT);
+#endif
+ flash_get_config("net_debug", &net_debug, CONFIG_BOOL);
+ flash_get_config("gdb_port", &gdb_port, CONFIG_INT);
+ flash_get_config("bootp", &use_bootp, CONFIG_BOOL);
+ if (!use_bootp) {
+ flash_get_IP("bootp_my_ip", &__local_ip_addr);
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+ flash_get_IP("bootp_my_ip_mask", &__local_ip_mask);
+ flash_get_IP("bootp_my_gateway_ip", &__local_ip_gate);
+#endif
+ }
+#endif
+# ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
+ // Don't override if the user has deliberately set something more
+ // verbose.
+ if (0 == cyg_io_eth_net_debug)
+ cyg_io_eth_net_debug = net_debug;
+# endif
+ have_net = false;
+ // Make sure the recv buffers are set up
+ eth_drv_buffers_init();
+ __pktbuf_init();
+
+ // Initialize network device(s).
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ default_index = net_devindex(default_devname);
+ if (default_index < 0)
+ default_index = 0;
+#ifdef CYGSEM_REDBOOT_NETWORK_INIT_ONE_DEVICE
+ if ((t = net_devtab_entry(default_index)) != NULL && t->init(t)) {
+ t->status = CYG_NETDEVTAB_STATUS_AVAIL;
+ primary_net = __local_enet_sc;
+ } else
+#endif
+#endif
+ for (index = 0; (t = net_devtab_entry(index)) != NULL; index++) {
+#ifdef CYGSEM_REDBOOT_NETWORK_INIT_ONE_DEVICE
+ if (index == default_index)
+ continue;
+#endif
+ if (t->init(t)) {
+ t->status = CYG_NETDEVTAB_STATUS_AVAIL;
+ if (primary_net == (struct eth_drv_sc *)0) {
+ primary_net = __local_enet_sc;
+ }
+#if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
+ if (index == default_index) {
+ primary_net = __local_enet_sc;
+ }
+#endif
+ }
+ }
+ __local_enet_sc = primary_net;
+
+ if (!__local_enet_sc) {
+ diag_printf("No network interfaces found\n");
+ return;
+ }
+ // Initialize the network [if present]
+ if (use_bootp) {
+ if (__bootp_find_local_ip(&my_bootp_info) == 0) {
+ have_net = true;
+ } else {
+ // Is it an unset address, or has it been set to a static addr
+ if (__local_ip_addr[0] == 0 && __local_ip_addr[1] == 0 &&
+ __local_ip_addr[2] == 0 && __local_ip_addr[3] == 0) {
+ show_eth_info();
+ diag_printf("Can't get BOOTP info for device!\n");
+ } else {
+ diag_printf("Can't get BOOTP info, using default IP address\n");
+ have_net = true;
+ }
+ }
+ } else {
+ if (__local_ip_addr[0] == 0 && __local_ip_addr[1] == 0 &&
+ __local_ip_addr[2] == 0 && __local_ip_addr[3] == 0) {
+ show_eth_info();
+ diag_printf("No IP info for device!\n");
+ } else {
+ enet_addr_t enet_addr;
+ have_net = true; // Assume values in FLASH were OK
+ // Tell the world that we are using this fixed IP address
+ if (__arp_request((ip_addr_t *)__local_ip_addr, &enet_addr, 1) >= 0) {
+ diag_printf("Warning: IP address %s in use\n", inet_ntoa((in_addr_t *)&__local_ip_addr));
+ }
+ }
+ }
+ if (have_net) {
+ show_eth_info();
+#ifdef CYGDAT_REDBOOT_DEFAULT_BOOTP_SERVER_IP_ADDR
+ diag_sprintf(ip_addr, "%d.%d.%d.%d",
+ CYGDAT_REDBOOT_DEFAULT_BOOTP_SERVER_IP_ADDR);
+ inet_aton(ip_addr, &my_bootp_info.bp_siaddr);
+#endif
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ flash_get_IP("bootp_server_ip", (ip_addr_t *)&my_bootp_info.bp_siaddr);
+#endif
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ redboot_dns_res_init();
+#endif
+ show_addrs();
+ net_io_init();
+ }
+}
+
+static char usage[] = "[-b] [-l <local_ip_address>[/<mask_len>]] [-h <server_address>]"
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ " [-d <dns_server_address]"
+#endif
+ ;
+
+// Exported CLI function
+static void do_ip_addr(int argc, char *argv[]);
+RedBoot_cmd("ip_address",
+ "Set/change IP addresses",
+ usage,
+ do_ip_addr
+ );
+
+void
+do_ip_addr(int argc, char *argv[])
+{
+ struct option_info opts[4];
+ char *ip_addr, *host_addr;
+ bool ip_addr_set, host_addr_set;
+ bool do_bootp = false;
+ struct sockaddr_in host;
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ char *dns_addr;
+ bool dns_addr_set;
+#endif
+ int num_opts;
+
+ init_opts(&opts[0], 'l', true, OPTION_ARG_TYPE_STR,
+ (void *)&ip_addr, (bool *)&ip_addr_set, "local IP address");
+ init_opts(&opts[1], 'h', true, OPTION_ARG_TYPE_STR,
+ (void *)&host_addr, (bool *)&host_addr_set, "default server address");
+ init_opts(&opts[2], 'b', false, OPTION_ARG_TYPE_FLG,
+ &do_bootp, 0, "use BOOTP");
+ num_opts = 3;
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ init_opts(&opts[num_opts], 'd', true, OPTION_ARG_TYPE_STR,
+ (void *)&dns_addr, (bool *)&dns_addr_set, "DNS server address");
+ num_opts++;
+#endif
+
+ CYG_ASSERT(num_opts <= NUM_ELEMS(opts), "Too many options");
+
+ if (!scan_opts(argc, argv, 1, opts, num_opts, 0, 0, "")) {
+ return;
+ }
+ if (do_bootp) {
+ if (__bootp_find_local_ip(&my_bootp_info) != 0) {
+ diag_printf("Failed to get BOOTP address\n");
+ }
+ }
+ if (ip_addr_set) {
+#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
+ char *slash_pos;
+ /* see if the (optional) mask length was given */
+ if( (slash_pos = strchr(ip_addr, '/')) ) {
+ int mask_len;
+ unsigned long mask;
+ *slash_pos = '\0';
+ slash_pos++;
+ if( !parse_num(slash_pos, (unsigned long *)&mask_len, 0, 0) ||
+ mask_len <= 0 || mask_len > 32 ) {
+ diag_printf("Invalid mask length: %s\n", slash_pos);
+ return;
+ }
+ mask = htonl((0xffffffff << (32-mask_len))&0xffffffff);
+ memcpy(&__local_ip_mask, &mask, 4);
+ }
+#endif
+ if (!_gethostbyname(ip_addr, (in_addr_t *)&host)) {
+ diag_printf("Invalid local IP address: %s\n", ip_addr);
+ return;
+ }
+ // Of course, each address goes in its own place :-)
+ memcpy(&__local_ip_addr, &host.sin_addr, sizeof(host.sin_addr));
+ }
+ if (host_addr_set) {
+ if (!_gethostbyname(host_addr, (in_addr_t *)&host)) {
+ diag_printf("Invalid server address: %s\n", host_addr);
+ return;
+ }
+ my_bootp_info.bp_siaddr = host.sin_addr;
+ }
+#ifdef CYGPKG_REDBOOT_NETWORKING_DNS
+ if (dns_addr_set) {
+ set_dns(dns_addr);
+ }
+#endif
+ show_addrs();
+ if (!have_net) {
+ have_net = true;
+ net_io_init();
+ }
+}
+
+// EOF net_io.c
diff --git a/ecos/packages/redboot/current/src/net/ping.c b/ecos/packages/redboot/current/src/net/ping.c
new file mode 100644
index 0000000000..74dcb0712a
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/ping.c
@@ -0,0 +1,248 @@
+//==========================================================================
+//
+// ping.c
+//
+// Network utility - ping
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2001-01-22
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+
+#ifndef CYGPKG_REDBOOT_NETWORKING
+#error CYGPKG_REDBOOT_NETWORKING required!
+#else
+
+static void do_ping(int argc, char *argv[]);
+RedBoot_cmd("ping",
+ "Network connectivity test",
+ "[-v] [-n <count>] [-l <length>] [-t <timeout>] [-r <rate>]\n"
+ " [-i <IP_addr>] -h <IP_addr>",
+ do_ping
+ );
+
+static bool icmp_received;
+static icmp_header_t hold_hdr;
+
+static void
+handle_icmp(pktbuf_t *pkt, ip_route_t *src_route)
+{
+ icmp_header_t *icmp;
+ unsigned short cksum;
+
+ icmp = pkt->icmp_hdr;
+ if (icmp->type == ICMP_TYPE_ECHOREQUEST
+ && icmp->code == 0
+ && __sum((word *)icmp, pkt->pkt_bytes, 0) == 0) {
+
+ icmp->type = ICMP_TYPE_ECHOREPLY;
+ icmp->checksum = 0;
+ cksum = __sum((word *)icmp, pkt->pkt_bytes, 0);
+ icmp->checksum = htons(cksum);
+ __ip_send(pkt, IP_PROTO_ICMP, src_route);
+ } else if (icmp->type == ICMP_TYPE_ECHOREPLY) {
+ memcpy(&hold_hdr, icmp, sizeof(*icmp));
+ icmp_received = true;
+ }
+}
+
+static void
+do_ping(int argc, char *argv[])
+{
+ struct option_info opts[7];
+ long count, timeout, length, rate, start_time, end_time, timer, received, tries;
+ char *local_ip_addr, *host_ip_addr;
+ bool local_ip_addr_set, host_ip_addr_set, count_set,
+ timeout_set, length_set, rate_set, verbose;
+ struct sockaddr_in local_addr, host_addr;
+ ip_addr_t hold_addr;
+ icmp_header_t *icmp;
+ pktbuf_t *pkt;
+ ip_header_t *ip;
+ unsigned short cksum;
+ ip_route_t dest_ip;
+
+ init_opts(&opts[0], 'n', true, OPTION_ARG_TYPE_NUM,
+ (void *)&count, (bool *)&count_set, "<count> - number of packets to test");
+ init_opts(&opts[1], 't', true, OPTION_ARG_TYPE_NUM,
+ (void *)&timeout, (bool *)&timeout_set, "<timeout> - max #ms per packet [rount trip]");
+ init_opts(&opts[2], 'i', true, OPTION_ARG_TYPE_STR,
+ (void *)&local_ip_addr, (bool *)&local_ip_addr_set, "local IP address");
+ init_opts(&opts[3], 'h', true, OPTION_ARG_TYPE_STR,
+ (void *)&host_ip_addr, (bool *)&host_ip_addr_set, "host name or IP address");
+ init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM,
+ (void *)&length, (bool *)&length_set, "<length> - size of payload");
+ init_opts(&opts[5], 'v', false, OPTION_ARG_TYPE_FLG,
+ (void *)&verbose, (bool *)0, "verbose operation");
+ init_opts(&opts[6], 'r', true, OPTION_ARG_TYPE_NUM,
+ (void *)&rate, (bool *)&rate_set, "<rate> - time between packets");
+ if (!scan_opts(argc, argv, 1, opts, 7, (void **)0, 0, "")) {
+ diag_printf("PING - Invalid option specified\n");
+ return;
+ }
+ // Set defaults; this has to be done _after_ the scan, since it will
+ // have destroyed all values not explicitly set.
+ if (local_ip_addr_set) {
+ if (!_gethostbyname(local_ip_addr, (in_addr_t *)&local_addr)) {
+ diag_printf("PING - Invalid local name: %s\n", local_ip_addr);
+ return;
+ }
+ } else {
+ memcpy((in_addr_t *)&local_addr, __local_ip_addr, sizeof(__local_ip_addr));
+ }
+ if (host_ip_addr_set) {
+ if (!_gethostbyname(host_ip_addr, (in_addr_t *)&host_addr)) {
+ diag_printf("PING - Invalid host name: %s\n", host_ip_addr);
+ return;
+ }
+ if (__arp_lookup((ip_addr_t *)&host_addr.sin_addr, &dest_ip) < 0) {
+ diag_printf("PING: Cannot reach server '%s' (%s)\n",
+ host_ip_addr, inet_ntoa((in_addr_t *)&host_addr));
+ return;
+ }
+ } else {
+ diag_printf("PING - host name or IP address required\n");
+ return;
+ }
+#define DEFAULT_LENGTH 64
+#define DEFAULT_COUNT 10
+#define DEFAULT_TIMEOUT 1000
+#define DEFAULT_RATE 1000
+ if (!rate_set) {
+ rate = DEFAULT_RATE;
+ }
+ if (!length_set) {
+ length = DEFAULT_LENGTH;
+ }
+ if ((length < 64) || (length > 1400)) {
+ diag_printf("Invalid length specified: %ld\n", length);
+ return;
+ }
+ if (!count_set) {
+ count = DEFAULT_COUNT;
+ }
+ if (!timeout_set) {
+ timeout = DEFAULT_TIMEOUT;
+ }
+ // Note: two prints here because 'inet_ntoa' returns a static pointer
+ diag_printf("Network PING - from %s",
+ inet_ntoa((in_addr_t *)&local_addr));
+ diag_printf(" to %s\n",
+ inet_ntoa((in_addr_t *)&host_addr));
+ received = 0;
+ __icmp_install_listener(handle_icmp);
+ // Save default "local" address
+ memcpy(hold_addr, __local_ip_addr, sizeof(hold_addr));
+ for (tries = 0; tries < count; tries++) {
+ // The network stack uses the global variable '__local_ip_addr'
+ memcpy(__local_ip_addr, &local_addr, sizeof(__local_ip_addr));
+ // Build 'ping' request
+ if ((pkt = __pktbuf_alloc(ETH_MAX_PKTLEN)) == NULL) {
+ // Give up if no packets - something is wrong
+ break;
+ }
+
+ icmp = pkt->icmp_hdr;
+ ip = pkt->ip_hdr;
+ pkt->pkt_bytes = length + sizeof(icmp_header_t);
+
+ icmp->type = ICMP_TYPE_ECHOREQUEST;
+ icmp->code = 0;
+ icmp->checksum = 0;
+ icmp->seqnum = htons(tries+1);
+ cksum = __sum((word *)icmp, pkt->pkt_bytes, 0);
+ icmp->checksum = htons(cksum);
+
+ memcpy(ip->source, (in_addr_t *)&local_addr, sizeof(ip_addr_t));
+ memcpy(ip->destination, (in_addr_t *)&host_addr, sizeof(ip_addr_t));
+ ip->protocol = IP_PROTO_ICMP;
+ ip->length = htons(pkt->pkt_bytes);
+
+ __ip_send(pkt, IP_PROTO_ICMP, &dest_ip);
+ __pktbuf_free(pkt);
+
+ start_time = MS_TICKS();
+ timer = start_time + timeout;
+ icmp_received = false;
+ while (!icmp_received && (MS_TICKS_DELAY() < timer)) {
+ if (_rb_break(1)) {
+ goto abort;
+ }
+ MS_TICKS_DELAY();
+ __enet_poll();
+ }
+ end_time = MS_TICKS();
+
+ timer = MS_TICKS() + rate;
+ while (MS_TICKS_DELAY() < timer) {
+ if (_rb_break(1)) {
+ goto abort;
+ }
+ MS_TICKS_DELAY();
+ __enet_poll();
+ }
+
+ if (icmp_received) {
+ received++;
+ if (verbose) {
+ diag_printf(" seq: %d, time: %ld (ticks)\n",
+ ntohs(hold_hdr.seqnum), end_time-start_time);
+ }
+ }
+ }
+ abort:
+ __icmp_remove_listener();
+ // Clean up
+ memcpy(__local_ip_addr, &hold_addr, sizeof(__local_ip_addr));
+ // Report
+ diag_printf("PING - received %ld of %ld expected\n", received, count);
+}
+
+#endif //CYGPKG_REDBOOT_NETWORKING
diff --git a/ecos/packages/redboot/current/src/net/pktbuf.c b/ecos/packages/redboot/current/src/net/pktbuf.c
new file mode 100644
index 0000000000..584e84befa
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/pktbuf.c
@@ -0,0 +1,167 @@
+//==========================================================================
+//
+// net/pktbuf.c
+//
+// Stand-alone network packet support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+
+#define MAX_PKTBUF CYGNUM_REDBOOT_NETWORKING_MAX_PKTBUF
+
+#define BUFF_STATS 1
+
+#if BUFF_STATS
+int max_alloc = 0;
+int num_alloc = 0;
+int num_free = 0;
+#endif
+
+static pktbuf_t pktbuf_list[MAX_PKTBUF];
+static word bufdata[MAX_PKTBUF][ETH_MAX_PKTLEN/2 + 1];
+static pktbuf_t *free_list;
+
+
+/*
+ * Initialize the free list.
+ */
+void
+__pktbuf_init(void)
+{
+ int i;
+ word *p;
+ static int init = 0;
+
+ if (init) return;
+ init = 1;
+
+ for (i = 0; i < MAX_PKTBUF; i++) {
+ p = bufdata[i];
+ if ((((unsigned long)p) & 2) != 0)
+ ++p;
+ pktbuf_list[i].buf = p;
+ pktbuf_list[i].bufsize = ETH_MAX_PKTLEN;
+ pktbuf_list[i].next = free_list;
+ free_list = &pktbuf_list[i];
+ }
+}
+
+void
+__pktbuf_dump(void)
+{
+ int i;
+ for (i = 0; i < MAX_PKTBUF; i++) {
+ diag_printf("Buf[%d]/%p: buf: %p, len: %d/%d, next: %p\n",
+ i,
+ (void*)&pktbuf_list[i],
+ (void*)pktbuf_list[i].buf,
+ pktbuf_list[i].bufsize,
+ pktbuf_list[i].pkt_bytes,
+ (void*)pktbuf_list[i].next);
+ }
+ diag_printf("Free list = %p\n", (void*)free_list);
+}
+
+/*
+ * simple pktbuf allocation
+ */
+pktbuf_t *
+__pktbuf_alloc(int nbytes)
+{
+ pktbuf_t *p = free_list;
+
+ if (p) {
+ free_list = p->next;
+ p->ip_hdr = (ip_header_t *)p->buf;
+ p->tcp_hdr = (tcp_header_t *)(p->ip_hdr + 1);
+ p->pkt_bytes = 0;
+#if BUFF_STATS
+ ++num_alloc;
+ if ((num_alloc - num_free) > max_alloc)
+ max_alloc = num_alloc - num_free;
+#endif
+ }
+ return p;
+}
+
+
+/*
+ * free a pktbuf.
+ */
+void
+__pktbuf_free(pktbuf_t *pkt)
+{
+#if BUFF_STATS
+ --num_alloc;
+#endif
+#ifdef BSP_LOG
+ {
+ int i;
+ word *p;
+
+ for (i = 0; i < MAX_PKTBUF; i++) {
+ p = bufdata[i];
+ if ((((unsigned long)p) & 2) == 0)
+ ++p;
+ if (p == (word *)pkt)
+ break;
+ }
+ if (i < MAX_PKTBUF) {
+ BSPLOG(bsp_log("__pktbuf_free: bad pkt[%x].\n", pkt));
+ BSPLOG(while(1));
+ }
+ }
+#endif
+ pkt->next = free_list;
+ free_list = pkt;
+}
+
+
diff --git a/ecos/packages/redboot/current/src/net/tcp.c b/ecos/packages/redboot/current/src/net/tcp.c
new file mode 100644
index 0000000000..44fde44d08
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/tcp.c
@@ -0,0 +1,921 @@
+//==========================================================================
+//
+// net/tcp.c
+//
+// Stand-alone TCP networking support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <net/net.h>
+#include <cyg/infra/diag.h>
+#include <cyg/hal/hal_if.h>
+
+#define MAX_TCP_SEGMENT (ETH_MAX_PKTLEN - (sizeof(eth_header_t) + sizeof(ip_header_t)))
+#define MAX_TCP_DATA (MAX_TCP_SEGMENT - sizeof(tcp_header_t))
+
+
+/* sequence number comparison macros */
+#define SEQ_LT(a,b) ((int)((a)-(b)) < 0)
+#define SEQ_LE(a,b) ((int)((a)-(b)) <= 0)
+#define SEQ_GT(a,b) ((int)((a)-(b)) > 0)
+#define SEQ_GE(a,b) ((int)((a)-(b)) >= 0)
+
+/* Set a timer which will send an RST and abort a connection. */
+static timer_t abort_timer;
+
+static void do_retrans(void *p);
+static void do_close(void *p);
+
+#ifdef BSP_LOG
+static char *
+flags_to_str(octet f)
+{
+ static char str[7], *p;
+
+ p = str;
+
+ if (f & TCP_FLAG_FIN)
+ *p++ = 'F';
+ if (f & TCP_FLAG_SYN)
+ *p++ = 'S';
+ if (f & TCP_FLAG_RST)
+ *p++ = 'R';
+ if (f & TCP_FLAG_PSH)
+ *p++ = 'P';
+ if (f & TCP_FLAG_ACK)
+ *p++ = 'A';
+ if (f & TCP_FLAG_URG)
+ *p++ = 'U';
+ *p = '\0';
+ return str;
+}
+#endif
+
+/*
+ * A major assumption is that only a very small number of sockets will
+ * active, so a simple linear search of those sockets is acceptible.
+ */
+static tcp_socket_t *tcp_list;
+
+/*
+ * Format and send an outgoing segment.
+ */
+static void
+tcp_send(tcp_socket_t *s, int flags, int resend)
+{
+ tcp_header_t *tcp;
+ ip_header_t *ip;
+ pktbuf_t *pkt = &s->pkt;
+ unsigned short cksum;
+ dword tcp_magic;
+ int tcp_magic_size = sizeof(tcp_magic);
+
+ ip = pkt->ip_hdr;
+ tcp = pkt->tcp_hdr;
+
+ if (flags & TCP_FLAG_SYN) {
+ /* If SYN, assume no data and send MSS option in tcp header */
+ pkt->pkt_bytes = sizeof(tcp_header_t) + 4;
+ tcp->hdr_len = 6;
+ tcp_magic = htonl(0x02040000 | MAX_TCP_DATA);
+ memcpy((unsigned char *)(tcp+1), &tcp_magic, tcp_magic_size);
+ s->data_bytes = 0;
+ } else {
+ pkt->pkt_bytes = s->data_bytes + sizeof(tcp_header_t);
+ tcp->hdr_len = 5;
+ }
+
+ /* tcp header */
+ tcp->reserved = 0;
+ tcp->seqnum = htonl(s->seq);
+ tcp->acknum = htonl(s->ack);
+ tcp->checksum = 0;
+
+ if (!resend) {
+ tcp->src_port = htons(s->our_port);
+ tcp->dest_port = htons(s->his_port);
+ tcp->flags = flags;
+ /* always set PUSH flag if sending data */
+ if (s->data_bytes)
+ tcp->flags |= TCP_FLAG_PSH;
+ tcp->window = htons(MAX_TCP_DATA);
+ tcp->urgent = 0;
+
+ /* fill in some pseudo-header fields */
+ memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
+ memcpy(ip->destination, s->his_addr.ip_addr, sizeof(ip_addr_t));
+ ip->protocol = IP_PROTO_TCP;
+ }
+
+ /* another pseudo-header field */
+ ip->length = htons(pkt->pkt_bytes);
+
+ /* compute tcp checksum */
+ cksum = __sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip));
+ tcp->checksum = htons(cksum);
+
+ __ip_send(pkt, IP_PROTO_TCP, &s->his_addr);
+
+ // HACK! If this delay is not present, then if the target system sends
+ // back data (not just an ACK), then somehow we miss it :-(
+ CYGACC_CALL_IF_DELAY_US(2*1000);
+
+ BSPLOG(bsp_log("tcp_send: state[%d] flags[%s] ack[%x] data[%d].\n",
+ s->state, flags_to_str(tcp->flags), s->ack, s->data_bytes));
+
+ if (s->state == _TIME_WAIT) {
+ // If 'reuse' is set on socket, close after 1 second, otherwise 2 minutes
+ __timer_set(&s->timer, s->reuse ? 1000 : 120000, do_close, s);
+ }
+ else if ((tcp->flags & (TCP_FLAG_FIN | TCP_FLAG_SYN)) || s->data_bytes)
+ __timer_set(&s->timer, 1000, do_retrans, s);
+}
+
+static pktbuf_t ack_pkt;
+static word ack_buf[ETH_MIN_PKTLEN/sizeof(word)];
+
+/*
+ * Send an ack.
+ */
+static void
+send_ack(tcp_socket_t *s)
+{
+ tcp_header_t *tcp;
+ ip_header_t *ip;
+ unsigned short cksum;
+
+ ack_pkt.buf = ack_buf;
+ ack_pkt.bufsize = sizeof(ack_buf);
+ ack_pkt.ip_hdr = ip = (ip_header_t *)ack_buf;
+ ack_pkt.tcp_hdr = tcp = (tcp_header_t *)(ip + 1);
+ ack_pkt.pkt_bytes = sizeof(tcp_header_t);
+
+ /* tcp header */
+ tcp->hdr_len = 5;
+ tcp->reserved = 0;
+ tcp->seqnum = htonl(s->seq);
+ tcp->acknum = htonl(s->ack);
+ tcp->checksum = 0;
+
+ tcp->src_port = htons(s->our_port);
+ tcp->dest_port = htons(s->his_port);
+ tcp->flags = TCP_FLAG_ACK;
+
+ tcp->window = htons(MAX_TCP_DATA);
+ tcp->urgent = 0;
+
+ /* fill in some pseudo-header fields */
+ memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
+ memcpy(ip->destination, s->his_addr.ip_addr, sizeof(ip_addr_t));
+ ip->protocol = IP_PROTO_TCP;
+
+ /* another pseudo-header field */
+ ip->length = htons(sizeof(tcp_header_t));
+
+ /* compute tcp checksum */
+ cksum = __sum((word *)tcp, sizeof(*tcp), __pseudo_sum(ip));
+ tcp->checksum = htons(cksum);
+
+ __ip_send(&ack_pkt, IP_PROTO_TCP, &s->his_addr);
+}
+
+
+/*
+ * Send a reset for a bogus incoming segment.
+ */
+static void
+send_reset(pktbuf_t *pkt, ip_route_t *r)
+{
+ ip_header_t *ip = pkt->ip_hdr;
+ tcp_header_t *tcp = pkt->tcp_hdr;
+ dword seq, ack;
+ word src, dest;
+ word cksum;
+
+ seq = ntohl(tcp->acknum);
+ ack = ntohl(tcp->seqnum);
+ src = ntohs(tcp->dest_port);
+ dest = ntohs(tcp->src_port);
+
+ tcp = (tcp_header_t *)(ip + 1);
+ pkt->pkt_bytes = sizeof(tcp_header_t);
+
+ /* tcp header */
+ tcp->hdr_len = 5;
+ tcp->reserved = 0;
+ tcp->seqnum = htonl(seq);
+ tcp->acknum = htonl(ack);
+ tcp->window = htons(1024);
+ tcp->urgent = 0;
+ tcp->checksum = 0;
+ tcp->src_port = htons(src);
+ tcp->dest_port = htons(dest);
+ tcp->flags = TCP_FLAG_RST | TCP_FLAG_ACK;
+
+ /* fill in some pseudo-header fields */
+ memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
+ memcpy(ip->destination, r->ip_addr, sizeof(ip_addr_t));
+ ip->protocol = IP_PROTO_TCP;
+ ip->length = htons(pkt->pkt_bytes);
+
+ /* compute tcp checksum */
+ cksum = __sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip));
+ tcp->checksum = htons(cksum);
+
+ __ip_send(pkt, IP_PROTO_TCP, r);
+}
+
+
+
+/*
+ * Remove given socket from socket list.
+ */
+static void
+unlink_socket(tcp_socket_t *s)
+{
+ tcp_socket_t *prev, *tp;
+
+ for (prev = NULL, tp = tcp_list; tp; prev = tp, tp = tp->next)
+ if (tp == s) {
+ BSPLOG(bsp_log("unlink tcp socket.\n"));
+ if (prev)
+ prev->next = s->next;
+ else
+ tcp_list = s->next;
+ }
+}
+
+/*
+ * Retransmit last packet.
+ */
+static void
+do_retrans(void *p)
+{
+ BSPLOG(bsp_log("tcp do_retrans.\n"));
+ tcp_send((tcp_socket_t *)p, 0, 1);
+}
+
+
+static void
+do_close(void *p)
+{
+ BSPLOG(bsp_log("tcp do_close.\n"));
+ /* close connection */
+ ((tcp_socket_t *)p)->state = _CLOSED;
+ unlink_socket(p);
+}
+
+
+static void
+free_rxlist(tcp_socket_t *s)
+{
+ pktbuf_t *p;
+
+ BSPLOG(bsp_log("tcp free_rxlist.\n"));
+
+ while ((p = s->rxlist) != NULL) {
+ s->rxlist = p->next;
+ __pktbuf_free(p);
+ }
+}
+
+
+/*
+ * Handle a conection reset.
+ */
+static void
+do_reset(tcp_socket_t *s)
+{
+ /* close connection */
+ s->state = _CLOSED;
+ __timer_cancel(&s->timer);
+ free_rxlist(s);
+ unlink_socket(s);
+}
+
+
+/*
+ * Extract data from incoming tcp segment.
+ * Returns true if packet is queued on rxlist, false otherwise.
+ */
+static int
+handle_data(tcp_socket_t *s, pktbuf_t *pkt)
+{
+ tcp_header_t *tcp = pkt->tcp_hdr;
+ unsigned int diff, seq;
+ int data_len;
+ char *data_ptr;
+ pktbuf_t *p;
+
+ data_len = pkt->pkt_bytes - (tcp->hdr_len << 2);
+ data_ptr = ((char *)tcp) + (tcp->hdr_len << 2);
+
+ seq = ntohl(tcp->seqnum);
+
+ BSPLOG(bsp_log("tcp data: seq[%x] len[%d].\n", seq, data_len));
+
+ if (SEQ_LE(seq, s->ack)) {
+ /*
+ * Figure difference between which byte we're expecting and which byte
+ * is sent first. Adjust data length and data pointer accordingly.
+ */
+ diff = s->ack - seq;
+ data_len -= diff;
+ data_ptr += diff;
+
+ if (data_len > 0) {
+ /* queue the new data */
+ s->ack += data_len;
+ pkt->next = NULL;
+ if ((p = s->rxlist) != NULL) {
+ while (p->next)
+ p = p->next;
+ p->next = pkt;
+ BSPLOG(bsp_log("tcp data: Add pkt[%x] len[%d].\n",
+ pkt, data_len));
+ } else {
+ s->rxlist = pkt;
+ s->rxcnt = data_len;
+ s->rxptr = data_ptr;
+ BSPLOG(bsp_log("tcp data: pkt[%x] len[%d].\n",
+ pkt, data_len));
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static void
+handle_ack(tcp_socket_t *s, pktbuf_t *pkt)
+{
+ tcp_header_t *tcp = pkt->tcp_hdr;
+ dword ack;
+ int advance;
+ char *dp;
+
+ /* process ack value in packet */
+ ack = ntohl(tcp->acknum);
+
+ BSPLOG(bsp_log("Rcvd tcp ACK %x\n", ack));
+
+ if (SEQ_GT(ack, s->seq)) {
+ __timer_cancel(&s->timer);
+ advance = ack - s->seq;
+ if (advance > s->data_bytes)
+ advance = s->data_bytes;
+
+ BSPLOG(bsp_log("seq advance %d", advance));
+
+ if (advance > 0) {
+ s->seq += advance;
+ s->data_bytes -= advance;
+ if (s->data_bytes) {
+ /* other end ack'd only part of the pkt */
+ BSPLOG(bsp_log(" %d bytes left", s->data_bytes));
+ dp = (char *)(s->pkt.tcp_hdr + 1);
+ memcpy(dp, dp + advance, s->data_bytes);
+ }
+ }
+ }
+ BSPLOG(bsp_log("\n"));
+}
+
+
+/*
+ * Handle incoming TCP packets.
+ */
+void
+__tcp_handler(pktbuf_t *pkt, ip_route_t *r)
+{
+ tcp_header_t *tcp = pkt->tcp_hdr;
+ ip_header_t *ip = pkt->ip_hdr;
+ tcp_socket_t *prev,*s;
+ dword ack;
+ int queued = 0;
+
+ /* set length for pseudo sum calculation */
+ ip->length = htons(pkt->pkt_bytes);
+
+ if (__sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip)) == 0) {
+ for (prev = NULL, s = tcp_list; s; prev = s, s = s->next) {
+ if (s->our_port == ntohs(tcp->dest_port)) {
+ if (s->his_port == 0)
+ break;
+ if (s->his_port == ntohs(tcp->src_port) &&
+ !memcmp(r->ip_addr, s->his_addr.ip_addr, sizeof(ip_addr_t)))
+ break;
+ }
+ }
+
+ if (s) {
+ /* found the socket this packet belongs to */
+
+ /* refresh his ethernet address */
+ memcpy(s->his_addr.enet_addr, r->enet_addr, sizeof(enet_addr_t));
+
+ if (s->state != _SYN_RCVD && tcp->flags & TCP_FLAG_RST) {
+ BSPLOG(bsp_log("TCP_FLAG_RST rcvd\n"));
+ do_reset(s);
+ __pktbuf_free(pkt);
+ return;
+ }
+
+ switch (s->state) {
+
+ case _SYN_SENT:
+ /* active open not supported */
+ if (tcp->flags != (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
+ do_reset(s);
+ __pktbuf_free(pkt);
+ return;
+ }
+ s->state = _ESTABLISHED;
+ s->ack = ntohl(tcp->seqnum) + 1;
+ s->seq = ntohl(tcp->acknum);
+ __timer_cancel(&s->timer);
+ send_ack(s);
+ break;
+
+ case _LISTEN:
+ if (tcp->flags & TCP_FLAG_SYN) {
+ s->state = _SYN_RCVD;
+ s->ack = ntohl(tcp->seqnum) + 1;
+ s->his_port = ntohs(tcp->src_port);
+ memcpy(s->his_addr.ip_addr, r->ip_addr, sizeof(ip_addr_t));
+ s->data_bytes = 0;
+
+ BSPLOG(bsp_log("SYN from %d.%d.%d.%d:%d (seq %x)\n",
+ s->his_addr.ip_addr[0],s->his_addr.ip_addr[1],
+ s->his_addr.ip_addr[2],s->his_addr.ip_addr[3],
+ s->his_port, ntohl(tcp->seqnum)));
+
+ tcp_send(s, TCP_FLAG_SYN | TCP_FLAG_ACK, 0);
+ }
+ else
+ send_reset(pkt, r);
+ break;
+
+ case _SYN_RCVD:
+ BSPLOG(bsp_log("_SYN_RCVD timer cancel.\n"));
+ __timer_cancel(&s->timer);
+
+ /* go back to _LISTEN state if reset */
+ if (tcp->flags & TCP_FLAG_RST) {
+ s->state = _LISTEN;
+
+ BSPLOG(bsp_log("_SYN_RCVD --> _LISTEN\n"));
+
+ } else if (tcp->flags & TCP_FLAG_SYN) {
+ /* apparently our SYN/ACK was lost? */
+ tcp_send(s, 0, 1);
+
+ BSPLOG(bsp_log("retransmitting SYN/ACK\n"));
+
+ } else if ((tcp->flags & TCP_FLAG_ACK) &&
+ ntohl(tcp->acknum) == (s->seq + 1)) {
+ /* we've established the connection */
+ s->state = _ESTABLISHED;
+ s->seq++;
+
+ BSPLOG(bsp_log("ACK received - connection established\n"));
+ }
+ break;
+
+ case _ESTABLISHED:
+ case _CLOSE_WAIT:
+ ack = s->ack; /* save original ack */
+ if (tcp->flags & TCP_FLAG_ACK)
+ handle_ack(s, pkt);
+
+ queued = handle_data(s, pkt);
+
+ if ((tcp->flags & TCP_FLAG_FIN) &&
+ ntohl(tcp->seqnum) == s->ack) {
+
+ BSPLOG(bsp_log("FIN received - going to _CLOSE_WAIT\n"));
+
+ s->ack++;
+ s->state = _CLOSE_WAIT;
+ }
+ /*
+ * Send an ack if neccessary.
+ */
+ if (s->ack != ack || pkt->pkt_bytes > (tcp->hdr_len << 2))
+ send_ack(s);
+ break;
+
+ case _LAST_ACK:
+ if (tcp->flags & TCP_FLAG_ACK) {
+ handle_ack(s, pkt);
+ if (ntohl(tcp->acknum) == (s->seq + 1)) {
+ BSPLOG(bsp_log("_LAST_ACK --> _CLOSED\n"));
+ s->state = _CLOSED;
+ unlink_socket(s);
+ }
+ }
+ break;
+
+ case _FIN_WAIT_1:
+ if (tcp->flags & TCP_FLAG_ACK) {
+ handle_ack(s, pkt);
+ if (ntohl(tcp->acknum) == (s->seq + 1)) {
+ /* got ACK for FIN packet */
+ s->seq++;
+ if (tcp->flags & TCP_FLAG_FIN) {
+ BSPLOG(bsp_log("_FIN_WAIT_1 --> _TIME_WAIT\n"));
+ s->ack++;
+ s->state = _TIME_WAIT;
+ send_ack(s);
+ } else {
+ s->state = _FIN_WAIT_2;
+ BSPLOG(bsp_log("_FIN_WAIT_1 --> _FIN_WAIT_2\n"));
+ }
+ break; /* All done for now */
+ }
+ }
+ /* At this point, no ACK for FIN has been seen, so check for
+ simultaneous close */
+ if (tcp->flags & TCP_FLAG_FIN) {
+ BSPLOG(bsp_log("_FIN_WAIT_1 --> _CLOSING\n"));
+ __timer_cancel(&s->timer);
+ s->ack++;
+ s->state = _CLOSING;
+ /* FIN is resent so the timeout and retry for this packet
+ will also take care of timeout and resend of the
+ previously sent FIN (which got us to FIN_WAIT_1). While
+ not technically correct, resending FIN only causes a
+ duplicate FIN (same sequence number) which should be
+ ignored by the other end. */
+ tcp_send(s, TCP_FLAG_FIN | TCP_FLAG_ACK, 0);
+ }
+ break;
+
+ case _FIN_WAIT_2:
+ queued = handle_data(s, pkt);
+ if (tcp->flags & TCP_FLAG_FIN) {
+ BSPLOG(bsp_log("_FIN_WAIT_2 --> _TIME_WAIT\n"));
+ s->ack++;
+ s->state = _TIME_WAIT;
+ send_ack(s);
+ }
+ break;
+
+ case _CLOSING:
+ if (tcp->flags & TCP_FLAG_ACK) {
+ handle_ack(s, pkt);
+ if (ntohl(tcp->acknum) == (s->seq + 1)) {
+ /* got ACK for FIN packet */
+ BSPLOG(bsp_log("_CLOSING --> _TIME_WAIT\n"));
+ __timer_cancel(&s->timer);
+ s->state = _TIME_WAIT;
+ }
+ }
+ break;
+
+ case _TIME_WAIT:
+ BSPLOG(bsp_log("_TIME_WAIT resend.\n"));
+ if (tcp->flags & TCP_FLAG_FIN)
+ tcp_send(s, 0, 1); /* just resend ack */
+ break;
+ }
+ } else {
+ BSPLOG(bsp_log("Unexpected segment from: %d.%d.%d.%d:%d\n",
+ r->ip_addr[0], r->ip_addr[1], r->ip_addr[3],
+ r->ip_addr[4], ntohs(tcp->src_port)));
+ send_reset(pkt, r);
+ }
+ }
+ if (!queued)
+ __pktbuf_free(pkt);
+}
+
+
+void
+__tcp_poll(void)
+{
+ __enet_poll();
+ __timer_poll();
+}
+
+
+int
+__tcp_listen(tcp_socket_t *s, word port)
+{
+ BSPLOG(bsp_log("tcp_listen: s[%p] port[%x]\n", s, port));
+
+ memset(s, 0, sizeof(tcp_socket_t));
+ s->state = _LISTEN;
+ s->our_port = port;
+ s->pkt.buf = (word *)s->pktbuf;
+ s->pkt.bufsize = ETH_MAX_PKTLEN;
+ s->pkt.ip_hdr = (ip_header_t *)s->pkt.buf;
+ s->pkt.tcp_hdr = (tcp_header_t *)(s->pkt.ip_hdr + 1);
+
+ s->next = tcp_list;
+
+#if 0
+ /* limit to one open socket at a time */
+ if (s->next) {
+ BSPLOG(bsp_log("tcp_listen: recursion error\n"));
+ BSPLOG(while(1));
+ }
+#endif
+
+ tcp_list = s;
+
+ return 0;
+}
+
+/*
+ * SO_REUSEADDR, no 2MSL.
+ */
+void
+__tcp_so_reuseaddr(tcp_socket_t *s)
+{
+// BSPLOG(bsp_log("__tcp_so_reuseaddr.\n"));
+ s->reuse = 0x01;
+}
+
+/*
+ * Block while waiting for all data to be transmitted.
+ */
+void
+__tcp_drain(tcp_socket_t *s)
+{
+// BSPLOG(bsp_log("__tcp_drain.\n"));
+ while (s->state != _CLOSED && s->data_bytes)
+ __tcp_poll();
+// BSPLOG(bsp_log("__tcp_drain done.\n"));
+}
+
+
+/*
+ * Close the tcp connection.
+ */
+static void
+do_abort(void *s)
+{
+ BSPLOG(bsp_log("do_abort: send RST\n"));
+ tcp_send((tcp_socket_t *)s, TCP_FLAG_ACK | TCP_FLAG_RST, 0);
+ __timer_cancel(&abort_timer);
+ ((tcp_socket_t *)s)->state = _CLOSED;
+ free_rxlist((tcp_socket_t *)s);
+ unlink_socket((tcp_socket_t *)s);
+}
+
+void
+__tcp_abort(tcp_socket_t *s, unsigned long delay)
+{
+ __timer_set(&abort_timer, delay, do_abort, s);
+}
+
+/*
+ * Close the tcp connection.
+ */
+void
+__tcp_close(tcp_socket_t *s)
+{
+ __tcp_drain(s);
+ if (s->state == _ESTABLISHED || s->state == _SYN_RCVD) {
+ BSPLOG(bsp_log("__tcp_close: going to _FIN_WAIT_1\n"));
+ s->state = _FIN_WAIT_1;
+ tcp_send(s, TCP_FLAG_ACK | TCP_FLAG_FIN, 0);
+ } else if (s->state == _CLOSE_WAIT) {
+
+ BSPLOG(bsp_log("__tcp_close: going to _LAST_ACK\n"));
+
+ s->state = _LAST_ACK;
+ tcp_send(s, TCP_FLAG_ACK | TCP_FLAG_FIN, 0);
+ }
+ free_rxlist(s);
+}
+
+
+/*
+ * Wait for connection to be fully closed.
+ */
+void
+__tcp_close_wait(tcp_socket_t *s)
+{
+ BSPLOG(bsp_log("__tcp_close_wait.\n"));
+ while (s->state != _CLOSED)
+ __tcp_poll();
+ BSPLOG(bsp_log("__tcp_close_wait done.\n"));
+}
+
+
+/*
+ * Read up to 'len' bytes without blocking.
+ */
+int
+__tcp_read(tcp_socket_t *s, char *buf, int len)
+{
+ int nread;
+ pktbuf_t *pkt;
+ tcp_header_t *tcp;
+
+ if (len <= 0 || s->rxcnt == 0)
+ return 0;
+
+ if (s->state != _ESTABLISHED && s->rxcnt == 0)
+ return -1;
+
+ nread = 0;
+ while (len) {
+ if (len < s->rxcnt) {
+ memcpy(buf, s->rxptr, len);
+ BSPLOG(bsp_log("tcp_read: read %d bytes.\n", len));
+ s->rxptr += len;
+ s->rxcnt -= len;
+ nread += len;
+
+ BSPLOG(bsp_log("tcp_read: %d bytes left in rxlist head.\n",
+ s->rxcnt));
+
+ break;
+ } else {
+ memcpy(buf, s->rxptr, s->rxcnt);
+ BSPLOG(bsp_log("tcp_read: read %d bytes. pkt[%x] freed.\n",
+ s->rxcnt, s->rxlist));
+ nread += s->rxcnt;
+ buf += s->rxcnt;
+ len -= s->rxcnt;
+
+ /* setup for next packet in list */
+ pkt = s->rxlist;
+ s->rxlist = pkt->next;
+ __pktbuf_free(pkt);
+
+ if ((pkt = s->rxlist) != NULL) {
+ tcp = pkt->tcp_hdr;
+ s->rxcnt = pkt->pkt_bytes - (tcp->hdr_len << 2);
+ s->rxptr = ((char *)tcp) + (tcp->hdr_len << 2);
+
+ BSPLOG(bsp_log("tcp_read: next pkt[%x] has %d bytes.\n",
+ s->rxlist, s->rxcnt));
+ } else {
+
+ BSPLOG(bsp_log("tcp_read: no more data.\n"));
+
+ s->rxcnt = 0;
+ break;
+ }
+ }
+ }
+ return nread;
+}
+
+
+/*
+ * Write up to 'len' bytes without blocking
+ */
+int
+__tcp_write(tcp_socket_t *s, char *buf, int len)
+{
+ tcp_header_t *tcp = s->pkt.tcp_hdr;
+
+ if (len <= 0)
+ return 0;
+
+ if (s->state != _ESTABLISHED && s->state != _CLOSE_WAIT)
+ return -1;
+
+ if (s->data_bytes)
+ return 0;
+
+ if (len > MAX_TCP_DATA)
+ len = MAX_TCP_DATA;
+
+ memcpy(tcp + 1, buf, len);
+ s->data_bytes = len;
+
+ tcp_send(s, TCP_FLAG_ACK, 0);
+
+ return len;
+}
+
+/*
+ * Write 'len' bytes from 'buf', blocking until sent.
+ * If connection collapses, return -1
+ */
+int
+__tcp_write_block(tcp_socket_t *s, char *buf, int len)
+{
+ int total = 0;
+ int n;
+
+ while (len) {
+ if (s->state == _CLOSE_WAIT) {
+ // This connection is tring to close
+ // This connection is breaking
+ if (s->data_bytes == 0 && s->rxcnt == 0)
+ __tcp_close(s);
+ }
+ if (s->state == _CLOSED) {
+ // The connection is gone!
+ return -1;
+ }
+ n = __tcp_write(s, buf, len);
+ if (n > 0) {
+ len -= n;
+ buf += n;
+ }
+ __tcp_poll();
+ }
+ __tcp_drain(s);
+ return total;
+}
+
+/*
+ * Establish a new [outgoing] connection, with a timeout.
+ */
+int
+__tcp_open(tcp_socket_t *s, struct sockaddr_in *host,
+ word port, int timeout, int *err)
+{
+ // Fill in socket details
+ memset(s, 0, sizeof(tcp_socket_t));
+ s->state = _SYN_SENT;
+ s->our_port = port;
+ s->his_port = host->sin_port;
+ s->pkt.buf = (word *)s->pktbuf;
+ s->pkt.bufsize = ETH_MAX_PKTLEN;
+ s->pkt.ip_hdr = (ip_header_t *)s->pkt.buf;
+ s->pkt.tcp_hdr = (tcp_header_t *)(s->pkt.ip_hdr + 1);
+ s->seq = (port << 16) | 0xDE77;
+ s->ack = 0;
+ if (__arp_lookup((ip_addr_t *)&host->sin_addr, &s->his_addr) < 0) {
+ diag_printf("%s: Can't find address of server\n", __FUNCTION__);
+ return -1;
+ }
+ s->next = tcp_list;
+ tcp_list = s;
+
+ // Send off the SYN packet to open the connection
+ tcp_send(s, TCP_FLAG_SYN, 0);
+ // Wait for connection to establish
+ while (s->state != _ESTABLISHED) {
+ if (s->state == _CLOSED) {
+ diag_printf("TCP open - host closed connection\n");
+ return -1;
+ }
+ if (--timeout <= 0) {
+ diag_printf("TCP open - connection timed out\n");
+ return -1;
+ }
+ MS_TICKS_DELAY();
+ __tcp_poll();
+ }
+ return 0;
+}
+
+
diff --git a/ecos/packages/redboot/current/src/net/tftp_client.c b/ecos/packages/redboot/current/src/net/tftp_client.c
new file mode 100644
index 0000000000..d4213bfeaa
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/tftp_client.c
@@ -0,0 +1,279 @@
+//==========================================================================
+//
+// net/tftp_client.c
+//
+// Stand-alone TFTP support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002, 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// TFTP client support
+
+#include <redboot.h> // have_net
+#include <net/net.h>
+#include <net/tftp.h>
+#include <net/tftp_support.h>
+
+// So we remember which ports have been used
+static int get_port = 7700;
+
+static struct {
+ bool open;
+ int total_timeouts, packets_received;
+ unsigned long last_good_block;
+ int avail, actual_len;
+ struct sockaddr_in local_addr, from_addr;
+ char data[SEGSIZE+sizeof(struct tftphdr)];
+ char *bufp;
+} tftp_stream;
+
+int
+tftp_stream_open(connection_info_t *info,
+ int *err)
+{
+ struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
+ char *cp, *fp;
+ char test_buf;
+
+ if (!have_net || tftp_stream.open) {
+ *err = TFTP_INVALID; // Already open
+ return -1;
+ }
+
+ // Create initial request
+ hdr->th_opcode = htons(RRQ); // Read file
+ cp = (char *)&hdr->th_stuff;
+ fp = info->filename;
+ while (*fp) *cp++ = *fp++;
+ *cp++ = '\0';
+ // Since this is used for downloading data, OCTET (binary) is the
+ // only mode that makes sense.
+ fp = "OCTET";
+ while (*fp) *cp++ = *fp++;
+ *cp++ = '\0';
+
+ memset((char *)&tftp_stream.local_addr, 0, sizeof(tftp_stream.local_addr));
+ tftp_stream.local_addr.sin_family = AF_INET;
+ tftp_stream.local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ tftp_stream.local_addr.sin_port = htons(get_port++);
+
+ if (info->server->sin_port == 0) {
+ info->server->sin_port = htons(TFTP_PORT);
+ } else {
+ info->server->sin_port = htons(info->server->sin_port);
+ }
+
+ // Send request - note: RFC 1350 (TFTP rev 2) indicates that this should be
+ // only as long as required to hold the request, with the nul terminator.
+ // Some servers silently go to lunch if the request is not the correct size.
+ if (__udp_sendto(tftp_stream.data, cp-(char *)hdr,
+ info->server, &tftp_stream.local_addr) < 0) {
+ // Problem sending request
+ *err = TFTP_NETERR;
+ return -1;
+ }
+
+ tftp_stream.open = true;
+ tftp_stream.avail = 0;
+ tftp_stream.actual_len = -1;
+ tftp_stream.last_good_block = 0;
+ tftp_stream.total_timeouts = 0;
+ tftp_stream.from_addr.sin_port = 0;
+ tftp_stream.packets_received = 0;
+
+ // Try and read the first byte [block] since no errors are
+ // reported until then.
+ if (tftp_stream_read(&test_buf, 1, err) == 1) {
+ // Back up [rewind] over this datum
+ tftp_stream.bufp--;
+ tftp_stream.avail++;
+ return 0; // Open and first read successful
+ } else {
+ tftp_stream.open = false;
+ return -1; // Couldn't read
+ }
+}
+
+static int
+tftp_ack(int *err)
+{
+ struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
+ // ACK last packet so server can shut down
+ if (tftp_stream.packets_received > 0) {
+ hdr->th_opcode = htons(ACK);
+ hdr->th_block = htons((cyg_uint16)tftp_stream.last_good_block & 0xFFFF);
+ if (__udp_sendto(tftp_stream.data, 4 /* FIXME */,
+ &tftp_stream.from_addr, &tftp_stream.local_addr) < 0) {
+ // Problem sending ACK
+ *err = TFTP_NETERR;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void
+tftp_stream_close(int *err)
+{
+ tftp_ack(err);
+ tftp_stream.open = false;
+}
+
+int
+tftp_stream_read(char *buf,
+ int len,
+ int *err)
+{
+ int total_bytes = 0;
+ int size, recv_len, data_len;
+ struct timeval timeout;
+ struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
+
+ while (total_bytes < len) {
+ // Move any bytes which we've already read/buffered
+ if (tftp_stream.avail > 0) {
+ size = tftp_stream.avail;
+ if (size > (len - total_bytes)) size = len - total_bytes;
+ memcpy(buf, tftp_stream.bufp, size);
+ buf += size;
+ tftp_stream.bufp += size;
+ tftp_stream.avail -= size;
+ total_bytes += size;
+ } else {
+ if (tftp_ack(err) < 0) {
+ return -1;
+ }
+ if ((tftp_stream.actual_len >= 0) && (tftp_stream.actual_len < SEGSIZE)) {
+ // Out of data
+ break;
+ }
+ timeout.tv_sec = (tftp_stream.last_good_block == 0) ? 10*TFTP_TIMEOUT_PERIOD : TFTP_TIMEOUT_PERIOD;
+ timeout.tv_usec = 0;
+ recv_len = sizeof(tftp_stream.data);
+ if ((data_len = __udp_recvfrom(&tftp_stream.data[0], recv_len, &tftp_stream.from_addr,
+ &tftp_stream.local_addr, &timeout)) < 0) {
+ // No data, try again
+ diag_printf("TFTP timed out %d/%d\n", tftp_stream.total_timeouts+1, TFTP_TIMEOUT_MAX);
+ if ((++tftp_stream.total_timeouts > TFTP_TIMEOUT_MAX) ||
+ (tftp_stream.last_good_block == 0)) {
+ // Timeout - no data received
+ *err = TFTP_TIMEOUT;
+ return -1;
+ }
+ // Send out the ACK for the last block - maybe server will retry
+ if (tftp_ack(err) < 0) {
+ return -1;
+ }
+ } else {
+ tftp_stream.packets_received++;
+ if (ntohs(hdr->th_opcode) == DATA) {
+ if (ntohs(hdr->th_block) == (cyg_uint16)((tftp_stream.last_good_block+1) & 0xFFFF)) {
+ // Consume this data
+ data_len -= 4; /* Sizeof TFTP header */
+ tftp_stream.avail = tftp_stream.actual_len = data_len;
+ tftp_stream.bufp = hdr->th_data;
+ tftp_stream.last_good_block++;
+ }
+ } else {
+ if (ntohs(hdr->th_opcode) == ERROR) {
+ *err = ntohs(hdr->th_code);
+ return -1;
+ } else {
+ // What kind of packet is this?
+ *err = TFTP_PROTOCOL;
+ return -1;
+ }
+ }
+ }
+ }
+ }
+ return total_bytes;
+}
+
+char *
+tftp_error(int err)
+{
+ char *errmsg = "Unknown error";
+
+ switch (err) {
+ case TFTP_ENOTFOUND:
+ return "file not found";
+ case TFTP_EACCESS:
+ return "access violation";
+ case TFTP_ENOSPACE:
+ return "disk full or allocation exceeded";
+ case TFTP_EBADOP:
+ return "illegal TFTP operation";
+ case TFTP_EBADID:
+ return "unknown transfer ID";
+ case TFTP_EEXISTS:
+ return "file already exists";
+ case TFTP_ENOUSER:
+ return "no such user";
+ case TFTP_TIMEOUT:
+ return "operation timed out";
+ case TFTP_NETERR:
+ return "some sort of network error";
+ case TFTP_INVALID:
+ return "invalid parameter";
+ case TFTP_PROTOCOL:
+ return "protocol violation";
+ case TFTP_TOOLARGE:
+ return "file is larger than buffer";
+ }
+ return errmsg;
+}
+
+//
+// RedBoot interface
+//
+GETC_IO_FUNCS(tftp_io, tftp_stream_open, tftp_stream_close,
+ 0, tftp_stream_read, tftp_error);
+RedBoot_load(tftp, tftp_io, true, true, 0);
+
diff --git a/ecos/packages/redboot/current/src/net/timers.c b/ecos/packages/redboot/current/src/net/timers.c
new file mode 100644
index 0000000000..79523eda85
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/timers.c
@@ -0,0 +1,135 @@
+//==========================================================================
+//
+// net/timers.c
+//
+// Stand-alone networking support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <net/net.h>
+
+static timer_t *tmr_list;
+
+
+/*
+ * Set a timer. Caller is responsible for providing the timer_t struct.
+ */
+void
+__timer_set(timer_t *t, unsigned long delay,
+ tmr_handler_t handler, void *user_data)
+{
+ timer_t *p;
+
+ t->delay = delay;
+ t->start = MS_TICKS();
+ t->handler = handler;
+ t->user_data = user_data;
+
+ for (p = tmr_list; p; p = p->next)
+ if (p == t) {
+ return;
+ }
+
+ t->next = tmr_list;
+ tmr_list = t;
+}
+
+
+/*
+ * Remove a given timer from timer list.
+ */
+void
+__timer_cancel(timer_t *t)
+{
+ timer_t *prev, *p;
+
+ for (prev = NULL, p = tmr_list; p; prev = p, p = p->next)
+ if (p == t) {
+ if (prev)
+ prev->next = p->next;
+ else
+ tmr_list = p->next;
+ return;
+ }
+}
+
+
+/*
+ * Poll timer list for timer expirations.
+ */
+void
+__timer_poll(void)
+{
+ timer_t *prev, *t;
+
+ prev = NULL;
+ t = tmr_list;
+ while (t) {
+ if ((MS_TICKS_DELAY() - t->start) >= t->delay) {
+
+ /* remove it before calling handler */
+ if (prev)
+ prev->next = t->next;
+ else
+ tmr_list = t->next;
+ /* now, call the handler */
+ t->handler(t->user_data);
+
+ /*
+ * handler may be time consuming, so start
+ * from beginning of list.
+ */
+ prev = NULL;
+ t = tmr_list;
+ } else {
+ prev = t;
+ t = t->next;
+ }
+ }
+}
diff --git a/ecos/packages/redboot/current/src/net/udp.c b/ecos/packages/redboot/current/src/net/udp.c
new file mode 100644
index 0000000000..1ea50529a4
--- /dev/null
+++ b/ecos/packages/redboot/current/src/net/udp.c
@@ -0,0 +1,268 @@
+//==========================================================================
+//
+// net/udp.c
+//
+// Stand-alone UDP networking support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
+// Copyright (C) 2002, 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+
+#ifdef UDP_STATS
+static int udp_rx_total;
+static int udp_rx_handled;
+static int udp_rx_cksum;
+static int udp_rx_dropped;
+#endif
+
+#define MAX_UDP_DATA (ETH_MAX_PKTLEN - (ETH_HDR_SIZE + \
+ sizeof(ip_header_t) + \
+ sizeof(udp_header_t)))
+
+/*
+ * A major assumption is that only a very small number of sockets will
+ * active, so a simple linear search of those sockets is acceptible.
+ */
+static udp_socket_t *udp_list;
+
+
+/*
+ * Install a handler for incoming udp packets.
+ * Caller provides the udp_socket_t structure.
+ * Returns zero if successful, -1 if socket is already used.
+ */
+int
+__udp_install_listener(udp_socket_t *s, word port, udp_handler_t handler)
+{
+ udp_socket_t *p;
+
+ /*
+ * Make sure we only have one handler per port.
+ */
+ for (p = udp_list; p; p = p->next)
+ if (p->our_port == port)
+ return -1;
+
+ s->our_port = htons(port);
+ s->handler = handler;
+ s->next = udp_list;
+ udp_list = s;
+
+ return 0;
+}
+
+
+/*
+ * Remove the handler for the given socket.
+ */
+void
+__udp_remove_listener(word port)
+{
+ udp_socket_t *prev, *s;
+
+ for (prev = NULL, s = udp_list; s; prev = s, s = s->next)
+ if (s->our_port == htons(port)) {
+ if (prev)
+ prev->next = s->next;
+ else
+ udp_list = s->next;
+ }
+}
+
+
+/*
+ * Handle incoming UDP packets.
+ */
+void
+__udp_handler(pktbuf_t *pkt, ip_route_t *r)
+{
+ udp_header_t *udp = pkt->udp_hdr;
+ ip_header_t *ip = pkt->ip_hdr;
+ udp_socket_t *s;
+
+ if (udp->checksum == 0xffff)
+ udp->checksum = 0;
+
+ /* copy length for pseudo sum calculation */
+ ip->length = udp->length;
+
+ if (__sum((word *)udp, ntohs(udp->length), __pseudo_sum(ip)) == 0) {
+ for (s = udp_list; s; s = s->next) {
+ if (s->our_port == udp->dest_port) {
+ (*s->handler)(s, ((char *)udp) + sizeof(udp_header_t),
+ ntohs(udp->length) - sizeof(udp_header_t),
+ r, ntohs(udp->src_port));
+ __pktbuf_free(pkt);
+ return;
+ }
+ }
+ }
+ __pktbuf_free(pkt);
+}
+
+
+/*
+ * Send a UDP packet.
+ */
+int
+__udp_send(char *buf, int len, ip_route_t *dest_ip,
+ word dest_port, word src_port)
+{
+ pktbuf_t *pkt;
+ udp_header_t *udp;
+ ip_header_t *ip;
+ unsigned short cksum;
+ int ret;
+
+ /* dumb */
+ if (len > MAX_UDP_DATA)
+ return -1;
+
+ /* just drop it if can't get a buffer */
+ if ((pkt = __pktbuf_alloc(ETH_MAX_PKTLEN)) == NULL)
+ return -1;
+
+ udp = pkt->udp_hdr;
+ ip = pkt->ip_hdr;
+
+ pkt->pkt_bytes = len + sizeof(udp_header_t);
+
+ udp->src_port = htons(src_port);
+ udp->dest_port = htons(dest_port);
+ udp->length = htons(pkt->pkt_bytes);
+ udp->checksum = 0;
+
+ memcpy(((char *)udp) + sizeof(udp_header_t), buf, len);
+
+ /* fill in some pseudo-header fields */
+ memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t));
+ memcpy(ip->destination, dest_ip->ip_addr, sizeof(ip_addr_t));
+ ip->protocol = IP_PROTO_UDP;
+ ip->length = udp->length;
+
+ cksum = __sum((word *)udp, pkt->pkt_bytes, __pseudo_sum(ip));
+ udp->checksum = htons(cksum);
+
+ ret = __ip_send(pkt, IP_PROTO_UDP, dest_ip);
+ __pktbuf_free(pkt);
+ return ret;
+}
+
+int
+__udp_sendto(char *data, int len, struct sockaddr_in *server,
+ struct sockaddr_in *local)
+{
+ ip_route_t rt;
+
+ if (__arp_lookup((ip_addr_t *)&server->sin_addr, &rt) < 0) {
+ diag_printf("%s: Can't find address of server\n", __FUNCTION__);
+ return -1;
+ } else {
+ __udp_send(data, len, &rt, ntohs(server->sin_port), ntohs(local->sin_port));
+ return 0;
+ }
+}
+
+static char *recvfrom_buf;
+static int recvfrom_len;
+static struct sockaddr_in *recvfrom_server;
+
+static void
+__udp_recvfrom_handler(udp_socket_t *skt, char *buf, int len,
+ ip_route_t *src_route, word src_port)
+{
+ if (recvfrom_server == NULL || recvfrom_buf == NULL)
+ return;
+
+ if (recvfrom_server->sin_port && recvfrom_server->sin_port != htons(src_port))
+ return;
+
+ // Move data to waiting buffer
+ recvfrom_len = len;
+ memcpy(recvfrom_buf, buf, len);
+ if (recvfrom_server) {
+ recvfrom_server->sin_port = htons(src_port);
+ memcpy(&recvfrom_server->sin_addr, &src_route->ip_addr, sizeof(src_route->ip_addr));
+ recvfrom_buf = (char *)0; // Tell reader we got a packet
+ } else {
+ diag_printf("udp_recvfrom - dropped packet of %d bytes\n", len);
+ }
+}
+
+int
+__udp_recvfrom(char *data, int len, struct sockaddr_in *server,
+ struct sockaddr_in *local, struct timeval *timo)
+{
+ int res, my_port, total_ms;
+ udp_socket_t skt;
+ unsigned long start;
+
+ my_port = ntohs(local->sin_port);
+ if (__udp_install_listener(&skt, my_port, __udp_recvfrom_handler) < 0) {
+ return -1;
+ }
+ recvfrom_buf = data;
+ recvfrom_len = len;
+ recvfrom_server = server;
+ total_ms = (timo->tv_sec * 1000) + (timo->tv_usec / 1000);
+ start = MS_TICKS();
+ res = -1;
+ do {
+ __enet_poll(); // Handle the hardware
+ if (!recvfrom_buf) {
+ // Data have arrived
+ res = recvfrom_len;
+ break;
+ }
+ } while ((MS_TICKS_DELAY() - start) < total_ms);
+ __udp_remove_listener(my_port);
+ return res;
+}
diff --git a/ecos/packages/redboot/current/src/parse.c b/ecos/packages/redboot/current/src/parse.c
new file mode 100644
index 0000000000..c6ffc53225
--- /dev/null
+++ b/ecos/packages/redboot/current/src/parse.c
@@ -0,0 +1,402 @@
+//==========================================================================
+//
+// parse.c
+//
+// RedBoot command line parsing routine
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/hal_cache.h>
+#include CYGHWR_MEMORY_LAYOUT_H
+#include <cyg/hal/hal_tables.h>
+
+// Define table boundaries
+extern struct cmd __RedBoot_CMD_TAB__[], __RedBoot_CMD_TAB_END__;
+
+//
+// Scan through an input line and break it into "arguments". These
+// are space delimited strings. Return a structure which points to
+// the strings, similar to a Unix program. Multiple commands in the line
+// are separated by ; similar to sh. If we find a semi we stop processing the
+// line, terminate the current command with a null and return the start
+// of the next command in *line. parse() can then be called again to
+// process the next command on the line.
+// Note: original input is destroyed by replacing the delimiters with
+// null ('\0') characters for ease of use.
+//
+struct cmd *
+parse(char **line, int *argc, char **argv)
+{
+ char *cp = *line;
+ char *pp;
+ int indx = 0;
+ int semi = 0;
+
+ while (*cp) {
+ // Skip leading spaces
+ while (*cp && *cp == ' ') cp++;
+ if (!*cp) {
+ break; // Line ended with a string of spaces
+ }
+ if (*cp == ';') {
+ *cp = '\0';
+ semi=1;
+ break;
+ }
+ if (indx < MAX_ARGV) {
+ argv[indx++] = cp;
+ } else {
+ diag_printf("Too many arguments - stopped at: '%s'\n", cp);
+ }
+ while (*cp) {
+ if (*cp == ' ') {
+ *cp++ = '\0';
+ break;
+ } else if (*cp == ';') {
+ break;
+ } else if (*cp == '"') {
+ // Swallow quote, scan till following one
+ if (argv[indx-1] == cp) {
+ argv[indx-1] = ++cp;
+ }
+ pp = cp;
+ while (*cp && *cp != '"') {
+ if (*cp == '\\') {
+ // Skip over escape - allows for escaped '"'
+ cp++;
+ }
+ // Move string to swallow escapes
+ *pp++ = *cp++;
+ }
+ if (!*cp) {
+ diag_printf("Unbalanced string!\n");
+ } else {
+ if (pp != cp) *pp = '\0';
+ *cp++ = '\0';
+ break;
+ }
+ } else {
+ cp++;
+ }
+ }
+ }
+ if (semi) {
+ *line = cp + 1;
+ } else {
+ *line = cp;
+ }
+ *argc = indx;
+ return cmd_search(__RedBoot_CMD_TAB__, &__RedBoot_CMD_TAB_END__, argv[0]);
+}
+
+//
+// Search through a list of commands
+//
+struct cmd *
+cmd_search(struct cmd *tab, struct cmd *tabend, char *arg)
+{
+ int cmd_len;
+ struct cmd *cmd, *cmd2;
+ // Search command table
+ cmd_len = strlen(arg);
+ cmd = tab;
+ while (cmd != tabend) {
+ if (strncasecmp(arg, cmd->str, cmd_len) == 0) {
+ if (strlen(cmd->str) > cmd_len) {
+ // Check for ambiguous commands here
+ // Note: If there are commands which are not length-unique
+ // then this check will be invalid. E.g. "du" and "dump"
+ bool first = true;
+ cmd2 = tab;
+ while (cmd2 != tabend) {
+ if ((cmd != cmd2) &&
+ (strncasecmp(arg, cmd2->str, cmd_len) == 0)) {
+ if (first) {
+ diag_printf("Ambiguous command '%s', choices are: %s",
+ arg, cmd->str);
+ first = false;
+ }
+ diag_printf(" %s", cmd2->str);
+ }
+ cmd2++;
+ }
+ if (!first) {
+ // At least one ambiguity found - fail the lookup
+ diag_printf("\n");
+ return (struct cmd *)0;
+ }
+ }
+ return cmd;
+ }
+ cmd++;
+ }
+ return (struct cmd *)0;
+}
+
+void
+cmd_usage(struct cmd *tab, struct cmd *tabend, char *prefix)
+{
+ struct cmd *cmd;
+
+ diag_printf("Usage:\n");
+ for (cmd = tab; cmd != tabend; cmd++) {
+ diag_printf(" %s%s %s\n", prefix, cmd->str, cmd->usage);
+ }
+}
+
+// Option processing
+
+// Initialize option table entry (required because these entries
+// may have dynamic contents, thus cannot be statically initialized)
+//
+void
+init_opts(struct option_info *opts, char flag, bool takes_arg,
+ int arg_type, void *arg, bool *arg_set, char *name)
+{
+ opts->flag = flag;
+ opts->takes_arg = takes_arg;
+ opts->arg_type = arg_type,
+ opts->arg = arg;
+ opts->arg_set = arg_set;
+ opts->name = name;
+}
+
+//
+// Scan command line arguments (argc/argv), processing options, etc.
+//
+bool
+scan_opts(int argc, char *argv[], int first,
+ struct option_info *opts, int num_opts,
+ void *def_arg, int def_arg_type, char *def_descr)
+{
+ bool ret = true;
+ bool flag_ok;
+ bool def_arg_set = false;
+ int i, j;
+ char c, *s;
+ struct option_info *opt;
+
+ if (def_arg && (def_arg_type == OPTION_ARG_TYPE_STR)) {
+ *(char **)def_arg = (char *)0;
+ }
+ opt = opts;
+ for (j = 0; j < num_opts; j++, opt++) {
+ if (opt->arg_set) {
+ *opt->arg_set = false;
+ }
+ if (!opt->takes_arg) {
+ switch (opt->arg_type) {
+ case OPTION_ARG_TYPE_NUM:
+ *(int *)opt->arg = 0;
+ break;
+ case OPTION_ARG_TYPE_FLG:
+ *(bool *)opt->arg = false;
+ break;
+ }
+ }
+ }
+ for (i = first; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ c = argv[i][1];
+ flag_ok = false;
+ opt = opts;
+ for (j = 0; j < num_opts; j++, opt++) {
+ if (c == opt->flag) {
+ if (opt->arg_set && *opt->arg_set) {
+ diag_printf("** Error: %s already specified\n", opt->name);
+ ret = false;
+ }
+ if (opt->takes_arg) {
+ if (argv[i][2] == '=') {
+ s = &argv[i][3];
+ } else {
+ s = argv[i+1];
+ i++;
+ }
+ switch (opt->arg_type) {
+ case OPTION_ARG_TYPE_NUM:
+ if (!parse_num(s, (unsigned long *)opt->arg, 0, 0)) {
+ diag_printf("** Error: invalid number '%s' for %s\n",
+ s, opt->name);
+ ret = false;
+ }
+ break;
+ case OPTION_ARG_TYPE_STR:
+ *(char **)opt->arg = s;
+ break;
+ }
+ *opt->arg_set = true;
+ } else {
+ switch (opt->arg_type) {
+ case OPTION_ARG_TYPE_NUM:
+ *(int *)opt->arg = *(int *)opt->arg + 1;
+ break;
+ case OPTION_ARG_TYPE_FLG:
+ *(bool *)opt->arg = true;
+ break;
+ }
+ }
+ flag_ok = true;
+ break;
+ }
+ }
+ if (!flag_ok) {
+ diag_printf("** Error: invalid flag '%c'\n", c);
+ ret = false;
+ }
+ } else {
+ if (def_arg) {
+ if (def_arg_set) {
+ diag_printf("** Error: %s already specified\n", def_descr);
+ ret = false;
+ }
+ switch (def_arg_type) {
+ case OPTION_ARG_TYPE_NUM:
+ if (!parse_num(argv[i], (unsigned long *)def_arg, 0, 0)) {
+ diag_printf("** Error: invalid number '%s' for %s\n",
+ argv[i], def_descr);
+ ret = false;
+ }
+ break;
+ case OPTION_ARG_TYPE_STR:
+ *(char **)def_arg = argv[i];
+ break;
+ }
+ def_arg_set = true;
+ } else {
+ diag_printf("** Error: no default/non-flag arguments supported\n");
+ ret = false;
+ }
+ }
+ }
+ return ret;
+}
+
+//
+// Parse (scan) a number
+//
+bool
+parse_num(char *s, unsigned long *val, char **es, char *delim)
+{
+ bool first = true;
+ int radix = 10;
+ char c;
+ unsigned long result = 0;
+ int digit;
+
+ while (*s == ' ') s++;
+ while (*s) {
+ if (first && (s[0] == '0') && (_tolower(s[1]) == 'x')) {
+ radix = 16;
+ s += 2;
+ }
+ first = false;
+ c = *s++;
+ if (_is_hex(c) && ((digit = _from_hex(c)) < radix)) {
+ // Valid digit
+#ifdef CYGPKG_HAL_MIPS
+ // FIXME: tx49 compiler generates 0x2539018 for MUL which
+ // isn't any good.
+ if (16 == radix)
+ result = result << 4;
+ else
+ result = 10 * result;
+ result += digit;
+#else
+ result = (result * radix) + digit;
+#endif
+ } else {
+ if (delim != (char *)0) {
+ // See if this character is one of the delimiters
+ char *dp = delim;
+ while (*dp && (c != *dp)) dp++;
+ if (*dp) break; // Found a good delimiter
+ }
+ return false; // Malformatted number
+ }
+ }
+ *val = result;
+ if (es != (char **)0) {
+ *es = s;
+ }
+ return true;
+}
+
+bool
+parse_bool(char *s, bool *val)
+{
+ while (*s == ' ') s++;
+ if ((*s == 't') || (*s == 'T')) {
+ char *p = "rue";
+ char *P = "RUE";
+ // check for (partial) rest of the word and no extra including the
+ // terminating zero. "tru" will match; "truef" will not.
+ while ( *++s ) {
+ if ( *p != *s && *P != *s ) return false;
+ p++; P++;
+ }
+ *val = true;
+ } else
+ if ((*s == 'f') || (*s == 'F')) {
+ char *p = "alse";
+ char *P = "ALSE";
+ while ( *++s ) {
+ if ( *p != *s && *P != *s ) return false;
+ p++; P++;
+ }
+ *val = false;
+ } else {
+ return false;
+ }
+ return true;
+}
+
diff --git a/ecos/packages/redboot/current/src/syscall.c b/ecos/packages/redboot/current/src/syscall.c
new file mode 100644
index 0000000000..09df1449ef
--- /dev/null
+++ b/ecos/packages/redboot/current/src/syscall.c
@@ -0,0 +1,655 @@
+/*==========================================================================
+//
+// syscall.c
+//
+// Redboot syscall handling for GNUPro bsp support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): msalter
+// Contributors: msalter
+// Date: 1999-02-20
+// Purpose: Temporary support for gnupro bsp
+//
+//####DESCRIPTIONEND####
+//
+//=========================================================================*/
+
+#include <redboot.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/drv_api.h>
+#include <cyg/hal/hal_stub.h>
+
+#ifdef CYGSEM_REDBOOT_BSP_SYSCALLS
+
+#define NEWLIB_EIO 5 /* I/O error */
+#define NEWLIB_ENOSYS 88 /* Syscall not supported */
+
+/*
+ * Clients of this BSP will need to have access to BSP functions and
+ * data structures. Because, the client and the BSP may not be linked
+ * together, a structure of vectors is used to gain this access. A
+ * pointer to this structure can be gotten via a syscall. This syscall
+ * is made automatically from within the crt0.o file.
+ */
+typedef struct {
+ int version; /* version number for future expansion */
+ const void **__ictrl_table;
+ void **__exc_table;
+ void *__dbg_vector;
+ void *__kill_vector;
+ void *__console_procs;
+ void *__debug_procs;
+ void (*__flush_dcache)(void *__p, int __nbytes);
+ void (*__flush_icache)(void *__p, int __nbytes);
+ void *__cpu_data;
+ void *__board_data;
+ void *__sysinfo;
+ int (*__set_debug_comm)(int __comm_id);
+ int (*__set_console_comm)(int __comm_id);
+ int (*__set_serial_baud)(int __comm_id, int baud);
+ void *__dbg_data;
+ void (*__reset)(void);
+ int __console_interrupt_flag;
+} __shared_t;
+
+static __shared_t __shared_data = { 2 };
+
+// this is used by newlib's mode_t so we should match it
+#ifdef __GNUC__
+#define _ST_INT32 __attribute__ ((__mode__ (__SI__)))
+#else
+#define _ST_INT32
+#endif
+typedef unsigned int newlib_mode_t _ST_INT32;
+typedef short newlib_dev_t;
+typedef unsigned short newlib_ino_t;
+typedef unsigned short newlib_nlink_t;
+typedef long newlib_off_t;
+typedef unsigned short newlib_uid_t;
+typedef unsigned short newlib_gid_t;
+typedef long newlib_time_t;
+typedef long newlib_long_t;
+
+struct newlib_stat
+{
+ newlib_dev_t st_dev;
+ newlib_ino_t st_ino;
+ newlib_mode_t st_mode;
+ newlib_nlink_t st_nlink;
+ newlib_uid_t st_uid;
+ newlib_gid_t st_gid;
+ newlib_dev_t st_rdev;
+ newlib_off_t st_size;
+ // We assume we've been compiled with the same flags as newlib here
+#if defined(__svr4__) && !defined(__PPC__) && !defined(__sun__)
+ newlib_time_t st_atime;
+ newlib_time_t st_mtime;
+ newlib_time_t st_ctime;
+#else
+ newlib_time_t st_atime;
+ newlib_long_t st_spare1;
+ newlib_time_t st_mtime;
+ newlib_long_t st_spare2;
+ newlib_time_t st_ctime;
+ newlib_long_t st_spare3;
+ newlib_long_t st_blksize;
+ newlib_long_t st_blocks;
+ newlib_long_t st_spare4[2];
+#endif
+};
+#define NEWLIB_S_IFCHR 0020000 // character special file
+
+static inline char __getc(void)
+{
+ char c;
+ hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+
+ if (__chan)
+ c = CYGACC_COMM_IF_GETC(*__chan);
+ else {
+ __chan = CYGACC_CALL_IF_DEBUG_PROCS();
+ c = CYGACC_COMM_IF_GETC(*__chan);
+ }
+ return c;
+}
+
+static inline void __putc(char c)
+{
+ hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+ if (__chan)
+ CYGACC_COMM_IF_PUTC(*__chan, c);
+ else {
+ __chan = CYGACC_CALL_IF_DEBUG_PROCS();
+ CYGACC_COMM_IF_PUTC(*__chan, c);
+ }
+}
+
+
+static inline void __flush(void)
+{
+ hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+
+ if (__chan == NULL)
+ __chan = CYGACC_CALL_IF_DEBUG_PROCS();
+
+ CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_FLUSH_OUTPUT);
+}
+
+// Timer support
+
+static cyg_handle_t sys_timer_handle;
+static cyg_interrupt sys_timer_interrupt;
+static cyg_uint64 sys_timer_ticks = 0;
+
+#ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+
+static unsigned int set_period = CYGNUM_HAL_RTC_PERIOD; // The default
+
+typedef void *callback_func( char *pc, char *sp );
+static callback_func *timer_callback = 0;
+
+#endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+
+static void
+sys_timer_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+ // do nothing
+}
+
+
+static cyg_uint32
+sys_timer_isr(cyg_vector_t vector, cyg_addrword_t data)
+{
+ ++sys_timer_ticks;
+
+#ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+ HAL_CLOCK_RESET(CYGNUM_HAL_INTERRUPT_RTC, set_period);
+#else
+ HAL_CLOCK_RESET(CYGNUM_HAL_INTERRUPT_RTC, CYGNUM_HAL_RTC_PERIOD);
+#endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+
+ cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_RTC);
+
+#ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+ if ( timer_callback ) {
+ char *intrpc = (char *)0;
+ char *intrsp = (char *)0;
+
+ // There may be a number of ways to get the PC and (optional) SP
+ // information out of the HAL. Hence this is conditioned. In some
+ // configurations, a register-set pointer is available as
+ // (invisible) argument 3 to this ISR call.
+
+#ifdef HAL_GET_PROFILE_INFO
+ HAL_GET_PROFILE_INFO( intrpc, intrsp );
+#endif // HAL_GET_PROFILE_INFO available
+
+ CYGARC_HAL_SAVE_GP();
+ timer_callback( intrpc, intrsp );
+ CYGARC_HAL_RESTORE_GP();
+ }
+#endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+ return CYG_ISR_HANDLED;
+}
+
+
+static void sys_timer_init(void)
+{
+#ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+ HAL_CLOCK_INITIALIZE(set_period);
+#else
+ HAL_CLOCK_INITIALIZE(CYGNUM_HAL_RTC_PERIOD);
+#endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+
+ cyg_drv_interrupt_create(
+ CYGNUM_HAL_INTERRUPT_RTC,
+ 0, // Priority - unused
+ (CYG_ADDRWORD)0, // Data item passed to ISR & DSR
+ sys_timer_isr, // ISR
+ sys_timer_dsr, // DSR
+ &sys_timer_handle, // handle to intr obj
+ &sys_timer_interrupt ); // space for int obj
+
+ cyg_drv_interrupt_attach(sys_timer_handle);
+
+ cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_RTC);
+}
+
+
+//
+// read -- read bytes from the serial port. Ignore fd, since
+// we only have stdin.
+static int
+sys_read(int fd, char *buf, int nbytes)
+{
+ int i = 0;
+
+ for (i = 0; i < nbytes; i++) {
+ *(buf + i) = __getc();
+ if ((*(buf + i) == '\n') || (*(buf + i) == '\r')) {
+ (*(buf + i + 1)) = 0;
+ break;
+ }
+ }
+ return (i);
+}
+
+
+//
+// write -- write bytes to the serial port. Ignore fd, since
+// stdout and stderr are the same. Since we have no filesystem,
+// open will only return an error.
+//
+static int
+sys_write(int fd, char *buf, int nbytes)
+{
+#define WBUFSIZE 256
+ int tosend;
+
+ tosend = nbytes;
+
+ while (tosend > 0) {
+ if (*buf == '\n')
+ __putc('\r');
+ __putc(*buf++);
+ tosend--;
+ }
+ __flush();
+
+ return (nbytes);
+}
+
+
+//
+// open -- open a file descriptor. We don't have a filesystem, so
+// we return an error.
+//
+static int
+sys_open (const char *buf, int flags, int mode)
+{
+ return (-NEWLIB_EIO);
+}
+
+//
+// close -- We don't need to do anything, but pretend we did.
+//
+static int
+sys_close(int fd)
+{
+ return (0);
+}
+
+
+//
+// lseek -- Since a serial port is non-seekable, we return an error.
+//
+static int
+sys_lseek(int fd, int offset, int whence)
+{
+ return (-NEWLIB_EIO);
+}
+
+
+#define NS_PER_TICK (CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR)
+#define TICKS_PER_SEC (1000000000ULL / NS_PER_TICK)
+
+// This needs to match newlib HZ which is normally 60.
+#define HZ (60ULL)
+
+#ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+static unsigned int set_freq = TICKS_PER_SEC; // The default
+#endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+static int
+sys_times(unsigned long *p)
+{
+ static int inited = 0;
+
+ if (!inited) {
+ inited = 1;
+ sys_timer_init();
+ }
+
+ /* target clock runs at CLOCKS_PER_SEC. Convert to HZ */
+ if (p)
+#ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+ *p = (sys_timer_ticks * HZ) / (cyg_uint64)set_freq;
+#else
+ *p = (sys_timer_ticks * HZ) / TICKS_PER_SEC;
+#endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+
+ return 0;
+}
+
+#ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+
+static void sys_profile_call_back( char *func, char **previous_call_back )
+{
+ if ( previous_call_back )
+ *previous_call_back = (char *)timer_callback;
+
+ timer_callback = (callback_func *)func;
+
+ // Ensure the timer is started
+ (void)sys_times( (unsigned long *)0 );
+}
+
+static void sys_profile_frequency( int freq, int *previous_freq )
+{
+// Requested HZ:
+// 0 => tell me the current value (no change, IMPLEMENTED HERE)
+// - 1 => tell me the slowest (no change)
+// - 2 => tell me the default (no change, IMPLEMENTED HERE)
+// -nnn => tell me what you would choose for nnn (no change)
+// MIN_INT => tell me the fastest (no change)
+//
+// 1 => tell me the slowest (sets the clock)
+// MAX_INT => tell me the fastest (sets the clock)
+
+ // Ensure the timer is started
+ (void)sys_times( (unsigned long *)0 );
+
+ if ( -2 == freq )
+ freq = TICKS_PER_SEC; // default value
+ else if ( 0 == freq )
+ freq = set_freq; // collect current value
+ else {
+ int do_set_freq = (freq > 0);
+ unsigned int period = CYGNUM_HAL_RTC_PERIOD;
+
+ if ( 0 == (freq ^ -freq) ) // Then it's MIN_INT in local size
+ freq++; // just so that it will negate correctly
+
+ // Then set the timer to that fast - or pass on the enquiry
+#ifdef HAL_CLOCK_REINITIALIZE
+ // Give the HAL enough info to do the division sum relative to
+ // the default setup, in period and TICKS_PER_SEC.
+ HAL_CLOCK_REINITIALIZE( freq, period, TICKS_PER_SEC );
+#else
+ freq = TICKS_PER_SEC; // the only choice
+#endif
+ if ( do_set_freq ) { // update the global variables
+ unsigned int orig = set_freq;
+ set_freq = freq;
+ set_period = period;
+ // We must "correct" sys_timer_ticks for the new scale factor.
+ sys_timer_ticks = sys_timer_ticks * set_freq / orig;
+ }
+ }
+
+ if ( previous_freq ) // Return the current value (new value)
+ *previous_freq = freq;
+}
+
+void sys_profile_reset( void )
+{
+ timer_callback = NULL;
+// Want to preserve the frequency between runs, for clever GDB users!
+// sys_profile_frequency( TICKS_PER_SEC, NULL );
+}
+
+#endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+
+//
+// Generic syscall handler.
+//
+// Returns 0 if syscall number is not handled by this
+// module, 1 otherwise. This allows applications to
+// extend the syscall handler by using exception chaining.
+//
+CYG_ADDRWORD
+__do_syscall(CYG_ADDRWORD func, // syscall function number
+ CYG_ADDRWORD arg1, CYG_ADDRWORD arg2, // up to four args.
+ CYG_ADDRWORD arg3, CYG_ADDRWORD arg4,
+ CYG_ADDRWORD *retval, CYG_ADDRWORD *sig) // syscall return value
+{
+ int err = 0;
+ *sig = 0;
+
+ switch (func) {
+
+ case SYS_open:
+ {
+#ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
+ __externC int cyg_hal_gdbfileio_open( const char *name, int flags,
+ int mode, int *sig );
+ if (gdb_active)
+ err = cyg_hal_gdbfileio_open((const char *)arg1, (int)arg2, (int)arg3,
+ (int *)sig);
+ else
+#endif
+ err = sys_open((const char *)arg1, (int)arg2, (int)arg3);
+ break;
+ }
+ case SYS_read:
+ {
+#ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
+ __externC int cyg_hal_gdbfileio_read( int fd, void *buf, size_t count,
+ int *sig );
+ if (gdb_active)
+ err = cyg_hal_gdbfileio_read((int)arg1, (void *)arg2, (size_t)arg3,
+ (int *)sig);
+ else
+#endif
+ err = sys_read((int)arg1, (char *)arg2, (int)arg3);
+ break;
+ }
+ case SYS_write:
+ {
+#ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
+ __externC int cyg_hal_gdbfileio_write( int fd, const void *buf,
+ size_t count, int *sig );
+ if (gdb_active)
+ err = cyg_hal_gdbfileio_write((int)arg1, (const void *)arg2,
+ (size_t)arg3, (int *)sig);
+ else
+#endif
+ err = sys_write((int)arg1, (char *)arg2, (int)arg3);
+ break;
+ }
+ case SYS_close:
+ {
+#ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
+ __externC int cyg_hal_gdbfileio_close( int fd, int *sig );
+ if (gdb_active)
+ err = cyg_hal_gdbfileio_close((int)arg1, (int *)sig);
+ else
+#endif
+ err = sys_close((int)arg1);
+ break;
+ }
+ case SYS_lseek:
+ {
+#ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
+ __externC int cyg_hal_gdbfileio_lseek( int fd, long offset,
+ int whence, int *sig );
+ if (gdb_active)
+ err = cyg_hal_gdbfileio_lseek((int)arg1, (long)arg2, (int)arg3,
+ (int *)sig);
+ else
+#endif
+ err = sys_lseek((int)arg1, (int)arg2, (int)arg3);
+ break;
+ }
+ case SYS_stat:
+ {
+#ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
+ __externC int cyg_hal_gdbfileio_stat( const char *pathname,
+ void *statbuf, int *sig );
+ if (gdb_active)
+ err = cyg_hal_gdbfileio_stat((const char *)arg1, (void *)arg2,
+ (int *)sig);
+ else
+#endif
+ err = -NEWLIB_ENOSYS;
+ break;
+ }
+ case SYS_fstat:
+ {
+#ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
+ __externC int cyg_hal_gdbfileio_fstat( int fd, void *statbuf,
+ int *sig );
+ if (gdb_active)
+ err = cyg_hal_gdbfileio_fstat((int)arg1, (void *)arg2,
+ (int *)sig);
+ else
+#endif
+ {
+ struct newlib_stat *st = (struct newlib_stat *)arg2;
+ st->st_mode = NEWLIB_S_IFCHR;
+ st->st_blksize = 4096;
+ err = 0;
+ }
+ break;
+ }
+ case SYS_rename:
+ {
+#ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
+ __externC int cyg_hal_gdbfileio_rename( const char *oldpath,
+ const char *newpath,
+ int *sig );
+ if (gdb_active)
+ err = cyg_hal_gdbfileio_rename((const char *)arg1, (const char *)arg2,
+ (int *)sig);
+ else
+#endif
+ err = -NEWLIB_ENOSYS;
+ break;
+ }
+ case SYS_unlink:
+ {
+#ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
+ __externC int cyg_hal_gdbfileio_unlink( const char *pathname,
+ int *sig );
+ if (gdb_active)
+ err = cyg_hal_gdbfileio_unlink((const char *)arg1, (int *)sig);
+ else
+#endif
+ err = -NEWLIB_ENOSYS;
+ break;
+ }
+ case SYS_isatty:
+ {
+#ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
+ __externC int cyg_hal_gdbfileio_isatty( int fd, int *sig );
+ if (gdb_active)
+ err = cyg_hal_gdbfileio_isatty((int)arg1, (int *)sig);
+ else
+#endif
+ err = 1;
+ break;
+ }
+ case SYS_system:
+ {
+#ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
+ __externC int cyg_hal_gdbfileio_system( const char *command,
+ int *sig );
+ if (gdb_active)
+ err = cyg_hal_gdbfileio_system((const char *)arg1, (int *)sig);
+ else
+#endif
+ err = -1;
+ break;
+ }
+ case SYS_gettimeofday:
+ {
+#ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
+ __externC int cyg_hal_gdbfileio_gettimeofday( void *tv, void *tz,
+ int *sig );
+ if (gdb_active)
+ err = cyg_hal_gdbfileio_gettimeofday((void *)arg1, (void *)arg2,
+ (int *)sig);
+ else
+#endif
+ err = 0;
+ break;
+ }
+ case SYS_utime:
+ // FIXME. Some libglosses depend on this behavior.
+ err = sys_times((unsigned long *)arg1);
+ break;
+
+ case SYS_times:
+ err = sys_times((unsigned long *)arg1);
+ break;
+
+ case SYS_meminfo:
+ err = 1;
+ *(unsigned long *)arg1 = (unsigned long)(ram_end-ram_start);
+ *(unsigned long *)arg2 = (unsigned long)ram_end;
+ break;
+#ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+ case SYS_timer_call_back:
+ sys_profile_call_back( (char *)arg1, (char **)arg2 );
+ break;
+
+ case SYS_timer_frequency:
+ sys_profile_frequency( (int)arg1, (unsigned int *)arg2 );
+ break;
+
+ case SYS_timer_reset:
+ sys_profile_reset();
+ break;
+
+#endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
+ case __GET_SHARED:
+ *(__shared_t **)arg1 = &__shared_data;
+ break;
+
+ case SYS_exit:
+ *sig = -1; // signal exit
+ err = arg1;
+
+ if (gdb_active) {
+#ifdef CYGOPT_REDBOOT_BSP_SYSCALLS_EXIT_WITHOUT_TRAP
+ __send_exit_status((int)arg1);
+#else
+ *sig = SIGTRAP;
+ err = func;
+#endif // CYGOPT_REDBOOT_BSP_SYSCALLS_EXIT_WITHOUT_TRAP
+ }
+ break;
+
+ default:
+ return 0;
+ }
+
+ *retval = err;
+ return 1;
+}
+
+#endif
diff --git a/ecos/packages/redboot/current/src/ticks.c b/ecos/packages/redboot/current/src/ticks.c
new file mode 100644
index 0000000000..baedfde53f
--- /dev/null
+++ b/ecos/packages/redboot/current/src/ticks.c
@@ -0,0 +1,77 @@
+//==========================================================================
+//
+// ticks.c
+//
+// Stand-alone timer support for RedBoot
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include "redboot.h"
+
+static unsigned long ticks = 0;
+static long elapsed = 0;
+
+unsigned long
+do_ms_tick(void)
+{
+ CYGACC_CALL_IF_DELAY_US(CYGDBG_REDBOOT_TICK_GRANULARITY);
+ elapsed += CYGDBG_REDBOOT_TICK_GRANULARITY;
+ if (elapsed >= 1000) {
+ elapsed = 0;
+ ticks++;
+ }
+ return ticks;
+}
+
+unsigned long
+get_ms_ticks(void)
+{
+ return ticks;
+}
diff --git a/ecos/packages/redboot/current/src/time_date.cxx b/ecos/packages/redboot/current/src/time_date.cxx
new file mode 100644
index 0000000000..966b5b8e7e
--- /dev/null
+++ b/ecos/packages/redboot/current/src/time_date.cxx
@@ -0,0 +1,124 @@
+//==========================================================================
+//
+// time_date.cxx
+//
+// RedBoot time/date commands
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2003 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors:
+// Date: 2003-09-10
+// Description:
+//####DESCRIPTIONEND####
+// -------------------------------------------------------------------------
+
+#include <redboot.h>
+#include <pkgconf/hal.h>
+#include <pkgconf/wallclock.h>
+
+#include <cyg/infra/diag.h>
+#include <cyg/io/wallclock.hxx> // The WallClock API
+#include <cyg/io/wallclock/wallclock.inl> // Helper functions (avoids LIBC)
+
+RedBoot_cmd("date",
+ "Show/Set the time of day",
+ "[YYYY/MM/DD HH:MM:SS]",
+ do_time_date
+ );
+
+static bool
+verify(cyg_uint32 val, int min, int max, char *id)
+{
+ if (((int)val < min) || ((int)val > max)) {
+ diag_printf("%s is out of range - must be [%d..%d]\n", id, min, max);
+ return false;
+ }
+ return true;
+}
+
+void
+do_time_date(int argc, char *argv[])
+{
+ cyg_uint32 now = Cyg_WallClock::wallclock->get_current_time();
+ cyg_uint32 year, month, mday, hour, minute, second;
+ char *sp;
+ bool ok = true;
+
+ if (argc == 1) {
+ // Just show the current time/date
+ _simple_mkdate(now, &year, &month, &mday, &hour, &minute, &second);
+ diag_printf("%04d/%02d/%02d %02d:%02d:%02d\n",
+ year, month, mday, hour, minute, second);
+ } else if (argc == 3) {
+ sp = argv[1];
+ if (!parse_num(sp, (unsigned long *)&year, &sp, "/") ||
+ !parse_num(sp, (unsigned long *)&month, &sp, "/") ||
+ !parse_num(sp, (unsigned long *)&mday, &sp, "/")) {
+ ok = false;
+ }
+ sp = argv[2];
+ if (!parse_num(sp, (unsigned long *)&hour, &sp, ":") ||
+ !parse_num(sp, (unsigned long *)&minute, &sp, ":") ||
+ !parse_num(sp, (unsigned long *)&second, &sp, ":")) {
+ ok = false;
+ }
+ if (ok) {
+ // Verify values make some sense, then set the hardware
+ if (year < 100) year += 2000;
+ ok = ok && verify(year, 1970, 2034, "year");
+ ok = ok && verify(month, 1, 12, "month");
+ ok = ok && verify(mday, 1, 31, "day");
+ ok = ok && verify(hour, 0, 23, "hour");
+ ok = ok && verify(minute, 0, 59, "minute");
+ ok = ok && verify(second, 0, 59, "second");
+ if (ok) {
+ now = _simple_mktime(year, month, mday, hour, minute, second);
+ Cyg_WallClock::wallclock->set_current_time(now);
+ }
+ }
+ } else {
+ ok = false;
+ }
+ if (!ok) {
+ diag_printf("usage: date [YYYY/MM/DD HH:MM:SS]\n");
+ }
+
+}
+
+// -------------------------------------------------------------------------
+// EOF time_date.cxx
diff --git a/ecos/packages/redboot/current/src/version.c b/ecos/packages/redboot/current/src/version.c
new file mode 100644
index 0000000000..7df2730fb4
--- /dev/null
+++ b/ecos/packages/redboot/current/src/version.c
@@ -0,0 +1,97 @@
+//==========================================================================
+//
+// version.c
+//
+// RedBoot version "string"
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-12-13
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/redboot.h>
+#include <cyg/hal/hal_arch.h>
+
+//
+// These strings are used for informational purposes only. If the end
+// user wishes to replace them, simply redefine them in a platform specific
+// file, e.g. in a local file used to provide additional local RedBoot
+// customization. Examples of such are platforms which define a special
+// 'exec' command used to start a Linux kernel.
+//
+// CAUTION! Since this file is compiled using very special rules, it is not
+// possible to replace it with a local version contained in the "build" tree.
+// Replacing the information exported herein is accomplished via the techniques
+// outlined above.
+//
+
+// Do not change the following two lines at all. They are fiddled by release
+// scripts.
+#define _CERTIFICATE Non-certified
+//#define CYGDAT_REDBOOT_CUSTOM_VERSION current
+
+#if defined(CYGDAT_REDBOOT_CUSTOM_VERSION)
+#define _REDBOOT_VERSION CYGDAT_REDBOOT_CUSTOM_VERSION
+#elif defined(CYGPKG_REDBOOT_current)
+#define _REDBOOT_VERSION UNKNOWN
+#else
+#define _REDBOOT_VERSION CYGPKG_REDBOOT
+#endif
+
+#define __s(x) #x
+#define _s(x) __s(x)
+
+char RedBoot_version[] CYGBLD_ATTRIB_WEAK =
+ "\nRedBoot(tm) bootstrap and debug environment [" _s(CYG_HAL_STARTUP) "]"
+ "\n" _s(_CERTIFICATE) " release, version " _s(_REDBOOT_VERSION)
+ " - built " __TIME__ ", " __DATE__ "\n\n";
+
+// Override default GDB stubs 'info'
+// Note: this can still be a "weak" symbol since it will occur in the .o
+// file explicitly mentioned in the link command. User programs will
+// still be allowed to override it.
+char GDB_stubs_version[] CYGBLD_ATTRIB_WEAK =
+ "eCos GDB stubs [via RedBoot] - built " __DATE__ " / " __TIME__;
diff --git a/ecos/packages/redboot/current/src/xyzModem.c b/ecos/packages/redboot/current/src/xyzModem.c
new file mode 100644
index 0000000000..25794b8a02
--- /dev/null
+++ b/ecos/packages/redboot/current/src/xyzModem.c
@@ -0,0 +1,597 @@
+//==========================================================================
+//
+// xyzModem.c
+//
+// RedBoot stream handler for xyzModem protocol
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas, tsmith, Yoshinori Sato
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <xyzModem.h>
+
+// Assumption - run xyzModem protocol over the console port
+
+// Values magic to the protocol
+#define SOH 0x01
+#define STX 0x02
+#define EOT 0x04
+#define ACK 0x06
+#define BSP 0x08
+#define NAK 0x15
+#define CAN 0x18
+#define EOF 0x1A // ^Z for DOS officionados
+
+#define USE_YMODEM_LENGTH
+
+// Data & state local to the protocol
+static struct {
+ hal_virtual_comm_table_t* __chan;
+ unsigned char pkt[1024], *bufp;
+ unsigned char blk,cblk,crc1,crc2;
+ unsigned char next_blk; // Expected block
+ int len, mode, total_retries;
+ int total_SOH, total_STX, total_CAN;
+ bool crc_mode, at_eof, tx_ack;
+#ifdef USE_YMODEM_LENGTH
+ unsigned long file_length, read_length;
+#endif
+} xyz;
+
+#define xyzModem_CHAR_TIMEOUT 2000 // 2 seconds
+#define xyzModem_MAX_RETRIES 20
+#define xyzModem_MAX_RETRIES_WITH_CRC 10
+#define xyzModem_CAN_COUNT 3 // Wait for 3 CAN before quitting
+
+#ifdef DEBUG
+#ifndef USE_SPRINTF
+//
+// Note: this debug setup only works if the target platform has two serial ports
+// available so that the other one (currently only port 1) can be used for debug
+// messages.
+//
+static int
+zm_dprintf(char *fmt, ...)
+{
+ int cur_console;
+ va_list args;
+
+ va_start(args, fmt);
+ cur_console = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(1);
+ diag_vprintf(fmt, args);
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(cur_console);
+}
+
+static void
+zm_flush(void)
+{
+}
+
+#else
+//
+// Note: this debug setup works by storing the strings in a fixed buffer
+//
+static char *zm_out = (char *)0x00380000;
+static char *zm_out_start = (char *)0x00380000;
+
+static int
+zm_dprintf(char *fmt, ...)
+{
+ int len;
+ va_list args;
+
+ va_start(args, fmt);
+ len = diag_vsprintf(zm_out, fmt, args);
+ zm_out += len;
+ return len;
+}
+
+static void
+zm_flush(void)
+{
+ char *p = zm_out_start;
+ while (*p) mon_write_char(*p++);
+ zm_out = zm_out_start;
+}
+#endif
+
+static void
+zm_dump_buf(void *buf, int len)
+{
+ diag_vdump_buf_with_offset(zm_dprintf, buf, len, 0);
+}
+
+static unsigned char zm_buf[2048];
+static unsigned char *zm_bp;
+
+static void
+zm_new(void)
+{
+ zm_bp = zm_buf;
+}
+
+static void
+zm_save(unsigned char c)
+{
+ *zm_bp++ = c;
+}
+
+static void
+zm_dump(int line)
+{
+ zm_dprintf("Packet at line: %d\n", line);
+ zm_dump_buf(zm_buf, zm_bp-zm_buf);
+}
+
+#define ZM_DEBUG(x) x
+#else
+#define ZM_DEBUG(x)
+#endif
+
+// Wait for the line to go idle
+static void
+xyzModem_flush(void)
+{
+ int res;
+ char c;
+ while (true) {
+ res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &c);
+ if (!res) return;
+ }
+}
+
+static int
+xyzModem_get_hdr(void)
+{
+ char c;
+ int res;
+ bool hdr_found = false;
+ int i, can_total, hdr_chars;
+ unsigned short cksum;
+
+ ZM_DEBUG(zm_new());
+ // Find the start of a header
+ can_total = 0;
+ hdr_chars = 0;
+
+ if (xyz.tx_ack) {
+ CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
+ xyz.tx_ack = false;
+ }
+ while (!hdr_found) {
+ res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &c);
+ ZM_DEBUG(zm_save(c));
+ if (res) {
+ hdr_chars++;
+ switch (c) {
+ case SOH:
+ xyz.total_SOH++;
+ case STX:
+ if (c == STX) xyz.total_STX++;
+ hdr_found = true;
+ break;
+ case CAN:
+ xyz.total_CAN++;
+ ZM_DEBUG(zm_dump(__LINE__));
+ if (++can_total == xyzModem_CAN_COUNT) {
+ return xyzModem_cancel;
+ } else {
+ // Wait for multiple CAN to avoid early quits
+ break;
+ }
+ case EOT:
+ // EOT only supported if no noise
+ if (hdr_chars == 1) {
+ CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
+ ZM_DEBUG(zm_dprintf("ACK on EOT #%d\n", __LINE__));
+ ZM_DEBUG(zm_dump(__LINE__));
+ return xyzModem_eof;
+ }
+ default:
+ // Ignore, waiting for start of header
+ ;
+ }
+ } else {
+ // Data stream timed out
+ xyzModem_flush(); // Toss any current input
+ ZM_DEBUG(zm_dump(__LINE__));
+ CYGACC_CALL_IF_DELAY_US((cyg_int32)250000);
+ return xyzModem_timeout;
+ }
+ }
+
+ // Header found, now read the data
+ res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &xyz.blk);
+ ZM_DEBUG(zm_save(xyz.blk));
+ if (!res) {
+ ZM_DEBUG(zm_dump(__LINE__));
+ return xyzModem_timeout;
+ }
+ res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &xyz.cblk);
+ ZM_DEBUG(zm_save(xyz.cblk));
+ if (!res) {
+ ZM_DEBUG(zm_dump(__LINE__));
+ return xyzModem_timeout;
+ }
+ xyz.len = (c == SOH) ? 128 : 1024;
+ xyz.bufp = xyz.pkt;
+ for (i = 0; i < xyz.len; i++) {
+ res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &c);
+ ZM_DEBUG(zm_save(c));
+ if (res) {
+ xyz.pkt[i] = c;
+ } else {
+ ZM_DEBUG(zm_dump(__LINE__));
+ return xyzModem_timeout;
+ }
+ }
+ res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &xyz.crc1);
+ ZM_DEBUG(zm_save(xyz.crc1));
+ if (!res) {
+ ZM_DEBUG(zm_dump(__LINE__));
+ return xyzModem_timeout;
+ }
+ if (xyz.crc_mode) {
+ res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &xyz.crc2);
+ ZM_DEBUG(zm_save(xyz.crc2));
+ if (!res) {
+ ZM_DEBUG(zm_dump(__LINE__));
+ return xyzModem_timeout;
+ }
+ }
+ ZM_DEBUG(zm_dump(__LINE__));
+ // Validate the message
+ if ((xyz.blk ^ xyz.cblk) != (unsigned char)0xFF) {
+ ZM_DEBUG(zm_dprintf("Framing error - blk: %x/%x/%x\n", xyz.blk, xyz.cblk, (xyz.blk ^ xyz.cblk)));
+ ZM_DEBUG(zm_dump_buf(xyz.pkt, xyz.len));
+ xyzModem_flush();
+ return xyzModem_frame;
+ }
+ // Verify checksum/CRC
+ if (xyz.crc_mode) {
+ cksum = cyg_crc16(xyz.pkt, xyz.len);
+ if (cksum != ((xyz.crc1 << 8) | xyz.crc2)) {
+ ZM_DEBUG(zm_dprintf("CRC error - recvd: %02x%02x, computed: %x\n",
+ xyz.crc1, xyz.crc2, cksum & 0xFFFF));
+ return xyzModem_cksum;
+ }
+ } else {
+ cksum = 0;
+ for (i = 0; i < xyz.len; i++) {
+ cksum += xyz.pkt[i];
+ }
+ if (xyz.crc1 != (cksum & 0xFF)) {
+ ZM_DEBUG(zm_dprintf("Checksum error - recvd: %x, computed: %x\n", xyz.crc1, cksum & 0xFF));
+ return xyzModem_cksum;
+ }
+ }
+ // If we get here, the message passes [structural] muster
+ return 0;
+}
+
+int
+xyzModem_stream_open(connection_info_t *info, int *err)
+{
+ int console_chan, stat;
+ int retries = xyzModem_MAX_RETRIES;
+ int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC;
+
+// ZM_DEBUG(zm_out = zm_out_start);
+#ifdef xyzModem_zmodem
+ if (info->mode == xyzModem_zmodem) {
+ *err = xyzModem_noZmodem;
+ return -1;
+ }
+#endif
+
+ // Set up the I/O channel. Note: this allows for using a different port in the future
+ console_chan = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+ if (info->chan >= 0) {
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(info->chan);
+ } else {
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(console_chan);
+ }
+ xyz.__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
+ CYGACC_CALL_IF_SET_CONSOLE_COMM(console_chan);
+ CYGACC_COMM_IF_CONTROL(*xyz.__chan, __COMMCTL_SET_TIMEOUT, xyzModem_CHAR_TIMEOUT);
+ xyz.len = 0;
+ xyz.crc_mode = true;
+ xyz.at_eof = false;
+ xyz.tx_ack = false;
+ xyz.mode = info->mode;
+ xyz.total_retries = 0;
+ xyz.total_SOH = 0;
+ xyz.total_STX = 0;
+ xyz.total_CAN = 0;
+#ifdef USE_YMODEM_LENGTH
+ xyz.read_length = 0;
+ xyz.file_length = 0;
+#endif
+
+ CYGACC_COMM_IF_PUTC(*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
+
+ if (xyz.mode == xyzModem_xmodem) {
+ // X-modem doesn't have an information header - exit here
+ xyz.next_blk = 1;
+ return 0;
+ }
+
+ while (retries-- > 0) {
+ stat = xyzModem_get_hdr();
+ if (stat == 0) {
+ // Y-modem file information header
+ if (xyz.blk == 0) {
+#ifdef USE_YMODEM_LENGTH
+ // skip filename
+ while (*xyz.bufp++);
+ // get the length
+ parse_num(xyz.bufp, &xyz.file_length, NULL, " ");
+#endif
+ // The rest of the file name data block quietly discarded
+ xyz.tx_ack = true;
+ }
+ xyz.next_blk = 1;
+ xyz.len = 0;
+ return 0;
+ } else
+ if (stat == xyzModem_timeout) {
+ if (--crc_retries <= 0) xyz.crc_mode = false;
+ CYGACC_CALL_IF_DELAY_US(5*100000); // Extra delay for startup
+ CYGACC_COMM_IF_PUTC(*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
+ xyz.total_retries++;
+ ZM_DEBUG(zm_dprintf("NAK (%d)\n", __LINE__));
+ }
+ if (stat == xyzModem_cancel) {
+ break;
+ }
+ }
+ *err = stat;
+ ZM_DEBUG(zm_flush());
+ return -1;
+}
+
+int
+xyzModem_stream_read(char *buf, int size, int *err)
+{
+ int stat, total, len;
+ int retries;
+
+ total = 0;
+ stat = xyzModem_cancel;
+ // Try and get 'size' bytes into the buffer
+ while (!xyz.at_eof && (size > 0)) {
+ if (xyz.len == 0) {
+ retries = xyzModem_MAX_RETRIES;
+ while (retries-- > 0) {
+ stat = xyzModem_get_hdr();
+ if (stat == 0) {
+ if (xyz.blk == xyz.next_blk) {
+ xyz.tx_ack = true;
+ ZM_DEBUG(zm_dprintf("ACK block %d (%d)\n", xyz.blk, __LINE__));
+ xyz.next_blk = (xyz.next_blk + 1) & 0xFF;
+
+#if defined(xyzModem_zmodem) || defined(USE_YMODEM_LENGTH)
+ if (xyz.mode == xyzModem_xmodem || xyz.file_length == 0) {
+#else
+ if (1) {
+#endif
+ // Data blocks can be padded with ^Z (EOF) characters
+ // This code tries to detect and remove them
+ if ((xyz.bufp[xyz.len-1] == EOF) &&
+ (xyz.bufp[xyz.len-2] == EOF) &&
+ (xyz.bufp[xyz.len-3] == EOF)) {
+ while (xyz.len && (xyz.bufp[xyz.len-1] == EOF)) {
+ xyz.len--;
+ }
+ }
+ }
+
+#ifdef USE_YMODEM_LENGTH
+ // See if accumulated length exceeds that of the file.
+ // If so, reduce size (i.e., cut out pad bytes)
+ // Only do this for Y-modem (and Z-modem should it ever
+ // be supported since it can fall back to Y-modem mode).
+ if (xyz.mode != xyzModem_xmodem && 0 != xyz.file_length) {
+ xyz.read_length += xyz.len;
+ if (xyz.read_length > xyz.file_length) {
+ xyz.len -= (xyz.read_length - xyz.file_length);
+ }
+ }
+#endif
+ break;
+ } else if (xyz.blk == ((xyz.next_blk - 1) & 0xFF)) {
+ // Just re-ACK this so sender will get on with it
+ CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
+ continue; // Need new header
+ } else {
+ stat = xyzModem_sequence;
+ }
+ }
+ if (stat == xyzModem_cancel) {
+ break;
+ }
+ if (stat == xyzModem_eof) {
+ CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
+ ZM_DEBUG(zm_dprintf("ACK (%d)\n", __LINE__));
+ if (xyz.mode == xyzModem_ymodem) {
+ CYGACC_COMM_IF_PUTC(*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
+ xyz.total_retries++;
+ ZM_DEBUG(zm_dprintf("Reading Final Header\n"));
+ stat = xyzModem_get_hdr();
+ CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
+ ZM_DEBUG(zm_dprintf("FINAL ACK (%d)\n", __LINE__));
+ }
+ xyz.at_eof = true;
+ break;
+ }
+ CYGACC_COMM_IF_PUTC(*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
+ xyz.total_retries++;
+ ZM_DEBUG(zm_dprintf("NAK (%d)\n", __LINE__));
+ }
+ if (stat < 0) {
+ *err = stat;
+ xyz.len = -1;
+ return total;
+ }
+ }
+ // Don't "read" data from the EOF protocol package
+ if (!xyz.at_eof) {
+ len = xyz.len;
+ if (size < len) len = size;
+ memcpy(buf, xyz.bufp, len);
+ size -= len;
+ buf += len;
+ total += len;
+ xyz.len -= len;
+ xyz.bufp += len;
+ }
+ }
+ return total;
+}
+
+void
+xyzModem_stream_close(int *err)
+{
+ diag_printf("xyzModem - %s mode, %d(SOH)/%d(STX)/%d(CAN) packets, %d retries\n",
+ xyz.crc_mode ? "CRC" : "Cksum",
+ xyz.total_SOH, xyz.total_STX, xyz.total_CAN,
+ xyz.total_retries);
+// ZM_DEBUG(zm_flush());
+}
+
+// Need to be able to clean out the input buffer, so have to take the
+// getc
+void xyzModem_stream_terminate(bool abort, int (*getc)(void))
+{
+ int c;
+
+ if (abort) {
+ ZM_DEBUG(zm_dprintf("!!!! TRANSFER ABORT !!!!\n"));
+ switch (xyz.mode) {
+ case xyzModem_xmodem:
+ case xyzModem_ymodem:
+ // The X/YMODEM Spec seems to suggest that multiple CAN followed by an equal
+ // number of Backspaces is a friendly way to get the other end to abort.
+ CYGACC_COMM_IF_PUTC(*xyz.__chan,CAN);
+ CYGACC_COMM_IF_PUTC(*xyz.__chan,CAN);
+ CYGACC_COMM_IF_PUTC(*xyz.__chan,CAN);
+ CYGACC_COMM_IF_PUTC(*xyz.__chan,CAN);
+ CYGACC_COMM_IF_PUTC(*xyz.__chan,BSP);
+ CYGACC_COMM_IF_PUTC(*xyz.__chan,BSP);
+ CYGACC_COMM_IF_PUTC(*xyz.__chan,BSP);
+ CYGACC_COMM_IF_PUTC(*xyz.__chan,BSP);
+ // Now consume the rest of what's waiting on the line.
+ ZM_DEBUG(zm_dprintf("Flushing serial line.\n"));
+ xyzModem_flush();
+ xyz.at_eof = true;
+ break;
+#ifdef xyzModem_zmodem
+ case xyzModem_zmodem:
+ // Might support it some day I suppose.
+#endif
+ break;
+ }
+ } else {
+ ZM_DEBUG(zm_dprintf("Engaging cleanup mode...\n"));
+ // Consume any trailing crap left in the inbuffer from
+ // previous recieved blocks. Since very few files are an exact multiple
+ // of the transfer block size, there will almost always be some gunk here.
+ // If we don't eat it now, RedBoot will think the user typed it.
+ ZM_DEBUG(zm_dprintf("Trailing gunk:\n"));
+ while ((c = (*getc)()) > -1) ;
+ ZM_DEBUG(zm_dprintf("\n"));
+ // Make a small delay to give terminal programs like minicom
+ // time to get control again after their file transfer program
+ // exits.
+ CYGACC_CALL_IF_DELAY_US((cyg_int32)250000);
+ }
+}
+
+char *
+xyzModem_error(int err)
+{
+ switch (err) {
+ case xyzModem_access:
+ return "Can't access file";
+ break;
+ case xyzModem_noZmodem:
+ return "Sorry, zModem not available yet";
+ break;
+ case xyzModem_timeout:
+ return "Timed out";
+ break;
+ case xyzModem_eof:
+ return "End of file";
+ break;
+ case xyzModem_cancel:
+ return "Cancelled";
+ break;
+ case xyzModem_frame:
+ return "Invalid framing";
+ break;
+ case xyzModem_cksum:
+ return "CRC/checksum error";
+ break;
+ case xyzModem_sequence:
+ return "Block sequence error";
+ break;
+ default:
+ return "Unknown error";
+ break;
+ }
+}
+
+//
+// RedBoot interface
+//
+GETC_IO_FUNCS(xyzModem_io, xyzModem_stream_open, xyzModem_stream_close,
+ xyzModem_stream_terminate, xyzModem_stream_read, xyzModem_error);
+RedBoot_load(xmodem, xyzModem_io, false, false, xyzModem_xmodem);
+RedBoot_load(ymodem, xyzModem_io, false, false, xyzModem_ymodem);
diff --git a/ecos/packages/redboot/current/src/xyzModem.h b/ecos/packages/redboot/current/src/xyzModem.h
new file mode 100644
index 0000000000..eaff6f58cd
--- /dev/null
+++ b/ecos/packages/redboot/current/src/xyzModem.h
@@ -0,0 +1,84 @@
+//==========================================================================
+//
+// xyzModem.h
+//
+// RedBoot stream handler for xyzModem protocol
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): gthomas
+// Contributors: gthomas
+// Date: 2000-07-14
+// Purpose:
+// Description:
+//
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#ifndef _XYZMODEM_H_
+#define _XYZMODEM_H_
+
+#define xyzModem_xmodem 1
+#define xyzModem_ymodem 2
+// Don't define this until the protocol support is in place
+//#define xyzModem_zmodem 3
+
+#define xyzModem_access -1
+#define xyzModem_noZmodem -2
+#define xyzModem_timeout -3
+#define xyzModem_eof -4
+#define xyzModem_cancel -5
+#define xyzModem_frame -6
+#define xyzModem_cksum -7
+#define xyzModem_sequence -8
+
+#define xyzModem_close 1
+#define xyzModem_abort 2
+
+int xyzModem_stream_open(connection_info_t *info, int *err);
+void xyzModem_stream_close(int *err);
+void xyzModem_stream_terminate(int method, int (*getc)(void));
+int xyzModem_stream_read(char *buf, int size, int *err);
+char *xyzModem_error(int err);
+
+extern getc_io_funcs_t xyzModem_io;
+
+#endif // _XYZMODEM_H_