HRESULT fis_erase(CYG_ADDRESS flash_addr, unsigned long length) { int stat; void *err_addr; if (((stat = flash_verify_addr((void *)flash_addr)) || (stat = flash_verify_addr((void *)(flash_addr+length-1))))) { _show_invalid_flash_address(flash_addr, stat); return NO_ERROR; } if (flash_addr & (flash_block_size-1)) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Invalid FLASH address: %p\n\r", (void *)flash_addr); SYS_DEBUG(SYSDEBUG_TRACE_FIS, " must be 0x%x aligned\n\r", flash_block_size); return NO_ERROR; } // Safety check - make sure the address range is not within the code we're running if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Can't erase this region - contains code in use!\n\r"); return NO_ERROR; } if ((stat = fis_flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Error erasing at %p: %s\n\r", err_addr, flash_errmsg(stat)); } return NO_ERROR; }
HRESULT fis_write(CYG_ADDRESS mem_addr, uint32 length, CYG_ADDRESS flash_addr) { int stat; void *err_addr; bool prog_ok; SYS_DEBUG(SYSDEBUG_TRACE_FIS, "fis_write(%x, %x, %x)\n\r", mem_addr, length, flash_addr); // Round up length to FLASH block size if (((stat = flash_verify_addr((void *)flash_addr)) || (stat = flash_verify_addr((void *)(flash_addr+length-1))))) { _show_invalid_flash_address(flash_addr, stat); return NO_ERROR; } if (flash_addr & (flash_block_size-1)) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Invalid FLASH address: %p\n\r", (void *)flash_addr); SYS_DEBUG(SYSDEBUG_TRACE_FIS, " must be 0x%x aligned\n\r", flash_block_size); return NO_ERROR; } if ((mem_addr < (CYG_ADDRESS)ram_start) || ((mem_addr+length) >= (CYG_ADDRESS)ram_end)) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "** WARNING: RAM address: %p may be invalid\n\r", (void *)mem_addr); SYS_DEBUG(SYSDEBUG_TRACE_FIS, " valid range is %p-%p\n\r", (void *)ram_start, (void *)ram_end); } // Safety check - make sure the address range is not within the code we're running if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Can't program this region - contains code in use!\n\r"); return NO_ERROR; } prog_ok = true; if (prog_ok) { // Erase area to be programmed if ((stat = fis_flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Can't erase region at %p: %s\n\r", err_addr, flash_errmsg(stat)); prog_ok = false; } } if (prog_ok) { // Now program it if ((stat = fis_flash_program((void *)flash_addr, (void *)mem_addr, length, (void **)&err_addr)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "fis_write: can't program region at %p: %s\n\r", err_addr, flash_errmsg(stat)); //sysDebugPrintf("Can't program region at %p: %s\n\r", err_addr, stat); // prog_ok = false; } } return NO_ERROR; }
static void fis_unlock(int argc, char *argv[]) { char *name; int stat; unsigned long length; CYG_ADDRESS flash_addr; bool flash_addr_set = false; bool length_set = false; void *err_addr; struct option_info opts[2]; init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address"); init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, (void *)&length, (bool *)&length_set, "length"); if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name")) { fis_usage("invalid arguments"); return; } if (name) { struct fis_image_desc *img; if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) { diag_printf("No image '%s' found\n", name); return; } flash_addr = img->flash_base; length = img->size; } else if (!flash_addr_set || !length_set) { fis_usage("missing argument"); return; } if (flash_addr_set && ((stat = flash_verify_addr((void *)flash_addr)) || (stat = flash_verify_addr((void *)(flash_addr+length-1))))) { _show_invalid_flash_address(flash_addr, stat); return; } if ((stat = flash_unlock((void *)flash_addr, length, (void **)&err_addr)) != 0) { diag_printf("Error unlocking at %p: %s\n", err_addr, flash_errmsg(stat)); } }
static void fis_erase(int argc, char *argv[]) { int stat; unsigned long length; CYG_ADDRESS flash_addr; bool flash_addr_set = false; bool length_set = false; void *err_addr; struct option_info opts[2]; init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address"); init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, (void *)&length, (bool *)&length_set, "length"); if (!scan_opts(argc, argv, 2, opts, 2, (void **)0, 0, "")) { fis_usage("invalid arguments"); return; } if (!flash_addr_set || !length_set) { fis_usage("missing argument"); return; } if (flash_addr_set && ((stat = flash_verify_addr((void *)flash_addr)) || (stat = flash_verify_addr((void *)(flash_addr+length-1))))) { _show_invalid_flash_address(flash_addr, stat); return; } if (flash_addr_set && flash_addr & (flash_block_size-1)) { diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr); diag_printf(" must be 0x%x aligned\n", flash_block_size); return; } // Safety check - make sure the address range is not within the code we're running if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) { diag_printf("Can't erase this region - contains code in use!\n"); return; } if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) { diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat)); } }
static int flash_fis_op2( int op, unsigned int index, struct fis_table_entry *entry) { int res=0; CYGARC_HAL_SAVE_GP(); switch ( op ) { case CYGNUM_CALL_IF_FLASH_FIS_GET_VERSION: res=CYG_REDBOOT_FIS_VERSION; break; case CYGNUM_CALL_IF_FLASH_FIS_INIT: __flash_init=0; //force reinitialization res=do_flash_init(); break; case CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY_COUNT: res=fisdir_size / sizeof(struct fis_image_desc); break; case CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY: { struct fis_image_desc* img = (struct fis_image_desc *)fis_work_block; CYG_ASSERT(entry!=0, "fis_table_entry == 0 !"); memcpy(entry->name, img[index].u.name, 16); entry->flash_base=img[index].flash_base; entry->mem_base=img[index].mem_base; entry->size=img[index].size; entry->entry_point=img[index].entry_point; entry->data_length=img[index].data_length; entry->desc_cksum=img[index].desc_cksum; entry->file_cksum=img[index].file_cksum; res=0; } break; case CYGNUM_CALL_IF_FLASH_FIS_START_UPDATE: fis_start_update_directory(1); break; case CYGNUM_CALL_IF_FLASH_FIS_FINISH_UPDATE: fis_update_directory(1, index); break; case CYGNUM_CALL_IF_FLASH_FIS_MODIFY_ENTRY: { res=0; if (entry->name[0]!=0xff) { if ((entry->size==0) || ((entry->size % flash_block_size) !=0) || (flash_verify_addr((void*)entry->flash_base)!=0) || (flash_verify_addr((void*)(entry->flash_base+entry->size-1))!=0) || (entry->size < entry->data_length)) res=-1; } if (res==0) { struct fis_image_desc* img = (struct fis_image_desc *)fis_work_block; memcpy(img[index].u.name, entry->name, 16); img[index].flash_base=entry->flash_base; img[index].mem_base=entry->mem_base; img[index].size=entry->size; img[index].entry_point=entry->entry_point; img[index].data_length=entry->data_length; img[index].desc_cksum=entry->desc_cksum; img[index].file_cksum=entry->file_cksum; } } break; default: break; } CYGARC_HAL_RESTORE_GP(); return res; }
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; unsigned int port; // int because it's an OPTION_ARG_TYPE_NUM, // but will be cast to short char *hostname; #endif #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH bool flash_addr_set = false; #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[9]; connection_info_t info; getc_io_funcs_t *io = NULL; struct load_io_entry *io_tab; #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 #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH init_opts(&opts[num_options], 'f', true, OPTION_ARG_TYPE_NUM, (void *)&base, (bool *)&flash_addr_set, "flash address"); 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)) { err_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) { err_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) { err_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); } err_printf("\n"); } if (!io) { return; } verbose &= io_tab->can_verbose; if (io_tab->need_filename && !filename) { diag_printf("File name required\n"); err_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 #if 0 //def 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 err_printf("No default protocol!\n"); return; #endif } diag_printf("Using default protocol (%s)\n", which); } #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH if (flash_addr_set && flash_verify_addr((unsigned char *)base)) { if (!verify_action("Specified address (%p) is not believed to be in FLASH", (void*)base)) return; spillover_ok = true; } #endif 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 #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH || flash_addr_set #endif )) { err_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; } #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH flash_load_start(); #endif // 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 #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH if (flash_addr_set && flash_verify_addr(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); err_printf("*** Abort! RAW data spills over limit of FLASH at %p\n",(void*)mp); err = -1; break; } #endif if (base_addr_set && !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); err_printf("*** Abort! RAW data spills over limit of user RAM at %p\n",(void*)mp); err = -1; break; } #endif #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH if (flash_addr_set) { flash_load_write(mp, res); mp++; res++; } else #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); err_printf("Unrecognized image type: 0x%lx\n", *(unsigned long *)type); } } } #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH flash_load_finish(); #endif redboot_getc_close(); // Clean up return; }
// // 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 long load_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); err_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); err_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) #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH || (flash_verify_addr(addr) == FLASH_ERR_OK) #endif )) { // Only if there is no need to stop the download before printing // output can we ask confirmation questions. redboot_getc_terminate(true); err_printf("*** Abort! Attempt to load S-record to address: %p, which is not valid\n",(void*)addr); return 0; } #endif count -= ((type-'1'+2)+1); offset += count; while (count-- > 0) { val = _hex2(getc, 1, &sum); if (valid_address(addr)) { *addr++ = val; } #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH else { flash_load_write(addr, val); addr++; } #endif } cksum = _hex2(getc, 1, 0); offset += 1; sum = sum & 0xFF; cksum = (~cksum & 0xFF); if (cksum != sum) { redboot_getc_terminate(true); err_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); err_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 an ELF [binary] image // static unsigned long load_elf_image(getc_t getc, unsigned long base) { #ifdef CYGSEM_REDBOOT_ELF Elf32_Ehdr ehdr; #define MAX_PHDR 8 Elf32_Phdr phdr[MAX_PHDR]; unsigned long offset = 0; int phx, len, ch; unsigned char *addr; unsigned long addr_offset = 0; unsigned long highest_address = 0; unsigned long lowest_address = 0xFFFFFFFF; unsigned char *SHORT_DATA = "Short data reading ELF file\n"; // Read the header if (_read(getc, (unsigned char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr)) { err_printf("Can't read ELF header\n"); redboot_getc_terminate(true); return 0; } offset += sizeof(ehdr); #if 0 // DEBUG diag_printf("Type: %d, Machine: %d, Version: %d, Entry: %p, PHoff: %p/%d/%d, SHoff: %p/%d/%d\n", ehdr.e_type, ehdr.e_machine, ehdr.e_version, ehdr.e_entry, ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_phnum, ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shnum); #endif if (ehdr.e_type != ET_EXEC) { err_printf("Only absolute ELF images supported\n"); redboot_getc_terminate(true); return 0; } if (ehdr.e_phnum > MAX_PHDR) { err_printf("Too many program headers\n"); redboot_getc_terminate(true); return 0; } while (offset < ehdr.e_phoff) { if ((*getc)() < 0) { err_printf(SHORT_DATA); redboot_getc_terminate(true); return 0; } offset++; } for (phx = 0; phx < ehdr.e_phnum; phx++) { if (_read(getc, (unsigned char *)&phdr[phx], sizeof(phdr[0])) != sizeof(phdr[0])) { err_printf("Can't read ELF program header\n"); redboot_getc_terminate(true); return 0; } #if 0 // DEBUG diag_printf("Program header: type: %d, off: %p, va: %p, pa: %p, len: %d/%d, flags: %d\n", phdr[phx].p_type, phdr[phx].p_offset, phdr[phx].p_vaddr, phdr[phx].p_paddr, phdr[phx].p_filesz, phdr[phx].p_memsz, phdr[phx].p_flags); #endif offset += sizeof(phdr[0]); } if (base) { // Set address offset based on lowest address in file. addr_offset = 0xFFFFFFFF; for (phx = 0; phx < ehdr.e_phnum; phx++) { #ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_vaddr < addr_offset)) { addr_offset = phdr[phx].p_vaddr; #else if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_paddr < addr_offset)) { addr_offset = phdr[phx].p_paddr; #endif } } addr_offset = (unsigned long)base - addr_offset; } else { addr_offset = 0; } for (phx = 0; phx < ehdr.e_phnum; phx++) { if (phdr[phx].p_type == PT_LOAD) { // Loadable segment #ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS addr = (unsigned char *)phdr[phx].p_vaddr; #else addr = (unsigned char *)phdr[phx].p_paddr; #endif len = phdr[phx].p_filesz; if ((unsigned long)addr < lowest_address) { lowest_address = (unsigned long)addr; } addr += addr_offset; if (offset > phdr[phx].p_offset) { if ((phdr[phx].p_offset + len) < offset) { err_printf("Can't load ELF file - program headers out of order\n"); redboot_getc_terminate(true); return 0; } addr += offset - phdr[phx].p_offset; } else { while (offset < phdr[phx].p_offset) { if ((*getc)() < 0) { err_printf(SHORT_DATA); redboot_getc_terminate(true); return 0; } offset++; } } // Copy data into memory while (len-- > 0) { #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (!(valid_address(addr) #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH || (flash_verify_addr(addr) == FLASH_ERR_OK) #endif )) { redboot_getc_terminate(true); err_printf("*** Abort! Attempt to load ELF data to address: %p which is not valid\n", (void*)addr); return 0; } #endif if ((ch = (*getc)()) < 0) { err_printf(SHORT_DATA); redboot_getc_terminate(true); return 0; } if (valid_address(addr)) { *addr++ = ch; } #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH else { flash_load_write(addr, ch); addr++; } #endif offset++; if ((unsigned long)(addr-addr_offset) > highest_address) { highest_address = (unsigned long)(addr - addr_offset); } } } } // Save load base/top and entry if (base) { load_address = base; 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; } // nak everything to stop the transfer, since redboot // usually doesn't read all the way to the end of the // elf files. redboot_getc_terminate(true); 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 err_printf("Loading ELF images not supported\n"); return 0; #endif // CYGSEM_REDBOOT_ELF }
static void fis_create(int argc, char *argv[]) { int i, stat; unsigned long length, img_size; CYG_ADDRESS mem_addr, exec_addr, flash_addr, entry_addr; char *name; bool mem_addr_set = false; bool exec_addr_set = false; bool entry_addr_set = false; bool flash_addr_set = false; bool length_set = false; bool img_size_set = false; bool no_copy = false; void *err_addr; struct fis_image_desc *img = NULL; bool defaults_assumed; struct option_info opts[7]; bool prog_ok = true; init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, (void *)&mem_addr, (bool *)&mem_addr_set, "memory base address"); init_opts(&opts[1], 'r', true, OPTION_ARG_TYPE_NUM, (void *)&exec_addr, (bool *)&exec_addr_set, "ram base address"); init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM, (void *)&entry_addr, (bool *)&entry_addr_set, "entry point address"); init_opts(&opts[3], 'f', true, OPTION_ARG_TYPE_NUM, (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address"); init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM, (void *)&length, (bool *)&length_set, "image length [in FLASH]"); init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM, (void *)&img_size, (bool *)&img_size_set, "image size [actual data]"); init_opts(&opts[6], 'n', false, OPTION_ARG_TYPE_FLG, (void *)&no_copy, (bool *)0, "don't copy from RAM to FLASH, just update directory"); if (!scan_opts(argc, argv, 2, opts, 7, (void *)&name, OPTION_ARG_TYPE_STR, "file name")) { fis_usage("invalid arguments"); return; } fis_read_directory(); defaults_assumed = false; if (name) { // Search existing files to acquire defaults for params not specified: img = fis_lookup(name, NULL); if (img) { // Found it, so get image size from there if (!length_set) { length_set = true; length = img->size; defaults_assumed = true; } } } if (!mem_addr_set && (load_address >= (CYG_ADDRESS)ram_start) && (load_address_end) < (CYG_ADDRESS)ram_end) { mem_addr = load_address; mem_addr_set = true; defaults_assumed = true; // Get entry address from loader, unless overridden if (!entry_addr_set) entry_addr = entry_address; if (!length_set) { length = load_address_end - load_address; length_set = true; } else if (defaults_assumed && !img_size_set) { /* We got length from the FIS table, so the size of the actual loaded image becomes img_size */ img_size = load_address_end - load_address; img_size_set = true; } } // Get the remaining fall-back values from the fis if (img) { if (!exec_addr_set) { // Preserve "normal" behaviour exec_addr_set = true; exec_addr = flash_addr_set ? flash_addr : mem_addr; } if (!flash_addr_set) { flash_addr_set = true; flash_addr = img->flash_base; defaults_assumed = true; } } if ((!no_copy && !mem_addr_set) || (no_copy && !flash_addr_set) || !length_set || !name) { fis_usage("required parameter missing"); return; } if (!img_size_set) { img_size = length; } // 'length' is size of FLASH image, 'img_size' is actual data size // Round up length to FLASH block size #ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size; if (length < img_size) { diag_printf("Invalid FLASH image size/length combination\n"); return; } #endif if (flash_addr_set && ((stat = flash_verify_addr((void *)flash_addr)) || (stat = flash_verify_addr((void *)(flash_addr+length-1))))) { _show_invalid_flash_address(flash_addr, stat); return; } if (flash_addr_set && ((flash_addr & (flash_block_size-1)) != 0)) { diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr); diag_printf(" must be 0x%x aligned\n", flash_block_size); return; } if (strlen(name) >= sizeof(img->name)) { diag_printf("Name is too long, must be less than %d chars\n", (int)sizeof(img->name)); return; } if (!no_copy) { if ((mem_addr < (CYG_ADDRESS)ram_start) || ((mem_addr+img_size) >= (CYG_ADDRESS)ram_end)) { diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr); diag_printf(" valid range is %p-%p\n", (void *)ram_start, (void *)ram_end); } if (!flash_addr_set && !fis_find_free(&flash_addr, length)) { diag_printf("Can't locate %lx(%ld) bytes free in FLASH\n", length, length); return; } } // First, see if the image by this name has agreable properties if (img) { if (flash_addr_set && (img->flash_base != flash_addr)) { diag_printf("Image found, but flash address (%p)\n" " is incorrect (present image location %p)\n", flash_addr, img->flash_base); return; } if (img->size != length) { diag_printf("Image found, but length (0x%lx, necessitating image size 0x%lx)\n" " is incorrect (present image size 0x%lx)\n", img_size, length, img->size); return; } if (!verify_action("An image named '%s' exists", name)) { return; } else { if (defaults_assumed) { if (no_copy && !verify_action("* CAUTION * about to program '%s'\n at %p..%p from %p", name, (void *)flash_addr, (void *)(flash_addr+img_size-1), (void *)mem_addr)) { return; // The guy gave up } } } } else { #ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS // Make sure that any FLASH address specified directly is truly free if (flash_addr_set && !no_copy) { struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS]; int idx, num_chunks; bool is_free = false; num_chunks = find_free(chunks); for (idx = 0; idx < num_chunks; idx++) { if ((flash_addr >= chunks[idx].start) && ((flash_addr+length-1) <= chunks[idx].end)) { is_free = true; } } if (!is_free) { diag_printf("Invalid FLASH address - not free!\n"); return; } } #endif // If not image by that name, try and find an empty slot img = (struct fis_image_desc *)fis_work_block; for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) { if (img->name[0] == (unsigned char)0xFF) { break; } } } if (!no_copy) { // Safety check - make sure the address range is not within the code we're running if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+img_size-1))) { diag_printf("Can't program this region - contains code in use!\n"); return; } if (prog_ok) { // Erase area to be programmed if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) { diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat)); prog_ok = false; } } if (prog_ok) { // Now program it if ((stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, img_size, (void **)&err_addr)) != 0) { diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat)); prog_ok = false; } } } if (prog_ok) { // Update directory memset(img, 0, sizeof(*img)); strcpy(img->name, name); img->flash_base = flash_addr; img->mem_base = exec_addr_set ? exec_addr : (flash_addr_set ? flash_addr : mem_addr); img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address; // Hope it's been set img->size = length; img->data_length = img_size; #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK if (!no_copy) { img->file_cksum = cyg_crc32((unsigned char *)mem_addr, img_size); } else { // No way to compute this, sorry img->file_cksum = 0; } #endif fis_update_directory(); } }
static void fis_write(int argc, char *argv[]) { int stat; unsigned long length; CYG_ADDRESS mem_addr, flash_addr; bool mem_addr_set = false; bool flash_addr_set = false; bool length_set = false; void *err_addr; struct option_info opts[3]; bool prog_ok; init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, (void *)&mem_addr, (bool *)&mem_addr_set, "memory base address"); init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM, (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address"); init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM, (void *)&length, (bool *)&length_set, "image length [in FLASH]"); if (!scan_opts(argc, argv, 2, opts, 3, 0, 0, 0)) { fis_usage("invalid arguments"); return; } if (!mem_addr_set || !flash_addr_set || !length_set) { fis_usage("required parameter missing"); return; } // Round up length to FLASH block size #ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size; #endif if (flash_addr_set && ((stat = flash_verify_addr((void *)flash_addr)) || (stat = flash_verify_addr((void *)(flash_addr+length-1))))) { _show_invalid_flash_address(flash_addr, stat); return; } if (flash_addr_set && flash_addr & (flash_block_size-1)) { diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr); diag_printf(" must be 0x%x aligned\n", flash_block_size); return; } if ((mem_addr < (CYG_ADDRESS)ram_start) || ((mem_addr+length) >= (CYG_ADDRESS)ram_end)) { diag_printf("** WARNING: RAM address: %p may be invalid\n", (void *)mem_addr); diag_printf(" valid range is %p-%p\n", (void *)ram_start, (void *)ram_end); } // Safety check - make sure the address range is not within the code we're running if (flash_code_overlaps((void *)flash_addr, (void *)(flash_addr+length-1))) { diag_printf("Can't program this region - contains code in use!\n"); return; } if (!verify_action("* CAUTION * about to program FLASH\n at %p..%p from %p", (void *)flash_addr, (void *)(flash_addr+length-1), (void *)mem_addr)) { return; // The guy gave up } prog_ok = true; if (prog_ok) { // Erase area to be programmed if ((stat = flash_erase((void *)flash_addr, length, (void **)&err_addr)) != 0) { diag_printf("Can't erase region at %p: %s\n", err_addr, flash_errmsg(stat)); prog_ok = false; } } if (prog_ok) { // Now program it if ((stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, length, (void **)&err_addr)) != 0) { diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat)); prog_ok = false; } } }
HRESULT fis_create_progress(CYG_ADDRESS mem_addr, uint32 length, CYG_ADDRESS exec_addr, CYG_ADDRESS entry_addr, char *name, BOOL bDeleteIfNeeded, FIS_PROGRESS_FUNC progressFunc) { int stat, i; unsigned long img_size; CYG_ADDRESS flash_addr; void *err_addr; struct fis_image_desc *img = NULL; BOOL bFlashAddrGood = FALSE; BOOL bDelOldImage = FALSE; FIS_PROGRESS_STRUCT progress; memset (&progress,0,sizeof(progress)); memcpy(fis_work_block, fis_addr, fisdir_size); img_size = length; // 'length' is size of FLASH image, 'img_size' is actual data size // Round up length to FLASH block size length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size; if (length < img_size) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Internal error in image\n\r"); return E_FIS_ILLEGAL_IMAGE; } if (!name) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Internal error in image\n\r"); return E_FIS_ILLEGAL_IMAGE; } if (strlen(name) >= sizeof(img->name)) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Internal error in image\n\r"); return E_FIS_ILLEGAL_IMAGE; } // Search existing files to acquire defaults for params not specified: img = fis_lookup(name, NULL); // If we have an image we need to check if it is any good if (img) { if (length != img->size) { //in this case we either return an error or delete the old image if (!bDeleteIfNeeded) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Image already exist with different size\n\r"); return E_FIS_ILLEGAL_IMAGE; } //We need to remember to delete the image bDelOldImage = TRUE; SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Delete old image\n\r"); } else { bFlashAddrGood = TRUE; SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Reuse old image\n\r"); } } else { //need to find a new free image img = (struct fis_image_desc *)fis_work_block; for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) { if (img->name[0] == (unsigned char)0xFF) break; } if (img->name[0] != (unsigned char)0xFF) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "No more directory entries\n\r"); return E_FIS_NO_SPACE; } SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Using new image\n\r"); } //we definitely have an img pointer which is valid //Let's figure out the work we need to do for the progress info if (progressFunc) { progress.func = progressFunc; progress.procur = 0; progress.promax = fis_flash_program_progressinfo(img_size); if (bDelOldImage || bFlashAddrGood) progress.promax += fis_flash_erase_progressinfo (img->size); if (!bFlashAddrGood) progress.promax += fis_flash_erase_progressinfo (length); progress.promax += 10; //to update the directory progressFunc(progress.promax, progress.procur); } if (bDelOldImage || bFlashAddrGood) { if ((stat = fis_flash_erase_progress((void *)img->flash_base, img->size, &err_addr, &progress )) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Flash Erase failed\n\r"); return E_FIS_FLASH_OP_FAILED; } } if (!bFlashAddrGood) { //we need to find space if (!fis_find_free(&flash_addr, length)) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "No free space in flash\n\r"); return E_FIS_NO_SPACE; } } else { flash_addr = img->flash_base; } //at this point we have erased old stuff if needed and we are ready to program if (((stat = flash_verify_addr((void *)flash_addr)) || (stat = flash_verify_addr((void *)(flash_addr+img_size-1))))) { //this should not happen, it is an internal error SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Internal error, illegal flash address\n\r"); return E_FIS_FLASH_OP_FAILED; } if (flash_addr & (flash_block_size-1)) { //this should not happen, it is an internal error SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Internal error, illegal flash address\n\r"); return E_FIS_FLASH_OP_FAILED; } // We need to erase the new are we found but it is likely clean so we will not progress it // as it will only be a blank check if (!bFlashAddrGood) { if ((stat = fis_flash_erase_progress((void *)img->flash_base, img->size, &err_addr, &progress)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Flash erase failed\n\r"); return E_FIS_FLASH_OP_FAILED; } } if (mem_addr!=0xffffffff) //ML:Create image without programming if addr=0xffffffff { // Now program it if ((stat = fis_flash_program_progress((void *)flash_addr, (void *)mem_addr, img_size, &err_addr,&progress)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Flash program failed\n\r"); return E_FIS_FLASH_OP_FAILED; } } // Update directory memset(img, 0, sizeof(*img)); strcpy(img->name, name); img->flash_base = flash_addr; img->mem_base = exec_addr; img->entry_point = entry_addr; // Hope it's been set img->size = length; img->data_length = img_size; #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK img->file_cksum = cyg_crc32((unsigned char *)flash_addr, img_size); #endif fis_update_directory(); if (progressFunc) progressFunc(progress.promax, progress.promax); return NO_ERROR; }