OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [ecos-2.0/] [packages/] [redboot/] [v2_0/] [src/] [load.c] - Blame information for rev 1773

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.