📄 load.c
字号:
load_address_end = base + (highest_address - lowest_address); entry_address = base + (ehdr.e_entry - lowest_address); } else { load_address = lowest_address; load_address_end = highest_address; entry_address = ehdr.e_entry; } redboot_getc_terminate(false); if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset); diag_printf("Entry point: %p, address range: %p-%p\n", (void*)entry_address, (void *)load_address, (void *)load_address_end); return 1;#else // CYGSEM_REDBOOT_ELF diag_printf("Loading ELF images not supported\n"); return 0;#endif // CYGSEM_REDBOOT_ELF}//// Scan a string of hex bytes and update the checksum//static long_hex2(int (*getc)(void), int len, long *sum){ int val, byte; char c1, c2; val = 0; while (len-- > 0) { c1 = (*getc)(); c2 = (*getc)(); if (_is_hex(c1) && _is_hex(c2)) { val <<= 8; byte = (_from_hex(c1)<<4) | _from_hex(c2); val |= byte; if (sum) { *sum += byte; } } else { return (-1); } } return (val);}//// Process a set of S-records, loading the contents into memory. // Note: if a "base" value is provided, the data will be relocated// relative to that location. Of course, this can only work for// the first section of the data, so if there are non-contiguous// pieces of data, they will end up relocated in the same fashion.// Because of this, "base" probably only makes sense for a set of// data which has only one section, e.g. a ROM image.//static unsigned longload_srec_image(getc_t getc, unsigned long base){ int c; long offset = 0, count, sum, val, cksum; unsigned char *addr, *base_addr; char type; bool first_addr = true; unsigned long addr_offset = 0; unsigned long highest_address = 0; unsigned long lowest_address = 0xFFFFFFFF; while ((c = (*getc)()) > 0) { // Start of line if (c != 'S') { redboot_getc_terminate(true); diag_printf("Invalid S-record at offset %p, input: %c\n", (void *)offset, c); return 0; } type = (*getc)(); offset += 2; sum = 0; if ((count = _hex2(getc, 1, &sum)) < 0) { redboot_getc_terminate(true); diag_printf("Bad S-record count at offset %p\n", (void *)offset); return 0; } offset += 1; switch (type) { case '0': break; case '1': case '2': case '3': base_addr = addr = (unsigned char *)_hex2(getc, (type-'1'+2), &sum); offset += (type-'1'+2); if (first_addr) { if (base) { addr_offset = (unsigned long)base - (unsigned long)addr; } else { addr_offset = 0; } first_addr = false; } addr += addr_offset; if ((unsigned long)(addr-addr_offset) < lowest_address) { lowest_address = (unsigned long)(addr - addr_offset); }#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (!valid_address(addr)) { // Only if there is no need to stop the download before printing // output can we ask confirmation questions. redboot_getc_terminate(true); diag_printf("*** Abort! Attempt to load S-record to address: %p, which is not in RAM\n",(void*)addr); return 0; }#endif count -= ((type-'1'+2)+1); offset += count; while (count-- > 0) { val = _hex2(getc, 1, &sum); *addr++ = val; } cksum = _hex2(getc, 1, 0); offset += 1; sum = sum & 0xFF; cksum = (~cksum & 0xFF); if (cksum != sum) { redboot_getc_terminate(true); diag_printf("*** Warning! Checksum failure - Addr: %lx, %02lX <> %02lX\n", (unsigned long)base_addr, sum, cksum); return 0; } if ((unsigned long)(addr-addr_offset) > highest_address) { highest_address = (unsigned long)(addr - addr_offset); } break; case '7': case '8': case '9': addr = (unsigned char *)_hex2(getc, ('9'-type+2), &sum); offset += ('9'-type+2); // Save load base/top, entry address if (base) { load_address = base; load_address_end = base + (highest_address - lowest_address); entry_address = (unsigned long)(base + (addr - lowest_address)); } else { load_address = lowest_address; load_address_end = highest_address; entry_address = (unsigned long)addr; } redboot_getc_terminate(false); if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset); diag_printf("Entry point: %p, address range: %p-%p\n", (void*)entry_address, (void *)load_address, (void *)load_address_end); return load_address_end; default: redboot_getc_terminate(true); diag_printf("Invalid S-record at offset 0x%lx, type: %x\n", (unsigned long)offset, type); return 0; } while ((c = (*getc)()) != '\n') offset++; } return 0;}//// 'load' CLI command processing// -b - specify a load [base] address// -m - specify an I/O stream/method// -c - Alternate serial I/O channel#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB// -d - Decompress data [packed via 'zlib']#endif//void do_load(int argc, char *argv[]){ int res, num_options; int i, err; bool verbose, raw; bool base_addr_set, mode_str_set; char *mode_str;#ifdef CYGPKG_REDBOOT_NETWORKING struct sockaddr_in host; bool hostname_set, port_set; char *hostname;#endif bool decompress = false; int chan = -1;#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1 bool chan_set;#endif unsigned long base = 0; unsigned long end = 0; char type[4]; char *filename = 0; struct option_info opts[8]; connection_info_t info; getc_io_funcs_t *io = NULL; struct load_io_entry *io_tab; unsigned int port; //int because it's an OPTION_ARG_TYPE_NUM, but will be cast to short#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS bool spillover_ok = false;#endif#ifdef CYGPKG_REDBOOT_NETWORKING memset((char *)&host, 0, sizeof(host)); host.sin_len = sizeof(host); host.sin_family = AF_INET; host.sin_addr = my_bootp_info.bp_siaddr; host.sin_port = 0;#endif init_opts(&opts[0], 'v', false, OPTION_ARG_TYPE_FLG, (void *)&verbose, 0, "verbose"); init_opts(&opts[1], 'r', false, OPTION_ARG_TYPE_FLG, (void *)&raw, 0, "load raw data"); init_opts(&opts[2], 'b', true, OPTION_ARG_TYPE_NUM, (void *)&base, (bool *)&base_addr_set, "load address"); init_opts(&opts[3], 'm', true, OPTION_ARG_TYPE_STR, (void *)&mode_str, (bool *)&mode_str_set, "download mode (TFTP, xyzMODEM, or disk)"); num_options = 4;#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1 init_opts(&opts[num_options], 'c', true, OPTION_ARG_TYPE_NUM, (void *)&chan, (bool *)&chan_set, "I/O channel"); num_options++;#endif#ifdef CYGPKG_REDBOOT_NETWORKING init_opts(&opts[num_options], 'h', true, OPTION_ARG_TYPE_STR, (void *)&hostname, (bool *)&hostname_set, "host name or IP address"); num_options++; init_opts(&opts[num_options], 'p', true, OPTION_ARG_TYPE_NUM, (void *)&port, (bool *)&port_set, "TCP port"); num_options++;#endif#ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB init_opts(&opts[num_options], 'd', false, OPTION_ARG_TYPE_FLG, (void *)&decompress, 0, "decompress"); num_options++;#endif CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options"); if (!scan_opts(argc, argv, 1, opts, num_options, (void *)&filename, OPTION_ARG_TYPE_STR, "file name")) { return; }#ifdef CYGPKG_REDBOOT_NETWORKING if (hostname_set) { ip_route_t rt; if (!_gethostbyname(hostname, (in_addr_t *)&host)) { diag_printf("Invalid host: %s\n", hostname); return; } /* check that the host can be accessed */ if (__arp_lookup((ip_addr_t *)&host.sin_addr, &rt) < 0) { diag_printf("Unable to reach host %s (%s)\n", hostname, inet_ntoa((in_addr_t *)&host)); return; } } if (port_set) host.sin_port = port;#endif if (chan >= CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) { diag_printf("Invalid I/O channel: %d\n", chan); return; } if (mode_str_set) { for (io_tab = __RedBoot_LOAD_TAB__; io_tab != &__RedBoot_LOAD_TAB_END__; io_tab++) { if (strncasecmp(&mode_str[0], io_tab->name, strlen(&mode_str[0])) == 0) { io = io_tab->funcs; break; } } if (!io) { diag_printf("Invalid 'mode': %s. Valid modes are:", mode_str); for (io_tab = __RedBoot_LOAD_TAB__; io_tab != &__RedBoot_LOAD_TAB_END__; io_tab++) { diag_printf(" %s", io_tab->name); } diag_printf("\n"); } if (!io) { return; } verbose &= io_tab->can_verbose; if (io_tab->need_filename && !filename) { diag_printf("File name required\n"); diag_printf("usage: load %s\n", usage); return; } } else { char *which; io_tab = (struct load_io_entry *)NULL; // Default#ifdef CYGPKG_REDBOOT_NETWORKING#ifdef CYGSEM_REDBOOT_NET_TFTP_DOWNLOAD which = "TFTP"; io = &tftp_io;#elif defined(CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD) which = "HTTP"; io = &http_io;#endif#endif#ifdef CYGPKG_REDBOOT_FILEIO // Make file I/O default if mounted if (fileio_mounted) { which = "file"; io = &fileio_io; }#endif if (!io) {#ifdef CYGBLD_BUILD_REDBOOT_WITH_XYZMODEM which = "Xmodem"; io = &xyzModem_io; verbose = false;#else diag_printf("No default protocol!\n"); return;#endif } diag_printf("Using default protocol (%s)\n", which); }#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (base_addr_set && !valid_address((unsigned char *)base)) { if (!verify_action("Specified address (%p) is not believed to be in RAM", (void*)base)) return; spillover_ok = true; }#endif if (raw && !base_addr_set) { diag_printf("Raw load requires a memory address\n"); return; } info.filename = filename; info.chan = chan; info.mode = io_tab ? io_tab->mode : 0;#ifdef CYGPKG_REDBOOT_NETWORKING info.server = &host;#endif res = redboot_getc_init(&info, io, verbose, decompress); if (res < 0) { return; } // Stream open, process the data if (raw) { unsigned char *mp = (unsigned char *)base; err = 0; while ((res = redboot_getc()) >= 0) {#ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (!valid_address(mp) && !spillover_ok) { // Only if there is no need to stop the download // before printing output can we ask confirmation // questions. redboot_getc_terminate(true); diag_printf("*** Abort! RAW data spills over limit of user RAM at %p\n",(void*)mp); err = -1; break; }#endif *mp++ = res; } end = (unsigned long) mp; // Save load base/top load_address = base; load_address_end = end; entry_address = base; // best guess redboot_getc_terminate(false); if (0 == err) diag_printf("Raw file loaded %p-%p, assumed entry at %p\n", (void *)base, (void *)(end - 1), (void*)base); } else { // Read initial header - to determine file [image] type for (i = 0; i < sizeof(type); i++) { if ((res = redboot_getc()) < 0) { err = getc_info.err; break; } type[i] = res; } if (res >= 0) { redboot_getc_rewind(); // Restore header to stream // Treat data as some sort of executable image if (strncmp(&type[1], "ELF", 3) == 0) { end = load_elf_image(redboot_getc, base); } else if ((type[0] == 'S') && ((type[1] >= '0') && (type[1] <= '9'))) { end = load_srec_image(redboot_getc, base); } else { redboot_getc_terminate(true); diag_printf("Unrecognized image type: 0x%lx\n", *(unsigned long *)type); } } } redboot_getc_close(); // Clean up return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -