Mercurial > ecos
changeset 228:e1b642d73533
Improve load command - make I/O methods table driven.
| author | gthomas |
|---|---|
| date | Mon, 01 Jul 2002 20:55:25 +0000 |
| parents | bded64db11ce |
| children | ff3465255c3a |
| files | packages/redboot/current/ChangeLog packages/redboot/current/cdl/redboot.cdl packages/redboot/current/include/net/http.h packages/redboot/current/include/net/tftp_support.h packages/redboot/current/include/redboot.h packages/redboot/current/src/fs/disk.c packages/redboot/current/src/load.c packages/redboot/current/src/net/http_client.c packages/redboot/current/src/net/tftp_client.c packages/redboot/current/src/xyzModem.c packages/redboot/current/src/xyzModem.h |
| diffstat | 11 files changed, 372 insertions(+), 505 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/redboot/current/ChangeLog +++ b/packages/redboot/current/ChangeLog @@ -1,3 +1,16 @@ +2002-07-01 Gary Thomas <gary@chez-thomas.org> + + * src/net/tftp_client.c: + * src/net/http_client.c: + * src/fs/disk.c: + * src/xyzModem.h: + * src/xyzModem.c: + * src/load.c: + * include/net/tftp_support.h: + * include/net/http.h: + * include/redboot.h: + * cdl/redboot.cdl: Make 'load' command stream I/O table driven. + 2002-05-31 Jesper Skov <jskov@redhat.com> * doc/redboot_installing.sgml: Updated the remaining installation
--- a/packages/redboot/current/cdl/redboot.cdl +++ b/packages/redboot/current/cdl/redboot.cdl @@ -9,6 +9,7 @@ ## ------------------------------------------- ## 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 @@ -151,8 +152,8 @@ cdl_package CYGPKG_REDBOOT { This is handled by a rule in the target CDL." compile main.c crc.c - compile misc_funs.c io.c parse.c ticks.c xyzModem.c syscall.c alias.c - compile -library=libextras.a load.c + compile misc_funs.c io.c parse.c ticks.c syscall.c alias.c + compile -library=libextras.a load.c xyzModem.c make -priority 320 { <PREFIX>/bin/redboot.elf : $(PREFIX)/lib/target.ld $(PREFIX)/lib/vectors.o $(PREFIX)/lib/libtarget.a $(PREFIX)/lib/libextras.a @@ -169,8 +170,8 @@ cdl_package CYGPKG_REDBOOT { default_value 1 compile net/bootp.c net/udp.c net/ip.c net/pktbuf.c net/cksum.c compile net/enet.c net/icmp.c net/tcp.c net/timers.c net/arp.c - compile net/tftp_client.c net/net_io.c net/inet_addr.c - compile -library=libextras.a net/ping.c + compile net/net_io.c net/inet_addr.c + compile -library=libextras.a net/ping.c net/tftp_client.c description "This option includes networking support in RedBoot." define_proc { puts $::cdl_system_header "#define CYGNUM_HAL_VIRTUAL_VECTOR_AUX_CHANNELS 1" @@ -188,7 +189,7 @@ cdl_package CYGPKG_REDBOOT { display "Support HTTP for download" flavor bool default_value 1 - compile net/http_client.c + compile -library=libextras.a net/http_client.c description " This option enables the use of the HTTP protocol for download" }
--- a/packages/redboot/current/include/net/http.h +++ b/packages/redboot/current/include/net/http.h @@ -9,6 +9,7 @@ // ------------------------------------------- // 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 @@ -55,9 +56,9 @@ #ifndef _HTTP_H_ #define _HTTP_H_ -extern int http_stream_open(char *file, struct sockaddr_in *server, int *err); +extern int http_stream_open(connection_info_t *info, int *err); extern int http_stream_read(char *buf, int len, int *err); -extern int http_stream_close(int *err); +extern void http_stream_close(int *err); extern char *http_error(int err); #define HTTP_NOERR 0 // No error @@ -65,4 +66,5 @@ extern char *http_error(int err); #define HTTP_OPEN 2 // Problems opening connection #define HTTP_IO 3 // Misc I/O problems +extern getc_io_funcs_t http_io; #endif // _HTTP_H_
--- a/packages/redboot/current/include/net/tftp_support.h +++ b/packages/redboot/current/include/net/tftp_support.h @@ -9,6 +9,7 @@ // ------------------------------------------- // 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 @@ -83,17 +84,17 @@ * Client support */ -extern int tftp_get(char *, struct sockaddr_in *, char *, int, int, int *); +extern int tftp_stream_open(connection_info_t *info, int *err); +extern int tftp_stream_read(char *buf, int len, int *err); +extern void tftp_stream_close(int *err); extern char *tftp_error(int err); -extern int tftp_stream_open(char *file, struct sockaddr_in *server, int mode, int *err); -extern int tftp_stream_read(char *buf, int len, int *err); -extern int tftp_stream_close(int *err); - #define TFTP_TIMEOUT_PERIOD 5 #define TFTP_TIMEOUT_MAX 15 #define TFTP_RETRIES_MAX 5 #define TFTP_PORT 69 +extern getc_io_funcs_t tftp_io; + #endif // _TFTP_SUPPORT_H_
--- a/packages/redboot/current/include/redboot.h +++ b/packages/redboot/current/include/redboot.h @@ -9,6 +9,7 @@ // ------------------------------------------- // 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 @@ -64,7 +65,6 @@ #ifdef CYGPKG_REDBOOT_NETWORKING #include <net/net.h> -#include <net/tftp_support.h> #include <net/bootp.h> // Determine an IP address for this node, using BOOTP extern int __bootp_find_local_ip(bootp_header_t *info); @@ -149,9 +149,45 @@ externC char *flash_lookup_alias(char *a #endif externC void expand_aliases(char *line, int len); -typedef int (*getc_t)(void); -typedef void (*terminate_t)(int method, getc_t get_c); +// +// Stream I/O support +// + +typedef struct { + char *filename; + struct load_io_entry *mode; + int chan; +#ifdef CYGPKG_REDBOOT_NETWORKING + struct sockaddr_in *server; +#endif +} connection_info_t; +typedef struct { + int (*open)(connection_info_t *info, int *err); + void (*close)(int *err); + void (*terminate)(bool abort, int (*getc)(void)); + int (*read)(char *buf, int size, int *err); + char *(*error)(int err); +} getc_io_funcs_t; + +#define GETC_IO_FUNCS(_label_, _open_, _close_, _terminate_, _read_, _error_) \ +getc_io_funcs_t _label_ = { \ + _open_, _close_, _terminate_, _read_, _error_ \ +}; + +struct load_io_entry { + char *mode; + getc_io_funcs_t *funcs; + bool can_verbose; + bool need_filename; +} CYG_HAL_TABLE_TYPE; +#define _RedBoot_load(_mode_,_funcs_,_verbose_,_filename_) \ +struct load_io_entry _load_tab_##_funcs_##_mode_ \ + CYG_HAL_TABLE_QUALIFIED_ENTRY(RedBoot_load,_funcs_##_mode) = \ + { #_mode_, &_funcs_, _verbose_, _filename_ }; +#define RedBoot_load(_mode_,_funcs_,_verbose_,_filename_) \ + _RedBoot_load(_mode_,_funcs_,_verbose_,_filename_) + #ifdef CYGPKG_COMPRESS_ZLIB // Decompression support typedef struct _pipe { @@ -231,7 +267,7 @@ struct idle_tab_entry _idle_tab_##_p_##_ // This function called when changing idle/not - mostly used by I/O // to support idle when timeout, etc. void do_idle(bool state); - + // Option processing support struct option_info { @@ -256,12 +292,6 @@ externC bool scan_opts(int argc, char *a struct option_info *opts, int num_opts, void **def_arg, int def_arg_type, char *def_descr); -externC int redboot_getc(void); -externC void redboot_getc_init(int (*fun)(char *, int, int *), - int verbose, int decompress); -externC void redboot_getc_rewind(void); -externC void redboot_getc_close(void); - #ifdef CYGNUM_HAL_VIRTUAL_VECTOR_AUX_CHANNELS #define CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS \ (CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS+CYGNUM_HAL_VIRTUAL_VECTOR_AUX_CHANNELS)
--- a/packages/redboot/current/src/fs/disk.c +++ b/packages/redboot/current/src/fs/disk.c @@ -9,6 +9,7 @@ // ------------------------------------------- // 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 @@ -356,9 +357,10 @@ static void *fileptr; static partition_t *file_part; externC int -disk_stream_open(char *filename, int *err) +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. @@ -425,3 +427,9 @@ disk_error(int err) } } +// +// 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);
--- a/packages/redboot/current/src/load.c +++ b/packages/redboot/current/src/load.c @@ -9,6 +9,7 @@ // ------------------------------------------- // 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 @@ -58,13 +59,43 @@ #ifdef CYGPKG_REDBOOT_DISK #include <fs/disk.h> #endif +#ifdef CYGPKG_REDBOOT_NETWORKING +#include <net/tftp_support.h> #ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD #include <net/http.h> #endif +#endif + +static char usage[] = "[-r] [-v] " +#ifdef CYGPKG_COMPRESS_ZLIB + "[-d] " +#endif + "[-h <host>] [-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 256 struct { + getc_io_funcs_t *io; int (*fun)(char *, int len, int *err); unsigned char buf[BUF_SIZE]; unsigned char *bufp; @@ -77,35 +108,152 @@ struct { #endif } getc_info; -static char usage[] = "[-r] [-v] " +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.verbose) diag_printf("\n"); + return -1; + } + } + getc_info.avail--; + return *getc_info.bufp++; +} + #ifdef CYGPKG_COMPRESS_ZLIB - "[-d] " -#endif - "[-h <host>] [-m {TFTP " -#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD - "| HTTP" -#endif -#ifdef xyzModem_zmodem - "| {x|y|z}MODEM" -#else - "| {x|y}MODEM" +// +// 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 -#ifdef CYGPKG_REDBOOT_DISK - " | disk" -#endif -#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1 - " -c <channel_number>" + +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 CYGPKG_COMPRESS_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 - "}]\n [-b <base_address>] <file_name>"; + return 0; +} + +static void +redboot_getc_rewind(void) +{ + getc_info.bufp = getc_info.buf; + getc_info.avail = getc_info.len; +} -// Exported CLI function -RedBoot_cmd("load", - "Load a file", - usage, - do_load - ); +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 CYGPKG_COMPRESS_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) { @@ -124,8 +272,11 @@ static int } #endif +// +// Load an ELF [binary] image +// static unsigned long -load_elf_image(getc_t getc, terminate_t terminate, unsigned long base) +load_elf_image(getc_t getc, unsigned long base) { #ifdef CYGSEM_REDBOOT_ELF Elf32_Ehdr ehdr; @@ -218,16 +369,9 @@ load_elf_image(getc_t getc, terminate_t while (len-- > 0) { #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if ((addr < user_ram_start) || (addr > user_ram_end)) { - // Only if there is no need to stop the download before printing - // output can we ask confirmation questions. - if (terminate) { - (*terminate)(xyzModem_abort, getc); - diag_printf("*** Warning! Attempt to load ELF data to address: %p\nRedBoot does not believe this is in RAM\nUse TFTP for a chance to override this.\n",(void*)addr); - } else { - if (!verify_action("Attempt to load ELF data to address: %p\n" - "RedBoot does not believe this is in RAM", (void*)addr)) - return 0; - } + 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) { @@ -294,9 +438,8 @@ static long // Because of this, "base" probably only makes sense for a set of // data which has only one section, e.g. a ROM image. // -#define MAX_LINE 80 static unsigned long -load_srec_image(getc_t getc, terminate_t terminate, unsigned long base) +load_srec_image(getc_t getc, unsigned long base) { int c; long offset = 0, count, sum, val, cksum; @@ -310,7 +453,7 @@ load_srec_image(getc_t getc, terminate_t while ((c = (*getc)()) > 0) { // Start of line if (c != 'S') { - if (terminate) (*terminate)(xyzModem_abort, getc); + redboot_getc_terminate(true); diag_printf("Invalid S-record at offset %p, input: %c\n", (void *)offset, c); return 0; @@ -319,7 +462,7 @@ load_srec_image(getc_t getc, terminate_t offset += 2; sum = 0; if ((count = _hex2(getc, 1, &sum)) < 0) { - if (terminate) (*terminate)(xyzModem_abort, getc); + redboot_getc_terminate(true); diag_printf("Bad S-record count at offset %p\n", (void *)offset); return 0; } @@ -348,14 +491,9 @@ load_srec_image(getc_t getc, terminate_t if ((addr < user_ram_start) || (addr > user_ram_end)) { // Only if there is no need to stop the download before printing // output can we ask confirmation questions. - if (terminate) { - (*terminate)(xyzModem_abort, getc); - diag_printf("*** Warning! Attempt to load S-record to address: %p\nRedBoot does not believe this is in RAM\nUse TFTP for a chance to override this.\n",(void*)addr); - } else { - if (!verify_action("Attempt to load S-record data to address: %p\n" - "RedBoot does not believe this is in RAM", (void*)addr)) - return 0; - } + 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); @@ -369,7 +507,7 @@ load_srec_image(getc_t getc, terminate_t sum = sum & 0xFF; cksum = (~cksum & 0xFF); if (cksum != sum) { - if (terminate) (*terminate)(xyzModem_abort, getc); + redboot_getc_terminate(true); diag_printf("*** Warning! Checksum failure - Addr: %lx, %02lX <> %02lX\n", (unsigned long)base_addr, sum, cksum); return 0; @@ -385,7 +523,7 @@ load_srec_image(getc_t getc, terminate_t offset += ('9'-type+2); // Save entry address entry_address = (unsigned long)addr; - if (terminate) (*terminate)(xyzModem_close, getc); + 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 *)lowest_address, (void *)highest_address); @@ -396,7 +534,7 @@ load_srec_image(getc_t getc, terminate_t return highest_address; default: - if (terminate) (*terminate)(xyzModem_abort, getc); + redboot_getc_terminate(true); diag_printf("Invalid S-record at offset 0x%lx, type: %x\n", (unsigned long)offset, type); return 0; @@ -407,138 +545,19 @@ load_srec_image(getc_t getc, terminate_t } // -// Stream I/O support -// -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.verbose) diag_printf("\n"); - return -1; - } - } - getc_info.avail--; - return *getc_info.bufp++; -} - +// 'load' CLI command processing +// -b - specify a load [base] address +// -m - specify an I/O stream/method +// -c - Alternate serial I/O channel #ifdef CYGPKG_COMPRESS_ZLIB -// Called to fetch a new chunk of data and decompress it -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; -} +// -d - Decompress data [packed via 'zlib'] #endif - -void -redboot_getc_init(int (*fun)(char *, int, int *), - int verbose, int decompress) -{ - getc_info.avail = 0; - getc_info.len = BUF_SIZE; - getc_info.fun = fun; - getc_info.verbose = verbose; - getc_info.decompress = decompress; - getc_info.tick = 0; -#ifdef CYGPKG_COMPRESS_ZLIB - if (decompress) { - _pipe_t* p = &getc_info.load_pipe; - int err; - p->out_buf = &getc_info.buf[0]; - p->out_size = 0; - p->in_avail = 0; - getc_info.fun = _decompress_stream; - getc_info.raw_fun = fun; - err = (*_dc_init)(p); - if (0 != err && p->msg) { - diag_printf("open decompression error: %s\n", p->msg); - } - } -#endif -} - -void -redboot_getc_rewind(void) -{ - getc_info.bufp = getc_info.buf; - getc_info.avail = getc_info.len; -} - -void -redboot_getc_close(void) -{ -#ifdef CYGPKG_COMPRESS_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 -} - -#define MODE_TFTP 0 -#define MODE_XMODEM xyzModem_xmodem // 1 -#define MODE_YMODEM xyzModem_ymodem // 2 -#ifdef xyzModem_zmodem -#define MODE_ZMODEM xyzModem_zmodem // 3 -#endif -#define MODE_DISK 4 -#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD -#define MODE_HTTP 5 -#endif - +// void do_load(int argc, char *argv[]) { int res, num_options; - int i, err, mode; + int i, err; bool verbose, raw; bool base_addr_set, mode_str_set; char *mode_str; @@ -557,7 +576,9 @@ do_load(int argc, char *argv[]) char type[4]; char *filename = 0; struct option_info opts[7]; - terminate_t terminate = NULL; + connection_info_t info; + getc_io_funcs_t *io; + struct load_io_entry *io_tab; #ifdef CYGPKG_REDBOOT_NETWORKING memset((char *)&host, 0, sizeof(host)); @@ -566,11 +587,6 @@ do_load(int argc, char *argv[]) host.sin_addr = my_bootp_info.bp_siaddr; host.sin_port = 0; #endif -#ifdef CYGPKG_REDBOOT_NETWORKING - mode = MODE_TFTP; -#else - mode = MODE_YMODEM; -#endif init_opts(&opts[0], 'v', false, OPTION_ARG_TYPE_FLG, (void **)&verbose, 0, "verbose"); @@ -616,77 +632,45 @@ do_load(int argc, char *argv[]) } } #endif + if (chan >= CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) { + diag_printf("Invalid I/O channel: %d\n", chan); + return; + } if (mode_str_set) { - if (strncasecmp(&mode_str[1], "modem", strlen(&mode_str[1])) == 0) { - switch (_tolower(mode_str[0])) { - case 'x': - mode = MODE_XMODEM; - break; - case 'y': - mode = MODE_YMODEM; + io = (getc_io_funcs_t *)NULL; + for (io_tab = __RedBoot_LOAD_TAB__; + io_tab != &__RedBoot_LOAD_TAB_END__; io_tab++) { + if (strncasecmp(&mode_str[0], io_tab->mode, strlen(&mode_str[0])) == 0) { + io = io_tab->funcs; break; -#ifdef xyzModem_zmodem - case 'z': - mode = MODE_ZMODEM; - break; -#endif - default: - diag_printf("Invalid 'mode': %s\n", mode_str); - return; } - // When using a serial download type, override verbose - // setting: spinner interferes with the protocol. - verbose = false; -#ifdef CYGPKG_REDBOOT_DISK - } else if (strcasecmp(mode_str, "disk") == 0) { - mode = MODE_DISK; -#endif -#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD - } else if (strcasecmp(mode_str, "http") == 0) { - mode = MODE_HTTP; -#endif -#ifdef CYGPKG_REDBOOT_NETWORKING - } else if (strcasecmp(mode_str, "tftp") == 0) { - mode = MODE_TFTP; - if (!have_net) { - diag_printf("TFTP mode requires a working network\n"); - return; + } + 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->mode); } -#endif - } else { - diag_printf("Invalid 'mode': %s\n", mode_str); + diag_printf("\n"); + } + if (!io) { return; } - } -#if defined(CYGPKG_REDBOOT_NETWORKING) || defined(CYGPKG_REDBOOT_DISK) - if ((mode == MODE_TFTP || mode == MODE_DISK) && !filename) { - diag_printf("File name missing\n"); - diag_printf("usage: load %s\n", usage); - return; - } -#endif -#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1 - if (chan_set) { - if ((mode != MODE_XMODEM) && -#ifdef MODE_ZMODEM - (mode != MODE_ZMODEM) && -#endif - (mode != MODE_YMODEM)) { -#ifdef xyzModem_zmodem - diag_printf("I/O channel can only be used with {xyz}Modem\n"); -#else - diag_printf("I/O channel can only be used with {xy}Modem\n"); -#endif - return; - } - if (chan >= CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) { - diag_printf("Invalid I/O channel: %d\n", chan); + 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 { - chan = -1; + io_tab = (struct load_io_entry *)NULL; // Default +#ifdef CYGPKG_REDBOOT_NETWORKING + io = &tftp_io; +#else + io = &xyzModem_io; + verbose = false; +#endif } -#endif #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (base_addr_set && ((base < (unsigned long)user_ram_start) || @@ -699,74 +683,31 @@ do_load(int argc, char *argv[]) diag_printf("Raw load requires a memory address\n"); return; } + info.filename = filename; + info.chan = chan; + info.mode = io_tab; #ifdef CYGPKG_REDBOOT_NETWORKING - if (mode == MODE_TFTP) { - res = tftp_stream_open(filename, &host, TFTP_OCTET, &err); - if (res < 0) { - diag_printf("Can't load '%s': %s\n", filename, tftp_error(err)); - return; - } - redboot_getc_init(tftp_stream_read, verbose, decompress); - } -#endif -#ifdef CYGPKG_REDBOOT_DISK - else if (mode == MODE_DISK) { - res = disk_stream_open(filename, &err); - if (res < 0) { - - diag_printf("Can't load '%s': %s\n", filename, disk_error(err)); - return; - } - redboot_getc_init(disk_stream_read, verbose, decompress); - } + info.server = &host; #endif -#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD - else if (mode == MODE_HTTP) { - res = http_stream_open(filename, &host, &err); - if (res < 0) { - - diag_printf("Can't load '%s': %s\n", filename, http_error(err)); - return; - } - redboot_getc_init(http_stream_read, verbose, decompress); - } -#endif - else { - res = xyzModem_stream_open(filename, mode, chan, &err); - if (res < 0) { - diag_printf("Can't load '%s': %s\n", filename, xyzModem_error(err)); - return; - } - // Suppress verbosity when using xyz modem download - redboot_getc_init(xyzModem_stream_read, 0 && verbose, decompress); - - terminate = xyzModem_stream_terminate; + res = redboot_getc_init(&info, io, verbose, decompress); + if (res < 0) { + return; } + // Stream open, process the data if (raw) { - bool continue_load = false; unsigned char *mp = (unsigned char *)base; err = 0; while ((res = redboot_getc()) >= 0) { #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS - if (!continue_load && mp >= user_ram_end) { + if (mp >= user_ram_end) { // Only if there is no need to stop the download // before printing output can we ask confirmation // questions. - if (terminate) { - (*terminate)(xyzModem_abort, redboot_getc); - diag_printf("*** Warning! RAW data spills over limit of user RAM at %p\nRedBoot does not believe this is in RAM\nUse TFTP for a chance to override this.\n",(void*)mp); - err = -1; - break; - } else { - if (!verify_action("RAW data spills over limit of user RAM at %p\n" - "Continuing may cause a hang or crash", (void*)mp)) { - err = -1; - break; - } - // Don't ask again - continue_load = true; - } + 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; @@ -778,6 +719,7 @@ do_load(int argc, char *argv[]) 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, (void*)base); @@ -794,36 +736,16 @@ do_load(int argc, char *argv[]) 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, terminate, base); + end = load_elf_image(redboot_getc, base); } else if ((type[0] == 'S') && ((type[1] >= '0') && (type[1] <= '9'))) { - end = load_srec_image(redboot_getc, terminate, base); + end = load_srec_image(redboot_getc, base); } else { diag_printf("Unrecognized image type: 0x%lx\n", *(unsigned long *)type); } } } - switch (mode) { -#ifdef CYGPKG_REDBOOT_DISK - case MODE_DISK: - disk_stream_close(&err); - break; -#endif -#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD - case MODE_HTTP: - http_stream_close(&err); - break; -#endif -#ifdef CYGPKG_REDBOOT_NETWORKING - case MODE_TFTP: - tftp_stream_close(&err); - break; -#endif - default: - xyzModem_stream_close(&err); - break; - } redboot_getc_close(); // Clean up return; }
--- a/packages/redboot/current/src/net/http_client.c +++ b/packages/redboot/current/src/net/http_client.c @@ -9,6 +9,7 @@ // ------------------------------------------- // 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 @@ -79,19 +80,17 @@ min(int a, int b) } int -http_stream_open(char *filename, - struct sockaddr_in *server, - int *err) +http_stream_open(connection_info_t *info, int *err) { int res; struct _stream *s = &http_stream; - server->sin_port = 80; // HTTP port - if ((res = __tcp_open(&s->sock, server, get_port++, 5000, err)) < 0) { + 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", filename); + 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; @@ -99,7 +98,7 @@ http_stream_open(char *filename, return 0; } -int +void http_stream_close(int *err) { struct _stream *s = &http_stream; @@ -108,7 +107,6 @@ http_stream_close(int *err) __tcp_close(&s->sock); s->open = false; } - return 0; } int @@ -234,3 +232,10 @@ http_error(int err) } 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);
--- a/packages/redboot/current/src/net/tftp_client.c +++ b/packages/redboot/current/src/net/tftp_client.c @@ -9,6 +9,7 @@ // ------------------------------------------- // 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 @@ -62,132 +63,6 @@ // So we remember which ports have been used static int get_port = 7700; -#if 0 // No longer used -// -// Read a file from a host into a local buffer. Returns the -// number of bytes actually read, or (-1) if an error occurs. -// On error, *err will hold the reason. -// -int -tftp_get(char *filename, - struct sockaddr_in *server, - char *buf, - int len, - int mode, - int *err) -{ - int res = 0; - int actual_len, data_len, recv_len; - struct sockaddr_in local_addr, from_addr; - char data[SEGSIZE+sizeof(struct tftphdr)]; - struct tftphdr *hdr = (struct tftphdr *)data; - char *cp, *fp; - struct timeval timeout; - int last_good_block = 0; - int total_timeouts = 0; - - *err = 0; // Just in case - - // Create initial request - hdr->th_opcode = htons(RRQ); // Read file - cp = (char *)&hdr->th_stuff; - fp = filename; - while (*fp) *cp++ = *fp++; - *cp++ = '\0'; - if (mode == TFTP_NETASCII) { - fp = "NETASCII"; - } else if (mode == TFTP_OCTET) { - fp = "OCTET"; - } else { - *err = TFTP_INVALID; - return -1; - } - while (*fp) *cp++ = *fp++; - *cp++ = '\0'; - - 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 (server->sin_port == 0) { - server->sin_port = htons(TFTP_PORT); - } - - // Send request - if (__udp_sendto(data, sizeof(data), server, &local_addr) < 0) { - // Problem sending request - *err = TFTP_NETERR; - return -1; - } - - // Read data - fp = buf; - while (true) { - timeout.tv_sec = TFTP_TIMEOUT_PERIOD; - timeout.tv_usec = 0; - recv_len = sizeof(data); - if ((data_len = __udp_recvfrom(&data[0], recv_len, &from_addr, &local_addr, &timeout)) < 0) { - // No data, try again - if ((++total_timeouts > TFTP_TIMEOUT_MAX) || (last_good_block == 0)) { - // Timeout - no data received - *err = TFTP_TIMEOUT; - return -1; - } - // Try resending last ACK - hdr->th_opcode = htons(ACK); - hdr->th_block = htons(last_good_block); - if (__udp_sendto(data, 4 /* FIXME */, &from_addr, &local_addr) < 0) { - // Problem sending request - *err = TFTP_NETERR; - return -1; - } - } else { - if (ntohs(hdr->th_opcode) == DATA) { - actual_len = 0; - if (ntohs(hdr->th_block) == (last_good_block+1)) { - // Consume this data - cp = hdr->th_data; - data_len -= 4; /* Sizeof TFTP header */ - actual_len = data_len; - res += actual_len; - while (data_len-- > 0) { - if (len-- > 0) { - *fp++ = *cp++; - } else { - // Buffer overflow - *err = TFTP_TOOLARGE; - return -1; - } - } - last_good_block++; - } - // Send out the ACK - hdr->th_opcode = htons(ACK); - hdr->th_block = htons(last_good_block); - if (__udp_sendto(data, 4 /* FIXME */, &from_addr, &local_addr) < 0) { - // Problem sending ACK - *err = TFTP_NETERR; - return -1; - } - if ((actual_len >= 0) && (actual_len < SEGSIZE)) { - // End of data - return res; - } - } 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; - } - } - } -} -#endif - static struct { bool open; int total_timeouts; @@ -199,9 +74,7 @@ static struct { } tftp_stream; int -tftp_stream_open(char *filename, - struct sockaddr_in *server, - int mode, +tftp_stream_open(connection_info_t *info, int *err) { struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data; @@ -216,17 +89,12 @@ tftp_stream_open(char *filename, // Create initial request hdr->th_opcode = htons(RRQ); // Read file cp = (char *)&hdr->th_stuff; - fp = filename; + fp = info->filename; while (*fp) *cp++ = *fp++; *cp++ = '\0'; - if (mode == TFTP_NETASCII) { - fp = "NETASCII"; - } else if (mode == TFTP_OCTET) { - fp = "OCTET"; - } else { - *err = TFTP_INVALID; - return -1; - } + // Since this is used for downloading data, OCTET (binary) is the + // only mode that makes sense. + fp = "OCTET"; while (*fp) *cp++ = *fp++; *cp++ = '\0'; @@ -235,15 +103,15 @@ tftp_stream_open(char *filename, tftp_stream.local_addr.sin_addr.s_addr = htonl(INADDR_ANY); tftp_stream.local_addr.sin_port = htons(get_port++); - if (server->sin_port == 0) { - server->sin_port = htons(TFTP_PORT); + if (info->server->sin_port == 0) { + info->server->sin_port = htons(TFTP_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, - server, &tftp_stream.local_addr) < 0) { + info->server, &tftp_stream.local_addr) < 0) { // Problem sending request *err = TFTP_NETERR; return -1; @@ -269,11 +137,10 @@ tftp_stream_open(char *filename, } } -int +void tftp_stream_close(int *err) { tftp_stream.open = false; - return 0; } int @@ -382,3 +249,11 @@ tftp_error(int err) } 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); +
--- a/packages/redboot/current/src/xyzModem.c +++ b/packages/redboot/current/src/xyzModem.c @@ -9,6 +9,7 @@ // ------------------------------------------- // 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 @@ -316,7 +317,7 @@ xyzModem_get_hdr(void) } int -xyzModem_stream_open(char *filename, int mode, int chan, int *err) +xyzModem_stream_open(connection_info_t *info, int *err) { int console_chan, stat; int retries = xyzModem_MAX_RETRIES; @@ -324,7 +325,7 @@ xyzModem_stream_open(char *filename, int // ZM_DEBUG(zm_out = zm_out_start); #ifdef xyzModem_zmodem - if (mode == xyzModem_zmodem) { + if (info->mode == xyzModem_zmodem) { *err = xyzModem_noZmodem; return -1; } @@ -332,8 +333,8 @@ xyzModem_stream_open(char *filename, int // 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 (chan >= 0) { - CYGACC_CALL_IF_SET_CONSOLE_COMM(chan); + if (info->chan >= 0) { + CYGACC_CALL_IF_SET_CONSOLE_COMM(info->chan); } else { CYGACC_CALL_IF_SET_CONSOLE_COMM(console_chan); } @@ -344,7 +345,7 @@ xyzModem_stream_open(char *filename, int xyz.crc_mode = true; xyz.at_eof = false; xyz.tx_ack = false; - xyz.mode = mode; + xyz.mode = info->mode; xyz.total_retries = 0; xyz.total_SOH = 0; xyz.total_STX = 0; @@ -498,12 +499,11 @@ xyzModem_stream_close(int *err) // Need to be able to clean out the input buffer, so have to take the // getc -void xyzModem_stream_terminate(int method, int (*getc)(void)) +void xyzModem_stream_terminate(bool abort, int (*getc)(void)) { int c; - switch (method) { - case xyzModem_abort: + if (abort) { ZM_DEBUG(zm_dprintf("!!!! TRANSFER ABORT !!!!\n")); switch (xyz.mode) { case xyzModem_xmodem: @@ -529,7 +529,7 @@ void xyzModem_stream_terminate(int metho #endif break; } - default: + } 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 @@ -542,7 +542,6 @@ void xyzModem_stream_terminate(int metho // time to get control again after their file transfer program // exits. CYGACC_CALL_IF_DELAY_US((cyg_int32)250000); - break; } } @@ -579,3 +578,11 @@ xyzModem_error(int err) 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); +RedBoot_load(ymodem, xyzModem_io, false, false);
--- a/packages/redboot/current/src/xyzModem.h +++ b/packages/redboot/current/src/xyzModem.h @@ -9,6 +9,7 @@ // ------------------------------------------- // 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 @@ -72,10 +73,12 @@ #define xyzModem_close 1 #define xyzModem_abort 2 -int xyzModem_stream_open(char *filename, int mode, int chan, int *err); +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_
