source: SVN/cambria/redboot/packages/redboot/current/src/load.c

Last change on this file was 1, checked in by Tim Harvey, 2 years ago

restored latest version of files from server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 25.6 KB
Line 
1//==========================================================================
2//
3//      load.c
4//
5//      RedBoot file/image loader
6//
7//==========================================================================
8//####ECOSGPLCOPYRIGHTBEGIN####
9// -------------------------------------------
10// This file is part of eCos, the Embedded Configurable Operating System.
11// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12// Copyright (C) 2002, 2003, 2004 Gary Thomas
13//
14// eCos is free software; you can redistribute it and/or modify it under
15// the terms of the GNU General Public License as published by the Free
16// Software Foundation; either version 2 or (at your option) any later version.
17//
18// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19// WARRANTY; without even the implied warranty of MERCHANTABILITY or
20// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21// for more details.
22//
23// You should have received a copy of the GNU General Public License along
24// with eCos; if not, write to the Free Software Foundation, Inc.,
25// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26//
27// As a special exception, if other files instantiate templates or use macros
28// or inline functions from this file, or you compile this file and link it
29// with other works to produce a work based on this file, this file does not
30// by itself cause the resulting work to be covered by the GNU General Public
31// License. However the source code for this file must still be made available
32// in accordance with section (3) of the GNU General Public License.
33//
34// This exception does not invalidate any other reasons why a work based on
35// this file might be covered by the GNU General Public License.
36//
37// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38// at http://sources.redhat.com/ecos/ecos-license/
39// -------------------------------------------
40//####ECOSGPLCOPYRIGHTEND####
41//==========================================================================
42//#####DESCRIPTIONBEGIN####
43//
44// Author(s):    gthomas
45// Contributors: gthomas, tsmith
46// Date:         2000-07-14
47// Purpose:     
48// Description: 
49//             
50// This code is part of RedBoot (tm).
51//
52//####DESCRIPTIONEND####
53//
54//==========================================================================
55
56#include <redboot.h>
57#include <elf.h>
58#ifdef CYGBLD_BUILD_REDBOOT_WITH_XYZMODEM
59#include <xyzModem.h>
60#endif
61#ifdef CYGPKG_REDBOOT_DISK
62#include <fs/disk.h>
63#endif
64#ifdef CYGPKG_REDBOOT_FILEIO
65#include <fs/fileio.h>
66#endif
67#ifdef CYGPKG_REDBOOT_NETWORKING
68#ifdef CYGSEM_REDBOOT_NET_TFTP_DOWNLOAD
69#include <net/tftp_support.h>
70#endif
71#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD
72#include <net/http.h>
73#endif
74#endif
75#include <cyg/infra/cyg_ass.h>         // assertion macros
76
77static char usage[] = "[-r] [-v] "
78#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
79                      "[-d] "
80#endif
81#ifdef CYGPKG_REDBOOT_NETWORKING
82                      "[-h <host>] [-p <TCP port>]"
83#endif
84                      "[-m <varies>] "
85#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
86                      "[-c <channel_number>] "
87#endif
88                      "\n        [-b <base_address>] <file_name>";
89
90// Exported CLI function
91RedBoot_cmd("load", 
92            "Load a file", 
93            usage,
94            do_load
95    );
96
97//
98// Stream I/O support
99//
100
101// Table describing the various I/O methods
102CYG_HAL_TABLE_BEGIN( __RedBoot_LOAD_TAB__, RedBoot_load );
103CYG_HAL_TABLE_END( __RedBoot_LOAD_TAB_END__, RedBoot_load );
104extern struct load_io_entry __RedBoot_LOAD_TAB__[], __RedBoot_LOAD_TAB_END__;
105
106// Buffers, data used by redboot_getc
107#define BUF_SIZE CYGNUM_REDBOOT_GETC_BUFFER
108struct {
109    getc_io_funcs_t *io;
110    int (*fun)(char *, int len, int *err);
111    unsigned char  buf[BUF_SIZE];
112    unsigned char *bufp;
113    int   avail, len, err;
114    int   verbose, decompress, tick;
115#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
116    int (*raw_fun)(char *, int len, int *err);
117    _pipe_t load_pipe;
118    unsigned char _buffer[CYGNUM_REDBOOT_LOAD_ZLIB_BUFFER];
119#endif
120} getc_info;
121
122typedef int (*getc_t)(void);
123
124//
125// Read the next data byte from the stream.
126// Returns:
127//    >= 0 - actual data
128//      -1 - error or EOF, status in getc_info.err
129//
130static int 
131redboot_getc(void)
132{
133    static char spin[] = "|/-\\|-";
134    if (getc_info.avail < 0) {
135      return -1;
136    }
137    if (getc_info.avail == 0) {
138        if (getc_info.verbose) {
139            diag_printf("%c\b", spin[getc_info.tick++]);
140            if (getc_info.tick >= sizeof(spin)) {
141                getc_info.tick = 0;
142            }
143        }
144        if (getc_info.len < BUF_SIZE) {
145            // No more data available
146            if (getc_info.verbose) diag_printf("\n");
147            return -1;
148        }
149        getc_info.bufp = getc_info.buf;
150        getc_info.len = (*getc_info.fun)(getc_info.bufp, BUF_SIZE, &getc_info.err);
151        if ((getc_info.avail = getc_info.len) <= 0) {
152            if (getc_info.len < 0) {
153                diag_printf("I/O error: %s\n", (getc_info.io->error)(getc_info.err));
154            }
155            if (getc_info.verbose) diag_printf("\n");
156            return -1;
157        }
158    }
159    getc_info.avail--;
160    return *getc_info.bufp++;
161}
162
163#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
164//
165// Called to fetch a new chunk of data and decompress it
166//
167static int 
168_decompress_stream(char *buf, int len, int *err)
169{
170    _pipe_t* p = &getc_info.load_pipe;
171    int res, total;
172
173    total = 0;
174    while (len > 0) {
175        if (p->in_avail == 0) {
176            p->in_buf = &getc_info._buffer[0];
177            res = (*getc_info.raw_fun)(p->in_buf, CYGNUM_REDBOOT_LOAD_ZLIB_BUFFER, 
178                                       &getc_info.err);
179            if ((p->in_avail = res) <= 0) {
180                // No more data
181                return total;
182            }
183        }
184        p->out_buf = buf;
185        p->out_size = 0;
186        p->out_max = len;
187        res = (*_dc_inflate)(p);
188        if (res != 0) {
189            *err = res;
190            return total;
191        }       
192        len -= p->out_size;
193        buf += p->out_size;
194        total += p->out_size;
195    }
196    return total;
197}
198#endif
199
200static int
201redboot_getc_init(connection_info_t *info, getc_io_funcs_t *funcs, 
202                  int verbose, int decompress)
203{
204    int res;
205
206    res = (funcs->open)(info, &getc_info.err);   
207    if (res < 0) {
208        diag_printf("Can't load '%s': %s\n", info->filename, (funcs->error)(getc_info.err));
209            return res;
210    }
211    getc_info.io = funcs;
212    getc_info.fun = funcs->read;
213    getc_info.avail = 0;
214    getc_info.len = BUF_SIZE;
215    getc_info.verbose = verbose;
216    getc_info.decompress = decompress;
217    getc_info.tick = 0;
218#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
219    if (decompress) {
220        _pipe_t* p = &getc_info.load_pipe;
221        p->out_buf = &getc_info.buf[0];
222        p->out_size = 0;
223        p->in_avail = 0;
224        getc_info.raw_fun = getc_info.fun;
225        getc_info.fun = _decompress_stream;
226        getc_info.err = (*_dc_init)(p);
227        if (0 != getc_info.err && p->msg) {
228            diag_printf("open decompression error: %s\n", p->msg);
229        }
230    }
231#endif
232    return 0;
233}
234
235static void
236redboot_getc_rewind(void)
237{
238    getc_info.bufp = getc_info.buf;
239    getc_info.avail = getc_info.len;
240}
241
242static void
243redboot_getc_terminate(bool abort)
244{
245    if (getc_info.io->terminate) {
246        (getc_info.io->terminate)(abort, redboot_getc);
247    }
248}
249
250static void
251redboot_getc_close(void)
252{
253    (getc_info.io->close)(&getc_info.err);
254#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
255    if (getc_info.decompress) {
256        _pipe_t* p = &getc_info.load_pipe;
257        int err = getc_info.err;
258        if (0 != err && p->msg) {
259            diag_printf("decompression error: %s\n", p->msg);
260        }
261        err = (*_dc_close)(p, getc_info.err);
262    }
263#endif
264}
265
266#ifdef CYGSEM_REDBOOT_ELF
267//
268// Support function - used to read bytes into a buffer
269// Returns the number of bytes read (stops short on errors)
270//
271static int
272_read(int (*getc)(void), unsigned char *buf, int len)
273{
274    int total = 0;
275    int ch;
276    while (len-- > 0) {
277        ch = (*getc)();
278        if (ch < 0) {
279            // EOF or error
280            break;
281        }
282        *buf++ = ch;
283        total++;
284    }
285    return total;
286}
287#endif
288
289//
290// Load an ELF [binary] image
291//
292static unsigned long
293load_elf_image(getc_t getc, unsigned long base)
294{
295#ifdef CYGSEM_REDBOOT_ELF
296    Elf32_Ehdr ehdr;
297#define MAX_PHDR 8
298    Elf32_Phdr phdr[MAX_PHDR];
299    unsigned long offset = 0;
300    int phx, len, ch;
301    unsigned char *addr;
302    unsigned long addr_offset = 0;
303    unsigned long highest_address = 0;
304    unsigned long lowest_address = 0xFFFFFFFF;
305    unsigned char *SHORT_DATA = "Short data reading ELF file\n";
306
307    // Read the header
308    if (_read(getc, (unsigned char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr)) {
309        diag_printf("Can't read ELF header\n");
310        return 0;
311    }
312    offset += sizeof(ehdr);   
313#if 0 // DEBUG
314    diag_printf("Type: %d, Machine: %d, Version: %d, Entry: %p, PHoff: %p/%d/%d, SHoff: %p/%d/%d\n",
315                ehdr.e_type, ehdr.e_machine, ehdr.e_version, ehdr.e_entry,
316                ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_phnum,
317                ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shnum);
318#endif
319    if (ehdr.e_type != ET_EXEC) {
320        diag_printf("Only absolute ELF images supported\n");
321        return 0;
322    }
323    if (ehdr.e_phnum > MAX_PHDR) {
324        diag_printf("Too many program headers\n");
325        return 0;
326    }
327    while (offset < ehdr.e_phoff) {
328        if ((*getc)() < 0) {
329            diag_printf(SHORT_DATA);
330            return 0;
331        }
332        offset++;
333    }
334    for (phx = 0;  phx < ehdr.e_phnum;  phx++) {
335        if (_read(getc, (unsigned char *)&phdr[phx], sizeof(phdr[0])) != sizeof(phdr[0])) {
336            diag_printf("Can't read ELF program header\n");
337            return 0;
338        }
339#if 0 // DEBUG
340        diag_printf("Program header: type: %d, off: %p, va: %p, pa: %p, len: %d/%d, flags: %d\n",
341                    phdr[phx].p_type, phdr[phx].p_offset, phdr[phx].p_vaddr, phdr[phx].p_paddr,
342                    phdr[phx].p_filesz, phdr[phx].p_memsz, phdr[phx].p_flags);
343#endif
344        offset += sizeof(phdr[0]);
345    }
346    if (base) {
347        // Set address offset based on lowest address in file.
348        addr_offset = 0xFFFFFFFF;
349        for (phx = 0;  phx < ehdr.e_phnum;  phx++) {
350#ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS     
351            if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_vaddr < addr_offset)) {
352                addr_offset = phdr[phx].p_vaddr;
353#else
354            if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_paddr < addr_offset)) {
355                addr_offset = phdr[phx].p_paddr;
356#endif
357            }
358        }
359        addr_offset = (unsigned long)base - addr_offset;
360    } else {
361        addr_offset = 0;
362    }
363    for (phx = 0;  phx < ehdr.e_phnum;  phx++) {
364        if (phdr[phx].p_type == PT_LOAD) {
365            // Loadable segment
366#ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS
367            addr = (unsigned char *)phdr[phx].p_vaddr;
368#else     
369            addr = (unsigned char *)phdr[phx].p_paddr;
370#endif
371            len = phdr[phx].p_filesz;
372            if ((unsigned long)addr < lowest_address) {
373                lowest_address = (unsigned long)addr;
374            }
375            addr += addr_offset;
376            if (offset > phdr[phx].p_offset) {
377                if ((phdr[phx].p_offset + len) < offset) {
378                    diag_printf("Can't load ELF file - program headers out of order\n");
379                    return 0;
380                }
381                addr += offset - phdr[phx].p_offset;
382            } else {
383                while (offset < phdr[phx].p_offset) {
384                    if ((*getc)() < 0) {
385                        diag_printf(SHORT_DATA);
386                        return 0;
387                    }
388                    offset++;
389                }
390            }
391
392            // Copy data into memory
393            while (len-- > 0) {
394#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
395                if (!valid_address(addr)) {
396                    redboot_getc_terminate(true);
397                    diag_printf("*** Abort! Attempt to load ELF data to address: %p which is not in RAM\n", (void*)addr);
398                    return 0;
399                }
400#endif
401                if ((ch = (*getc)()) < 0) {
402                    diag_printf(SHORT_DATA);
403                    return 0;
404                }
405                *addr++ = ch;
406                offset++;
407                if ((unsigned long)(addr-addr_offset) > highest_address) {
408                    highest_address = (unsigned long)(addr - addr_offset);
409                }
410            }
411        }
412    }
413
414    // Save load base/top and entry
415    if (base) {
416        load_address = base;
417        load_address_end = base + (highest_address - lowest_address);
418        entry_address = base + (ehdr.e_entry - lowest_address);
419    } else {
420        load_address = lowest_address;
421        load_address_end = highest_address;
422        entry_address = ehdr.e_entry;
423    }
424
425    redboot_getc_terminate(false);
426    if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset);
427    diag_printf("Entry point: %p, address range: %p-%p\n", 
428                (void*)entry_address, (void *)load_address, (void *)load_address_end);
429    return 1;
430#else // CYGSEM_REDBOOT_ELF
431    diag_printf("Loading ELF images not supported\n");
432    return 0;
433#endif // CYGSEM_REDBOOT_ELF
434}
435
436
437//
438// Scan a string of hex bytes and update the checksum
439//
440static long
441_hex2(int (*getc)(void), int len, long *sum)
442{
443    int val, byte;
444    char c1, c2;
445
446    val = 0;
447    while (len-- > 0) {
448        c1 = (*getc)();
449        c2 = (*getc)();
450        if (_is_hex(c1) && _is_hex(c2)) {
451            val <<= 8;
452            byte = (_from_hex(c1)<<4) | _from_hex(c2);
453            val |= byte;
454            if (sum) {
455                *sum += byte;
456            }
457        } else {
458            return (-1);
459        }
460    }
461    return (val);
462}
463
464//
465// Process a set of S-records, loading the contents into memory. 
466// Note: if a "base" value is provided, the data will be relocated
467// relative to that location.  Of course, this can only work for
468// the first section of the data, so if there are non-contiguous
469// pieces of data, they will end up relocated in the same fashion.
470// Because of this, "base" probably only makes sense for a set of
471// data which has only one section, e.g. a ROM image.
472//
473static unsigned long
474load_srec_image(getc_t getc, unsigned long base)
475{
476    int  c;
477    long offset = 0, count, sum, val, cksum;
478    unsigned char *addr, *base_addr;
479    char type;
480    bool first_addr = true;
481    unsigned long addr_offset = 0;
482    unsigned long highest_address = 0;
483    unsigned long lowest_address = 0xFFFFFFFF;
484
485    while ((c = (*getc)()) > 0) {
486        // Start of line
487        if (c != 'S') {
488            redboot_getc_terminate(true);
489            diag_printf("Invalid S-record at offset %p, input: %c\n", 
490                   (void *)offset, c);
491            return 0;
492        }
493        type = (*getc)();
494        offset += 2;
495        sum = 0;
496        if ((count = _hex2(getc, 1, &sum)) < 0) {
497            redboot_getc_terminate(true);
498            diag_printf("Bad S-record count at offset %p\n", (void *)offset);
499            return 0;
500        }
501        offset += 1;
502        switch (type) {
503        case '0':
504            break;
505        case '1':
506        case '2':
507        case '3':
508            base_addr = addr = (unsigned char *)_hex2(getc, (type-'1'+2), &sum);
509            offset += (type-'1'+2);
510            if (first_addr) {
511                if (base) {
512                    addr_offset = (unsigned long)base - (unsigned long)addr;
513                } else {
514                    addr_offset = 0;                   
515                }
516                first_addr = false;
517            }
518            addr += addr_offset;
519            if ((unsigned long)(addr-addr_offset) < lowest_address) {
520                lowest_address = (unsigned long)(addr - addr_offset);
521            }
522#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
523            if (!valid_address(addr)) {
524              // Only if there is no need to stop the download before printing
525              // output can we ask confirmation questions.
526                redboot_getc_terminate(true);
527                diag_printf("*** Abort! Attempt to load S-record to address: %p, which is not in RAM\n",(void*)addr);
528                return 0;
529            }
530#endif
531            count -= ((type-'1'+2)+1);
532            offset += count;
533            while (count-- > 0) {
534                val = _hex2(getc, 1, &sum);
535                *addr++ = val;
536            }
537            cksum = _hex2(getc, 1, 0);
538            offset += 1;
539            sum = sum & 0xFF;
540            cksum = (~cksum & 0xFF);
541            if (cksum != sum) {
542                redboot_getc_terminate(true);
543                diag_printf("*** Warning! Checksum failure - Addr: %lx, %02lX <> %02lX\n", 
544                       (unsigned long)base_addr, sum, cksum);
545                return 0;
546            }
547            if ((unsigned long)(addr-addr_offset) > highest_address) {
548                highest_address = (unsigned long)(addr - addr_offset);
549            }
550            break;
551        case '7':
552        case '8':
553        case '9':
554            addr = (unsigned char *)_hex2(getc, ('9'-type+2), &sum);
555            offset += ('9'-type+2);
556            // Save load base/top, entry address
557            if (base) {
558                load_address = base;
559                load_address_end = base + (highest_address - lowest_address);
560                entry_address = (unsigned long)(base + (addr - lowest_address));
561            } else {
562                load_address = lowest_address;
563                load_address_end = highest_address;
564                entry_address = (unsigned long)addr;
565            }
566            redboot_getc_terminate(false);
567            if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset);
568            diag_printf("Entry point: %p, address range: %p-%p\n", 
569                   (void*)entry_address, (void *)load_address, (void *)load_address_end);
570
571            return load_address_end;
572        default:
573            redboot_getc_terminate(true);
574            diag_printf("Invalid S-record at offset 0x%lx, type: %x\n", 
575                   (unsigned long)offset, type);
576            return 0;
577        }
578        while ((c = (*getc)()) != '\n') offset++;
579    }
580    return 0;
581}
582
583//
584// 'load' CLI command processing
585//   -b - specify a load [base] address
586//   -m - specify an I/O stream/method
587//   -c - Alternate serial I/O channel
588#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
589//   -d - Decompress data [packed via 'zlib']
590#endif
591//
592void 
593do_load(int argc, char *argv[])
594{
595    int res, num_options;
596    int i, err;
597    bool verbose, raw;
598    bool base_addr_set, mode_str_set;
599    char *mode_str;
600#ifdef CYGPKG_REDBOOT_NETWORKING
601    struct sockaddr_in host;
602    bool hostname_set, port_set;
603    char *hostname;
604#endif
605    bool decompress = false;
606    int chan = -1;
607#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
608    bool chan_set;
609#endif
610    unsigned long base = 0;
611    unsigned long end = 0;
612    char type[4];
613    char *filename = 0;
614    struct option_info opts[8];
615    connection_info_t info;
616    getc_io_funcs_t *io = NULL;
617    struct load_io_entry *io_tab;
618    unsigned int port;  //int because it's an OPTION_ARG_TYPE_NUM, but will be cast to short
619#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
620    bool spillover_ok = false;
621#endif
622
623#ifdef CYGPKG_REDBOOT_NETWORKING
624    memset((char *)&host, 0, sizeof(host));
625    host.sin_len = sizeof(host);
626    host.sin_family = AF_INET;
627    host.sin_addr = my_bootp_info.bp_siaddr;
628    host.sin_port = 0;
629#endif
630
631    init_opts(&opts[0], 'v', false, OPTION_ARG_TYPE_FLG, 
632              (void *)&verbose, 0, "verbose");
633    init_opts(&opts[1], 'r', false, OPTION_ARG_TYPE_FLG, 
634              (void *)&raw, 0, "load raw data");
635    init_opts(&opts[2], 'b', true, OPTION_ARG_TYPE_NUM, 
636              (void *)&base, (bool *)&base_addr_set, "load address");
637    init_opts(&opts[3], 'm', true, OPTION_ARG_TYPE_STR, 
638              (void *)&mode_str, (bool *)&mode_str_set, "download mode (TFTP, xyzMODEM, or disk)");
639    num_options = 4;
640#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
641    init_opts(&opts[num_options], 'c', true, OPTION_ARG_TYPE_NUM, 
642              (void *)&chan, (bool *)&chan_set, "I/O channel");
643    num_options++;
644#endif
645#ifdef CYGPKG_REDBOOT_NETWORKING
646    init_opts(&opts[num_options], 'h', true, OPTION_ARG_TYPE_STR, 
647              (void *)&hostname, (bool *)&hostname_set, "host name or IP address");
648    num_options++;
649    init_opts(&opts[num_options], 'p', true, OPTION_ARG_TYPE_NUM, 
650              (void *)&port, (bool *)&port_set, "TCP port");
651    num_options++;
652#endif
653#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
654    init_opts(&opts[num_options], 'd', false, OPTION_ARG_TYPE_FLG, 
655              (void *)&decompress, 0, "decompress");
656    num_options++;
657#endif
658
659    CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options");
660   
661    if (!scan_opts(argc, argv, 1, opts, num_options, 
662                   (void *)&filename, OPTION_ARG_TYPE_STR, "file name")) {
663        return;
664    }
665#ifdef CYGPKG_REDBOOT_NETWORKING
666    if (hostname_set) {
667        ip_route_t rt;
668        if (!_gethostbyname(hostname, (in_addr_t *)&host)) {
669            diag_printf("Invalid host: %s\n", hostname);
670            return;
671        }
672        /* check that the host can be accessed */
673        if (__arp_lookup((ip_addr_t *)&host.sin_addr, &rt) < 0) {
674            diag_printf("Unable to reach host %s (%s)\n",
675                        hostname, inet_ntoa((in_addr_t *)&host));
676            return;
677        }
678    }
679    if (port_set) 
680            host.sin_port = port;
681#endif
682    if (chan >= CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) {
683        diag_printf("Invalid I/O channel: %d\n", chan);
684        return;
685    }
686    if (mode_str_set) {
687        for (io_tab = __RedBoot_LOAD_TAB__; 
688             io_tab != &__RedBoot_LOAD_TAB_END__;  io_tab++) {
689            if (strncasecmp(&mode_str[0], io_tab->name, strlen(&mode_str[0])) == 0) {
690                io = io_tab->funcs;
691                break;
692            }
693        }
694        if (!io) {
695            diag_printf("Invalid 'mode': %s.  Valid modes are:", mode_str);
696            for (io_tab = __RedBoot_LOAD_TAB__; 
697                 io_tab != &__RedBoot_LOAD_TAB_END__;  io_tab++) {
698                diag_printf(" %s", io_tab->name);
699            }
700            diag_printf("\n");
701        }
702        if (!io) {
703            return;
704        }
705        verbose &= io_tab->can_verbose;
706        if (io_tab->need_filename && !filename) {
707            diag_printf("File name required\n");
708            diag_printf("usage: load %s\n", usage);
709            return;
710        }
711    } else {
712        char *which;
713        io_tab = (struct load_io_entry *)NULL;  // Default
714#ifdef CYGPKG_REDBOOT_NETWORKING
715#ifdef CYGSEM_REDBOOT_NET_TFTP_DOWNLOAD       
716        which = "TFTP";
717        io = &tftp_io;
718#elif defined(CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD)
719        which = "HTTP";
720        io = &http_io;
721#endif
722#endif
723#ifdef CYGPKG_REDBOOT_FILEIO
724        // Make file I/O default if mounted
725        if (fileio_mounted) {
726            which = "file";
727            io = &fileio_io;
728        }
729#endif
730        if (!io) {
731#ifdef CYGBLD_BUILD_REDBOOT_WITH_XYZMODEM
732            which = "Xmodem";
733            io = &xyzModem_io;
734            verbose = false;
735#else
736            diag_printf("No default protocol!\n");
737            return;
738#endif
739        }
740        diag_printf("Using default protocol (%s)\n", which);
741    }
742#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
743    if (base_addr_set && !valid_address((unsigned char *)base)) {
744        if (!verify_action("Specified address (%p) is not believed to be in RAM", (void*)base))
745            return;
746        spillover_ok = true;
747    }
748#endif
749    if (raw && !base_addr_set) {
750        diag_printf("Raw load requires a memory address\n");
751        return;
752    }
753    info.filename = filename;
754    info.chan = chan;
755    info.mode = io_tab ? io_tab->mode : 0;
756#ifdef CYGPKG_REDBOOT_NETWORKING
757    info.server = &host;
758#endif
759    res = redboot_getc_init(&info, io, verbose, decompress);
760    if (res < 0) {
761        return;
762    }
763
764    // Stream open, process the data
765    if (raw) {
766        unsigned char *mp = (unsigned char *)base;
767        err = 0;
768        while ((res = redboot_getc()) >= 0) {
769#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
770            if (!valid_address(mp) && !spillover_ok) {
771                // Only if there is no need to stop the download
772                // before printing output can we ask confirmation
773                // questions.
774                redboot_getc_terminate(true);
775                diag_printf("*** Abort! RAW data spills over limit of user RAM at %p\n",(void*)mp);
776                err = -1;
777                break;
778            }
779#endif
780            *mp++ = res;
781        }
782        end = (unsigned long) mp;
783
784        // Save load base/top
785        load_address = base;
786        load_address_end = end;
787        entry_address = base;           // best guess
788
789        redboot_getc_terminate(false);
790        if (0 == err)
791            diag_printf("Raw file loaded %p-%p, assumed entry at %p\n", 
792                        (void *)base, (void *)(end - 1), (void*)base);
793    } else {
794        // Read initial header - to determine file [image] type
795        for (i = 0;  i < sizeof(type);  i++) {
796            if ((res = redboot_getc()) < 0) {
797                err = getc_info.err;
798                break;
799            } 
800            type[i] = res;
801        }
802        if (res >= 0) {
803            redboot_getc_rewind();  // Restore header to stream
804            // Treat data as some sort of executable image
805            if (strncmp(&type[1], "ELF", 3) == 0) {
806                end = load_elf_image(redboot_getc, base);
807            } else if ((type[0] == 'S') &&
808                       ((type[1] >= '0') && (type[1] <= '9'))) {
809                end = load_srec_image(redboot_getc, base);
810            } else {
811                redboot_getc_terminate(true);
812                diag_printf("Unrecognized image type: 0x%lx\n", *(unsigned long *)type);
813            }
814        }
815    }
816
817    redboot_getc_close();  // Clean up
818    return;
819}
Note: See TracBrowser for help on using the repository browser.