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