]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/load.c
Initial revision
[karo-tx-redboot.git] / packages / redboot / v2_0 / src / load.c
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
77 static char usage[] = "[-r] [-v] [-z to swap endianness on 16 bit] "
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
91 RedBoot_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
102 CYG_HAL_TABLE_BEGIN( __RedBoot_LOAD_TAB__, RedBoot_load );
103 CYG_HAL_TABLE_END( __RedBoot_LOAD_TAB_END__, RedBoot_load );
104 extern 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
108 struct {
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
122 typedef 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 //
130 static int 
131 redboot_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 //
167 static 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
200 static int
201 redboot_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
235 static void
236 redboot_getc_rewind(void)
237 {
238     getc_info.bufp = getc_info.buf;
239     getc_info.avail = getc_info.len;
240 }
241
242 static void
243 redboot_getc_terminate(bool abort)
244 {
245     if (getc_info.io->terminate) {
246         (getc_info.io->terminate)(abort, redboot_getc);
247     }
248 }
249
250 static void
251 redboot_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 //
271 static 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 //
292 //
293 // Note that in case of multicore and the core we wanna load the 
294 // image for is not in the same endianness that the core we run 
295 // redboot from, have to invert bytes on 16-bit boundary 
296 // (16-bit memory)
297 //
298 static unsigned long
299 load_elf_image(getc_t getc, unsigned long base, bool swap16bit)
300 {
301 #ifdef CYGSEM_REDBOOT_ELF
302     Elf32_Ehdr ehdr;
303 #define MAX_PHDR 8
304     Elf32_Phdr phdr[MAX_PHDR];
305     unsigned long offset = 0;
306     int phx, len, ch;
307     unsigned char *addr, *addr_swap;
308     unsigned long addr_offset = 0;
309     unsigned long highest_address = 0;
310     unsigned long lowest_address = 0xFFFFFFFF;
311     unsigned char *SHORT_DATA = "Short data reading ELF file\n";
312
313     // Read the header
314     if (_read(getc, (unsigned char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr)) {
315         diag_printf("Can't read ELF header\n");
316         redboot_getc_terminate(true);
317         return 0;
318     }
319     offset += sizeof(ehdr);    
320 #if 0 // DEBUG
321     diag_printf("Type: %d, Machine: %d, Version: %d, Entry: %p, PHoff: %p/%d/%d, SHoff: %p/%d/%d\n",
322                 ehdr.e_type, ehdr.e_machine, ehdr.e_version, ehdr.e_entry, 
323                 ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_phnum,
324                 ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shnum);
325 #endif
326     if (ehdr.e_type != ET_EXEC) {
327         diag_printf("Only absolute ELF images supported\n");
328         redboot_getc_terminate(true);
329         return 0;
330     }
331     if (ehdr.e_phnum > MAX_PHDR) {
332         diag_printf("Too many program headers\n");
333         redboot_getc_terminate(true);
334         return 0;
335     }
336     while (offset < ehdr.e_phoff) {
337         if ((*getc)() < 0) {
338             diag_printf(SHORT_DATA);
339             redboot_getc_terminate(true);
340             return 0;
341         }
342         offset++;
343     }
344     for (phx = 0;  phx < ehdr.e_phnum;  phx++) {
345         if (_read(getc, (unsigned char *)&phdr[phx], sizeof(phdr[0])) != sizeof(phdr[0])) {
346             diag_printf("Can't read ELF program header\n");
347             redboot_getc_terminate(true);
348             return 0;
349         }
350 #if 0 // DEBUG
351         diag_printf("Program header: type: %d, off: %p, va: %p, pa: %p, len: %d/%d, flags: %d\n",
352                     phdr[phx].p_type, phdr[phx].p_offset, phdr[phx].p_vaddr, phdr[phx].p_paddr,
353                     phdr[phx].p_filesz, phdr[phx].p_memsz, phdr[phx].p_flags);
354 #endif
355         offset += sizeof(phdr[0]);
356     }
357     if (base) {
358         // Set address offset based on lowest address in file.
359         addr_offset = 0xFFFFFFFF;
360         for (phx = 0;  phx < ehdr.e_phnum;  phx++) {
361 #ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS     
362             if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_vaddr < addr_offset)) {
363                 addr_offset = phdr[phx].p_vaddr;
364 #else
365             if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_paddr < addr_offset)) {
366                 addr_offset = phdr[phx].p_paddr;
367 #endif
368             }
369         }
370         addr_offset = (unsigned long)base - addr_offset;
371     } else {
372         addr_offset = 0;
373     }
374     for (phx = 0;  phx < ehdr.e_phnum;  phx++) {
375         if (phdr[phx].p_type == PT_LOAD) {
376             // Loadable segment
377 #ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS
378             addr = (unsigned char *)phdr[phx].p_vaddr;
379 #else     
380             addr = (unsigned char *)phdr[phx].p_paddr;
381 #endif
382             len = phdr[phx].p_filesz;
383             if ((unsigned long)addr < lowest_address) {
384                 lowest_address = (unsigned long)addr;
385             }
386             addr += addr_offset;
387             if (offset > phdr[phx].p_offset) {
388                 if ((phdr[phx].p_offset + len) < offset) {
389                     diag_printf("Can't load ELF file - program headers out of order\n");
390                     redboot_getc_terminate(true);
391                     return 0;
392                 }
393                 addr += offset - phdr[phx].p_offset;
394             } else {
395                 while (offset < phdr[phx].p_offset) {
396                     if ((*getc)() < 0) {
397                         diag_printf(SHORT_DATA);
398                         redboot_getc_terminate(true);
399                         return 0;
400                     }
401                     offset++;
402                 }
403             }
404
405             // Copy data into memory
406             while (len-- > 0) {
407 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
408                 if (!valid_address(addr)) {
409                     redboot_getc_terminate(true);
410                     diag_printf("*** Abort! Attempt to load ELF data to address: %p which is not in RAM\n", (void*)addr);
411                     return 0;
412                 }
413 #endif
414                 if ((ch = (*getc)()) < 0) {
415                     diag_printf(SHORT_DATA);
416                     redboot_getc_terminate(true);
417                     return 0;
418                 }
419      
420                 /* In case of multicore and the core we wanna load the image for is not in the same endianness
421                 that the core we run redboot from, have to invert bytes on 16-bit boundary (16-bit memory)*/
422                 if(swap16bit){
423                     // addr is even, have to write char data to the last address
424                     if(((unsigned long)addr)%2){
425                         addr_swap=addr-1;
426                         *addr_swap = ch;
427                     }
428                     // addr is odd, have to write char data to the next address
429                     else{
430                         addr_swap=addr+1;
431                        *addr_swap = ch;
432                     }
433                     addr++;
434                 }
435                 else {
436                     *addr++ = ch;
437                 }
438                 offset++;
439                 if ((unsigned long)(addr-addr_offset) > highest_address) {
440                     highest_address = (unsigned long)(addr - addr_offset);
441                 }
442             }
443         }
444     }
445
446     // Save load base/top and entry
447     if (base) {
448         load_address = base;
449         load_address_end = base + (highest_address - lowest_address);
450         entry_address = base + (ehdr.e_entry - lowest_address);
451     } else {
452         load_address = lowest_address;
453         load_address_end = highest_address;
454         entry_address = ehdr.e_entry;
455     }
456
457     // nak everything to stop the transfer, since redboot
458     // usually doesn't read all the way to the end of the
459     // elf files.
460     redboot_getc_terminate(true);
461     if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset);
462     diag_printf("Entry point: %p, address range: %p-%p\n", 
463                 (void*)entry_address, (void *)load_address, (void *)load_address_end);
464     return 1;
465 #else // CYGSEM_REDBOOT_ELF
466     diag_printf("Loading ELF images not supported\n");
467     return 0;
468 #endif // CYGSEM_REDBOOT_ELF
469 }
470
471
472 //
473 // Scan a string of hex bytes and update the checksum
474 //
475 static long
476 _hex2(int (*getc)(void), int len, long *sum)
477 {
478     int val, byte;
479     char c1, c2;
480
481     val = 0;
482     while (len-- > 0) {
483         c1 = (*getc)();
484         c2 = (*getc)();
485         if (_is_hex(c1) && _is_hex(c2)) {
486             val <<= 8;
487             byte = (_from_hex(c1)<<4) | _from_hex(c2);
488             val |= byte;
489             if (sum) {
490                 *sum += byte;
491             }
492         } else {
493             return (-1);
494         }
495     }
496     return (val);
497 }
498
499 //
500 // Process a set of S-records, loading the contents into memory.  
501 // Note: if a "base" value is provided, the data will be relocated
502 // relative to that location.  Of course, this can only work for
503 // the first section of the data, so if there are non-contiguous
504 // pieces of data, they will end up relocated in the same fashion.
505 // Because of this, "base" probably only makes sense for a set of
506 // data which has only one section, e.g. a ROM image.
507 //
508 // Note that in case of multicore and the core we wanna load the 
509 // image for is not in the same endianness that the core we run 
510 // redboot from, have to invert bytes on 16-bit boundary 
511 // (16-bit memory)
512 //
513 static unsigned long
514 load_srec_image(getc_t getc, unsigned long base, bool swap16bit)
515 {
516     int  c;
517     long offset = 0, count, sum, val, cksum;
518     unsigned char *addr, *base_addr, *addr_swap;
519     char type;
520     bool first_addr = true;
521     unsigned long addr_offset = 0;
522     unsigned long highest_address = 0;
523     unsigned long lowest_address = 0xFFFFFFFF;
524
525     while ((c = (*getc)()) > 0) {
526         // Start of line
527         if (c != 'S') {
528             redboot_getc_terminate(true);
529             diag_printf("Invalid S-record at offset %p, input: %c\n", 
530                    (void *)offset, c);
531             return 0;
532         }
533         type = (*getc)();
534         offset += 2;
535         sum = 0;
536         if ((count = _hex2(getc, 1, &sum)) < 0) {
537             redboot_getc_terminate(true);
538             diag_printf("Bad S-record count at offset %p\n", (void *)offset);
539             return 0;
540         }
541         offset += 1;
542         switch (type) {
543         case '0':
544             break;
545         case '1':
546         case '2':
547         case '3':
548             base_addr = addr = (unsigned char *)_hex2(getc, (type-'1'+2), &sum);
549             offset += (type-'1'+2);
550             if (first_addr) {
551                 if (base) {
552                     addr_offset = (unsigned long)base - (unsigned long)addr;
553                 } else {
554                     addr_offset = 0;                    
555                 }
556                 first_addr = false;
557             }
558             addr += addr_offset;
559             if ((unsigned long)(addr-addr_offset) < lowest_address) {
560                 lowest_address = (unsigned long)(addr - addr_offset);
561             }
562 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
563             if (!valid_address(addr)) {
564               // Only if there is no need to stop the download before printing
565               // output can we ask confirmation questions.
566                 redboot_getc_terminate(true);
567                 diag_printf("*** Abort! Attempt to load S-record to address: %p, which is not in RAM\n",(void*)addr);
568                 return 0;
569             }
570 #endif
571             count -= ((type-'1'+2)+1);
572             offset += count;
573             while (count-- > 0) {
574                 val = _hex2(getc, 1, &sum);
575                 /* In case of multicore and the core we wanna load the image for is not in the same endianness
576                 that the core we run redboot from, have to invert bytes on 16-bit boundary (16-bit memory)*/
577                 if(swap16bit){
578                     // addr is even, have to write char data to the last address
579                     if(((unsigned long)addr)%2){
580                         addr_swap=addr-1;
581                         *addr_swap = val;
582                     }
583                     // addr is odd, have to write char data to the next address
584                     else{
585                         addr_swap=addr+1;
586                         *addr_swap = val;
587                     }
588                     addr++;
589                 }
590                 else {
591                 *addr++ = val;
592                 }
593             }
594             cksum = _hex2(getc, 1, 0);
595             offset += 1;
596             sum = sum & 0xFF;
597             cksum = (~cksum & 0xFF);
598             if (cksum != sum) {
599                 redboot_getc_terminate(true);
600                 diag_printf("*** Warning! Checksum failure - Addr: %lx, %02lX <> %02lX\n", 
601                        (unsigned long)base_addr, sum, cksum);
602                 return 0;
603             }
604             if ((unsigned long)(addr-addr_offset) > highest_address) {
605                 highest_address = (unsigned long)(addr - addr_offset);
606             }
607             break;
608         case '7':
609         case '8':
610         case '9':
611             addr = (unsigned char *)_hex2(getc, ('9'-type+2), &sum);
612             offset += ('9'-type+2);
613             // Save load base/top, entry address
614             if (base) {
615                 load_address = base;
616                 load_address_end = base + (highest_address - lowest_address);
617                 entry_address = (unsigned long)(base + (addr - lowest_address));
618             } else {
619                 load_address = lowest_address;
620                 load_address_end = highest_address;
621                 entry_address = (unsigned long)addr;
622             }
623             redboot_getc_terminate(false);
624             if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset);
625             diag_printf("Entry point: %p, address range: %p-%p\n", 
626                    (void*)entry_address, (void *)load_address, (void *)load_address_end);
627
628             return load_address_end;
629         default:
630             redboot_getc_terminate(true);
631             diag_printf("Invalid S-record at offset 0x%lx, type: %x\n", 
632                    (unsigned long)offset, type);
633             return 0;
634         }
635         while ((c = (*getc)()) != '\n') offset++;
636     }
637     return 0;
638 }
639
640 //
641 // 'load' CLI command processing
642 //   -b - specify a load [base] address
643 //   -m - specify an I/O stream/method
644 //   -c - Alternate serial I/O channel
645 #ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
646 //   -d - Decompress data [packed via 'zlib']
647 #endif
648 //
649 void 
650 do_load(int argc, char *argv[])
651 {
652     int res, num_options;
653     int i, err;
654     bool verbose, raw, swap16bit;
655     bool base_addr_set, mode_str_set;
656     char *mode_str;
657 #ifdef CYGPKG_REDBOOT_NETWORKING
658     struct sockaddr_in host;
659     bool hostname_set, port_set;
660     unsigned int port;  // int because it's an OPTION_ARG_TYPE_NUM, 
661                         // but will be cast to short
662     char *hostname;
663 #endif
664     bool decompress = false;
665     int chan = -1;
666 #if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
667     bool chan_set;
668 #endif
669     unsigned long base = 0;
670     unsigned long end = 0;
671     char type[4];
672     char *filename = 0;
673     struct option_info opts[9];
674     connection_info_t info;
675     getc_io_funcs_t *io = NULL;
676     struct load_io_entry *io_tab;
677 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
678     bool spillover_ok = false;
679 #endif
680
681 #ifdef CYGPKG_REDBOOT_NETWORKING
682     memset((char *)&host, 0, sizeof(host));
683     host.sin_len = sizeof(host);
684     host.sin_family = AF_INET;
685     host.sin_addr = my_bootp_info.bp_siaddr;
686     host.sin_port = 0;
687 #endif
688
689     init_opts(&opts[0], 'v', false, OPTION_ARG_TYPE_FLG, 
690               (void *)&verbose, 0, "verbose");
691     init_opts(&opts[1], 'r', false, OPTION_ARG_TYPE_FLG, 
692               (void *)&raw, 0, "load raw data");
693     init_opts(&opts[2], 'b', true, OPTION_ARG_TYPE_NUM, 
694               (void *)&base, (bool *)&base_addr_set, "load address");
695     init_opts(&opts[3], 'm', true, OPTION_ARG_TYPE_STR, 
696               (void *)&mode_str, (bool *)&mode_str_set, "download mode (TFTP, xyzMODEM, or disk)");
697     init_opts(&opts[4], 'z', false, OPTION_ARG_TYPE_FLG, 
698               (void *)&swap16bit, 0, "swap endianness on 16 bit");
699     num_options = 5;
700 #if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
701     init_opts(&opts[num_options], 'c', true, OPTION_ARG_TYPE_NUM, 
702               (void *)&chan, (bool *)&chan_set, "I/O channel");
703     num_options++;
704 #endif
705 #ifdef CYGPKG_REDBOOT_NETWORKING
706     init_opts(&opts[num_options], 'h', true, OPTION_ARG_TYPE_STR, 
707               (void *)&hostname, (bool *)&hostname_set, "host name or IP address");
708     num_options++;
709     init_opts(&opts[num_options], 'p', true, OPTION_ARG_TYPE_NUM, 
710               (void *)&port, (bool *)&port_set, "TCP port");
711     num_options++;
712 #endif
713 #ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
714     init_opts(&opts[num_options], 'd', false, OPTION_ARG_TYPE_FLG, 
715               (void *)&decompress, 0, "decompress");
716     num_options++;
717 #endif
718
719     CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options");
720     
721     if (!scan_opts(argc, argv, 1, opts, num_options, 
722                    (void *)&filename, OPTION_ARG_TYPE_STR, "file name")) {
723         return;
724     }
725 #ifdef CYGPKG_REDBOOT_NETWORKING
726     if (hostname_set) {
727         ip_route_t rt;
728         if (!_gethostbyname(hostname, (in_addr_t *)&host)) {
729             diag_printf("Invalid host: %s\n", hostname);
730             return;
731         }
732         /* check that the host can be accessed */
733         if (__arp_lookup((ip_addr_t *)&host.sin_addr, &rt) < 0) {
734             diag_printf("Unable to reach host %s (%s)\n",
735                         hostname, inet_ntoa((in_addr_t *)&host));
736             return;
737         }
738     }
739     if (port_set) 
740             host.sin_port = port;
741 #endif
742     if (chan >= CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) {
743         diag_printf("Invalid I/O channel: %d\n", chan);
744         return;
745     }
746     if (mode_str_set) {
747         for (io_tab = __RedBoot_LOAD_TAB__; 
748              io_tab != &__RedBoot_LOAD_TAB_END__;  io_tab++) {
749             if (strncasecmp(&mode_str[0], io_tab->name, strlen(&mode_str[0])) == 0) {
750                 io = io_tab->funcs;
751                 break;
752             }
753         }
754         if (!io) {
755             diag_printf("Invalid 'mode': %s.  Valid modes are:", mode_str);
756             for (io_tab = __RedBoot_LOAD_TAB__; 
757                  io_tab != &__RedBoot_LOAD_TAB_END__;  io_tab++) {
758                 diag_printf(" %s", io_tab->name);
759             }
760             diag_printf("\n");
761         }
762         if (!io) {
763             return;
764         }
765         verbose &= io_tab->can_verbose;
766         if (io_tab->need_filename && !filename) {
767             diag_printf("File name required\n");
768             diag_printf("usage: load %s\n", usage);
769             return;
770         }
771     } else {
772         char *which;
773         io_tab = (struct load_io_entry *)NULL;  // Default
774 #ifdef CYGPKG_REDBOOT_NETWORKING
775 #ifdef CYGSEM_REDBOOT_NET_TFTP_DOWNLOAD        
776         which = "TFTP";
777         io = &tftp_io;
778 #elif defined(CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD)
779         which = "HTTP";
780         io = &http_io;
781 #endif
782 #endif
783 #ifdef CYGPKG_REDBOOT_FILEIO
784         // Make file I/O default if mounted
785         if (fileio_mounted) {
786             which = "file";
787             io = &fileio_io;
788         }
789 #endif
790         if (!io) {
791 #ifdef CYGBLD_BUILD_REDBOOT_WITH_XYZMODEM
792             which = "Xmodem";
793             io = &xyzModem_io;
794             verbose = false;
795 #else
796             diag_printf("No default protocol!\n");
797             return;
798 #endif
799         }
800         diag_printf("Using default protocol (%s)\n", which);
801     }
802 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
803     if (base_addr_set && !valid_address((unsigned char *)base)) {
804         if (!verify_action("Specified address (%p) is not believed to be in RAM", (void*)base))
805             return;
806         spillover_ok = true;
807     }
808 #endif
809     if (raw && !base_addr_set) {
810         diag_printf("Raw load requires a memory address\n");
811         return;
812     }
813     info.filename = filename;
814     info.chan = chan;
815     info.mode = io_tab ? io_tab->mode : 0;
816 #ifdef CYGPKG_REDBOOT_NETWORKING
817     info.server = &host;
818 #endif
819     res = redboot_getc_init(&info, io, verbose, decompress);
820     if (res < 0) {
821         return;
822     }
823
824     // Stream open, process the data
825     if (raw) {
826         unsigned char *mp = (unsigned char *)base;
827         unsigned char *addr_swap;
828         err = 0;
829         while ((res = redboot_getc()) >= 0) {
830 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
831             if (!valid_address(mp) && !spillover_ok) {
832                 // Only if there is no need to stop the download
833                 // before printing output can we ask confirmation
834                 // questions.
835                 redboot_getc_terminate(true);
836                 diag_printf("*** Abort! RAW data spills over limit of user RAM at %p\n",(void*)mp);
837                 err = -1;
838                 break;
839             }
840 #endif
841
842             /* In case of multicore and the core we wanna load the image for is not in the same endianness
843             that the core we run redboot from, have to invert bytes on 16-bit boundary (16-bit memory)*/
844             if(swap16bit){
845                 // addr is even, have to write char data to the last address
846                 if(((unsigned long)mp)%2){
847                     addr_swap=mp-1;
848                     *addr_swap = res;
849                 }
850                 // addr is odd, have to write char data to the next address
851                 else{
852                    addr_swap=mp+1;
853                     *addr_swap = res;
854                 }
855                 mp++;
856             }
857             else {
858                 *mp++ = res;
859             }
860         }
861         end = (unsigned long) mp;
862
863         // Save load base/top
864         load_address = base;
865         load_address_end = end;
866         entry_address = base;           // best guess
867
868         redboot_getc_terminate(false);
869         if (0 == err)
870             diag_printf("Raw file loaded %p-%p, assumed entry at %p\n", 
871                         (void *)base, (void *)(end - 1), (void*)base);
872     } else {
873         // Read initial header - to determine file [image] type
874         for (i = 0;  i < sizeof(type);  i++) {
875             if ((res = redboot_getc()) < 0) {
876                 err = getc_info.err;
877                 break;
878             } 
879             type[i] = res;
880         }
881         if (res >= 0) {
882             redboot_getc_rewind();  // Restore header to stream
883             // Treat data as some sort of executable image
884             if (strncmp(&type[1], "ELF", 3) == 0) {
885                 if(swap16bit) {
886                     end = load_elf_image(redboot_getc, base, true);
887                 }
888                 else {
889                     end = load_elf_image(redboot_getc, base, false);
890                 }
891             } else if ((type[0] == 'S') &&
892                        ((type[1] >= '0') && (type[1] <= '9'))) {
893                 if(swap16bit) {
894                     end = load_srec_image(redboot_getc, base, true);
895                 }
896                 else {
897                     end = load_srec_image(redboot_getc, base, false);
898                 }
899             } else {
900                 redboot_getc_terminate(true);
901                 diag_printf("Unrecognized image type: 0x%lx\n", *(unsigned long *)type);
902             }
903         }
904     }
905
906     redboot_getc_close();  // Clean up
907     return;
908 }