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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [redboot/] [current/] [src/] [load.c] - Blame information for rev 786

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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