1 //==========================================================================
5 // RedBoot file/image loader
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
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.
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
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.
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.
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.
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####
45 // Contributors: gthomas, tsmith
50 // This code is part of RedBoot (tm).
52 //####DESCRIPTIONEND####
54 //==========================================================================
58 #ifdef CYGBLD_BUILD_REDBOOT_WITH_XYZMODEM
61 #ifdef CYGPKG_REDBOOT_DISK
64 #ifdef CYGPKG_REDBOOT_FILEIO
65 #include <fs/fileio.h>
67 #ifdef CYGPKG_REDBOOT_NETWORKING
68 #ifdef CYGSEM_REDBOOT_NET_TFTP_DOWNLOAD
69 #include <net/tftp_support.h>
71 #ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD
75 #include <cyg/infra/cyg_ass.h> // assertion macros
77 static char usage[] = "[-r] [-v] [-z to swap endianness on 16 bit] "
78 #ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
81 #ifdef CYGPKG_REDBOOT_NETWORKING
82 "[-h <host>] [-p <TCP port>]"
85 #if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
86 "[-c <channel_number>] "
88 "\n [-b <base_address>] <file_name>";
90 // Exported CLI function
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__;
106 // Buffers, data used by redboot_getc
107 #define BUF_SIZE CYGNUM_REDBOOT_GETC_BUFFER
110 int (*fun)(char *, int len, int *err);
111 unsigned char buf[BUF_SIZE];
114 int verbose, decompress, tick;
115 #ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
116 int (*raw_fun)(char *, int len, int *err);
118 unsigned char _buffer[CYGNUM_REDBOOT_LOAD_ZLIB_BUFFER];
122 typedef int (*getc_t)(void);
125 // Read the next data byte from the stream.
127 // >= 0 - actual data
128 // -1 - error or EOF, status in getc_info.err
133 static char spin[] = "|/-\\|-";
134 if (getc_info.avail < 0) {
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)) {
144 if (getc_info.len < BUF_SIZE) {
145 // No more data available
146 if (getc_info.verbose) diag_printf("\n");
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));
155 if (getc_info.verbose) diag_printf("\n");
160 return *getc_info.bufp++;
163 #ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
165 // Called to fetch a new chunk of data and decompress it
168 _decompress_stream(char *buf, int len, int *err)
170 _pipe_t* p = &getc_info.load_pipe;
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,
179 if ((p->in_avail = res) <= 0) {
187 res = (*_dc_inflate)(p);
194 total += p->out_size;
201 redboot_getc_init(connection_info_t *info, getc_io_funcs_t *funcs,
202 int verbose, int decompress)
206 res = (funcs->open)(info, &getc_info.err);
208 diag_printf("Can't load '%s': %s\n", info->filename, (funcs->error)(getc_info.err));
211 getc_info.io = funcs;
212 getc_info.fun = funcs->read;
214 getc_info.len = BUF_SIZE;
215 getc_info.verbose = verbose;
216 getc_info.decompress = decompress;
218 #ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
220 _pipe_t* p = &getc_info.load_pipe;
221 p->out_buf = &getc_info.buf[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);
236 redboot_getc_rewind(void)
238 getc_info.bufp = getc_info.buf;
239 getc_info.avail = getc_info.len;
243 redboot_getc_terminate(bool abort)
245 if (getc_info.io->terminate) {
246 (getc_info.io->terminate)(abort, redboot_getc);
251 redboot_getc_close(void)
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);
261 err = (*_dc_close)(p, getc_info.err);
266 #ifdef CYGSEM_REDBOOT_ELF
268 // Support function - used to read bytes into a buffer
269 // Returns the number of bytes read (stops short on errors)
272 _read(int (*getc)(void), unsigned char *buf, int len)
290 // Load an ELF [binary] image
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
299 load_elf_image(getc_t getc, unsigned long base, bool swap16bit)
301 #ifdef CYGSEM_REDBOOT_ELF
304 Elf32_Phdr phdr[MAX_PHDR];
305 unsigned long offset = 0;
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";
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);
319 offset += sizeof(ehdr);
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);
326 if (ehdr.e_type != ET_EXEC) {
327 diag_printf("Only absolute ELF images supported\n");
328 redboot_getc_terminate(true);
331 if (ehdr.e_phnum > MAX_PHDR) {
332 diag_printf("Too many program headers\n");
333 redboot_getc_terminate(true);
336 while (offset < ehdr.e_phoff) {
338 diag_printf(SHORT_DATA);
339 redboot_getc_terminate(true);
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);
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);
355 offset += sizeof(phdr[0]);
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;
365 if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_paddr < addr_offset)) {
366 addr_offset = phdr[phx].p_paddr;
370 addr_offset = (unsigned long)base - addr_offset;
374 for (phx = 0; phx < ehdr.e_phnum; phx++) {
375 if (phdr[phx].p_type == PT_LOAD) {
377 #ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS
378 addr = (unsigned char *)phdr[phx].p_vaddr;
380 addr = (unsigned char *)phdr[phx].p_paddr;
382 len = phdr[phx].p_filesz;
383 if ((unsigned long)addr < lowest_address) {
384 lowest_address = (unsigned long)addr;
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);
393 addr += offset - phdr[phx].p_offset;
395 while (offset < phdr[phx].p_offset) {
397 diag_printf(SHORT_DATA);
398 redboot_getc_terminate(true);
405 // Copy data into memory
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);
414 if ((ch = (*getc)()) < 0) {
415 diag_printf(SHORT_DATA);
416 redboot_getc_terminate(true);
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)*/
423 // addr is even, have to write char data to the last address
424 if(((unsigned long)addr)%2){
428 // addr is odd, have to write char data to the next address
439 if ((unsigned long)(addr-addr_offset) > highest_address) {
440 highest_address = (unsigned long)(addr - addr_offset);
446 // Save load base/top and entry
449 load_address_end = base + (highest_address - lowest_address);
450 entry_address = base + (ehdr.e_entry - lowest_address);
452 load_address = lowest_address;
453 load_address_end = highest_address;
454 entry_address = ehdr.e_entry;
457 // nak everything to stop the transfer, since redboot
458 // usually doesn't read all the way to the end of the
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);
465 #else // CYGSEM_REDBOOT_ELF
466 diag_printf("Loading ELF images not supported\n");
468 #endif // CYGSEM_REDBOOT_ELF
473 // Scan a string of hex bytes and update the checksum
476 _hex2(int (*getc)(void), int len, long *sum)
485 if (_is_hex(c1) && _is_hex(c2)) {
487 byte = (_from_hex(c1)<<4) | _from_hex(c2);
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.
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
514 load_srec_image(getc_t getc, unsigned long base, bool swap16bit)
517 long offset = 0, count, sum, val, cksum;
518 unsigned char *addr, *base_addr, *addr_swap;
520 bool first_addr = true;
521 unsigned long addr_offset = 0;
522 unsigned long highest_address = 0;
523 unsigned long lowest_address = 0xFFFFFFFF;
525 while ((c = (*getc)()) > 0) {
528 redboot_getc_terminate(true);
529 diag_printf("Invalid S-record at offset %p, input: %c\n",
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);
548 base_addr = addr = (unsigned char *)_hex2(getc, (type-'1'+2), &sum);
549 offset += (type-'1'+2);
552 addr_offset = (unsigned long)base - (unsigned long)addr;
559 if ((unsigned long)(addr-addr_offset) < lowest_address) {
560 lowest_address = (unsigned long)(addr - addr_offset);
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);
571 count -= ((type-'1'+2)+1);
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)*/
578 // addr is even, have to write char data to the last address
579 if(((unsigned long)addr)%2){
583 // addr is odd, have to write char data to the next address
594 cksum = _hex2(getc, 1, 0);
597 cksum = (~cksum & 0xFF);
599 redboot_getc_terminate(true);
600 diag_printf("*** Warning! Checksum failure - Addr: %lx, %02lX <> %02lX\n",
601 (unsigned long)base_addr, sum, cksum);
604 if ((unsigned long)(addr-addr_offset) > highest_address) {
605 highest_address = (unsigned long)(addr - addr_offset);
611 addr = (unsigned char *)_hex2(getc, ('9'-type+2), &sum);
612 offset += ('9'-type+2);
613 // Save load base/top, entry address
616 load_address_end = base + (highest_address - lowest_address);
617 entry_address = (unsigned long)(base + (addr - lowest_address));
619 load_address = lowest_address;
620 load_address_end = highest_address;
621 entry_address = (unsigned long)addr;
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);
628 return load_address_end;
630 redboot_getc_terminate(true);
631 diag_printf("Invalid S-record at offset 0x%lx, type: %x\n",
632 (unsigned long)offset, type);
635 while ((c = (*getc)()) != '\n') offset++;
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']
650 do_load(int argc, char *argv[])
652 int res, num_options;
654 bool verbose, raw, swap16bit;
655 bool base_addr_set, mode_str_set;
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
664 bool decompress = false;
666 #if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
669 unsigned long base = 0;
670 unsigned long end = 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;
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;
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");
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");
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");
709 init_opts(&opts[num_options], 'p', true, OPTION_ARG_TYPE_NUM,
710 (void *)&port, (bool *)&port_set, "TCP port");
713 #ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
714 init_opts(&opts[num_options], 'd', false, OPTION_ARG_TYPE_FLG,
715 (void *)&decompress, 0, "decompress");
719 CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options");
721 if (!scan_opts(argc, argv, 1, opts, num_options,
722 (void *)&filename, OPTION_ARG_TYPE_STR, "file name")) {
725 #ifdef CYGPKG_REDBOOT_NETWORKING
728 if (!_gethostbyname(hostname, (in_addr_t *)&host)) {
729 diag_printf("Invalid host: %s\n", hostname);
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));
740 host.sin_port = port;
742 if (chan >= CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) {
743 diag_printf("Invalid I/O channel: %d\n", chan);
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) {
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);
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);
773 io_tab = (struct load_io_entry *)NULL; // Default
774 #ifdef CYGPKG_REDBOOT_NETWORKING
775 #ifdef CYGSEM_REDBOOT_NET_TFTP_DOWNLOAD
778 #elif defined(CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD)
783 #ifdef CYGPKG_REDBOOT_FILEIO
784 // Make file I/O default if mounted
785 if (fileio_mounted) {
791 #ifdef CYGBLD_BUILD_REDBOOT_WITH_XYZMODEM
796 diag_printf("No default protocol!\n");
800 diag_printf("Using default protocol (%s)\n", which);
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))
809 if (raw && !base_addr_set) {
810 diag_printf("Raw load requires a memory address\n");
813 info.filename = filename;
815 info.mode = io_tab ? io_tab->mode : 0;
816 #ifdef CYGPKG_REDBOOT_NETWORKING
819 res = redboot_getc_init(&info, io, verbose, decompress);
824 // Stream open, process the data
826 unsigned char *mp = (unsigned char *)base;
827 unsigned char *addr_swap;
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
835 redboot_getc_terminate(true);
836 diag_printf("*** Abort! RAW data spills over limit of user RAM at %p\n",(void*)mp);
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)*/
845 // addr is even, have to write char data to the last address
846 if(((unsigned long)mp)%2){
850 // addr is odd, have to write char data to the next address
861 end = (unsigned long) mp;
863 // Save load base/top
865 load_address_end = end;
866 entry_address = base; // best guess
868 redboot_getc_terminate(false);
870 diag_printf("Raw file loaded %p-%p, assumed entry at %p\n",
871 (void *)base, (void *)(end - 1), (void*)base);
873 // Read initial header - to determine file [image] type
874 for (i = 0; i < sizeof(type); i++) {
875 if ((res = redboot_getc()) < 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) {
886 end = load_elf_image(redboot_getc, base, true);
889 end = load_elf_image(redboot_getc, base, false);
891 } else if ((type[0] == 'S') &&
892 ((type[1] >= '0') && (type[1] <= '9'))) {
894 end = load_srec_image(redboot_getc, base, true);
897 end = load_srec_image(redboot_getc, base, false);
900 redboot_getc_terminate(true);
901 diag_printf("Unrecognized image type: 0x%lx\n", *(unsigned long *)type);
906 redboot_getc_close(); // Clean up