static void fis_delete(int argc, char *argv[]) { char *name; int num_reserved, i, stat; void *err_addr; struct fis_image_desc *img; if (!scan_opts(argc, argv, 2, 0, 0, (void *)&name, OPTION_ARG_TYPE_STR, "image name")) { fis_usage("invalid arguments"); return; } #ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB // FIXME: this is somewhat half-baked arm_fis_delete(name); return; #endif img = (struct fis_image_desc *)fis_work_block; num_reserved = 0; #ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE num_reserved++; #endif #ifdef CYGOPT_REDBOOT_FIS_REDBOOT num_reserved++; #endif #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP num_reserved++; #endif #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_POST num_reserved++; #endif #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH) num_reserved++; #endif #if 1 // And the descriptor for the descriptor table itself num_reserved++; #endif img = fis_lookup(name, &i); if (img) { if (i < num_reserved) { diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->name); return; } if (!verify_action("Delete image '%s'", name)) { return; } } else { diag_printf("No image '%s' found\n", name); return; } // Erase Data blocks (free space) if ((stat = flash_erase((void *)img->flash_base, img->size, (void **)&err_addr)) != 0) { diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat)); } else { img->name[0] = (unsigned char)0xFF; fis_update_directory(); } }
// // Write the in-memory copy of the configuration data to the flash device. // void flash_write_config(bool prompt) { #if defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH) void *err_addr; #if !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG) int stat; #endif #endif config->len = sizeof(struct _config); config->key1 = CONFIG_KEY1; config->key2 = CONFIG_KEY2; config->cksum = flash_crc(config); if (!prompt || verify_action("Update RedBoot non-volatile configuration")) { #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG fis_read_directory(); fis_update_directory(); #else #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL // Insure [quietly] that the config page is unlocked before trying to update flash_unlock((void *)cfg_base, cfg_size, (void **)&err_addr); #endif if ((stat = flash_erase(cfg_base, cfg_size, (void **)&err_addr)) != 0) { diag_printf(" initialization failed at %p: %s\n", err_addr, flash_errmsg(stat)); } else { conf_endian_fixup(config); if ((stat = FLASH_PROGRAM(cfg_base, config, sizeof(struct _config), (void **)&err_addr)) != 0) { diag_printf("Error writing config data at %p: %s\n", err_addr, flash_errmsg(stat)); } conf_endian_fixup(config); } #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL // Insure [quietly] that the config data is locked after the update flash_lock((void *)cfg_base, cfg_size, (void **)&err_addr); #endif #endif // CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG #else // CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH write_eeprom(config, sizeof(struct _config)); // into 'config' #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; 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; }
static void do_flash_config(int argc, char *argv[]) { bool need_update = false; struct config_option *optend = __CONFIG_options_TAB_END__; struct config_option *opt = __CONFIG_options_TAB__; struct option_info opts[5]; bool list_only; bool nicknames; bool fullnames; bool dumbterminal; int list_opt = 0; unsigned char *dp; int len, ret; char *title; char *onlyone = NULL; char *onevalue = NULL; bool doneone = false; bool init = false; #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH if (!__flash_init) { diag_printf("Sorry, no FLASH memory is available\n"); return; } #endif memcpy(backup_config, config, sizeof(struct _config)); script = (unsigned char *)0; init_opts(&opts[0], 'l', false, OPTION_ARG_TYPE_FLG, (void *)&list_only, (bool *)0, "list configuration only"); init_opts(&opts[1], 'n', false, OPTION_ARG_TYPE_FLG, (void *)&nicknames, (bool *)0, "show nicknames"); init_opts(&opts[2], 'f', false, OPTION_ARG_TYPE_FLG, (void *)&fullnames, (bool *)0, "show full names"); init_opts(&opts[3], 'i', false, OPTION_ARG_TYPE_FLG, (void *)&init, (bool *)0, "initialize configuration database"); init_opts(&opts[4], 'd', false, OPTION_ARG_TYPE_FLG, (void *)&dumbterminal, (bool *)0, "dumb terminal: no clever edits"); // First look to see if we are setting or getting a single option // by just quoting its nickname if ( (2 == argc && '-' != argv[1][0]) || (3 == argc && '-' != argv[1][0] && '-' != argv[2][0])) { // then the command was "fconfig foo [value]" onlyone = argv[1]; onevalue = (3 == argc) ? argv[2] : NULL; list_opt = LIST_OPT_NICKNAMES; } // Next see if we are setting or getting a single option with a dumb // terminal invoked, ie. no line editing. else if (3 == argc && '-' == argv[1][0] && 'd' == argv[1][1] && 0 == argv[1][2] && '-' != argv[2][0]) { // then the command was "fconfig -d foo" onlyone = argv[2]; onevalue = NULL; list_opt = LIST_OPT_NICKNAMES | LIST_OPT_DUMBTERM; } else { if (!scan_opts(argc, argv, 1, opts, 5, 0, 0, "")) return; list_opt |= list_only ? LIST_OPT_LIST_ONLY : 0; list_opt |= nicknames ? LIST_OPT_NICKNAMES : LIST_OPT_FULLNAMES; list_opt |= fullnames ? LIST_OPT_FULLNAMES : 0; list_opt |= dumbterminal ? LIST_OPT_DUMBTERM : 0; } if (init && verify_action("Initialize non-volatile configuration")) { config_init(); need_update = true; } dp = &config->config_data[0]; while (dp < &config->config_data[sizeof(config->config_data)]) { if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) { break; } len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) + config_length(CONFIG_OBJECT_TYPE(dp)); // Provide a title for well known [i.e. builtin] objects title = (char *)NULL; opt = __CONFIG_options_TAB__; while (opt != optend) { if (strcmp(opt->key, CONFIG_OBJECT_KEY(dp)) == 0) { title = opt->title; break; } opt++; } if ( onlyone && 0 != strcmp(CONFIG_OBJECT_KEY(dp), onlyone) ) ret = CONFIG_OK; // skip this entry else { doneone = true; ret = get_config(dp, title, list_opt, onevalue); // do this opt } switch (ret) { case CONFIG_DONE: goto done; case CONFIG_ABORT: memcpy(config, backup_config, sizeof(struct _config)); return; case CONFIG_CHANGED: need_update = true; case CONFIG_OK: dp += len; break; case CONFIG_BACK: dp = &config->config_data[0]; continue; case CONFIG_BAD: // Nothing - make him do it again diag_printf ("** invalid entry\n"); onevalue = NULL; // request a good value be typed in - or abort/whatever } } done: if (NULL != onlyone && !doneone) { #ifdef CYGSEM_REDBOOT_ALLOW_DYNAMIC_FLASH_CONFIG_DATA if (verify_action("** entry '%s' not found - add", onlyone)) { struct config_option opt; diag_printf("Trying to add value\n"); } #else diag_printf("** entry '%s' not found\n", onlyone); #endif } if (!need_update) return; flash_write_config(true); }
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_init(int argc, char *argv[]) { int stat; struct fis_image_desc *img; void *err_addr; bool full_init = false; struct option_info opts[1]; CYG_ADDRESS redboot_flash_start; unsigned long redboot_image_size; init_opts(&opts[0], 'f', false, OPTION_ARG_TYPE_FLG, (void *)&full_init, (bool *)0, "full initialization, erases all of flash"); if (!scan_opts(argc, argv, 2, opts, 1, 0, 0, "")) { return; } if (!verify_action("About to initialize [format] FLASH image system")) { diag_printf("** Aborted\n"); return; } diag_printf("*** Initialize FLASH Image System\n"); #define MIN_REDBOOT_IMAGE_SIZE CYGBLD_REDBOOT_MIN_IMAGE_SIZE redboot_image_size = flash_block_size > MIN_REDBOOT_IMAGE_SIZE ? flash_block_size : MIN_REDBOOT_IMAGE_SIZE; // Create a pseudo image for RedBoot img = (struct fis_image_desc *)fis_work_block; memset(img, 0xFF, fisdir_size); // Start with erased data #ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE memset(img, 0, sizeof(*img)); strcpy(img->name, "(reserved)"); img->flash_base = (CYG_ADDRESS)flash_start; img->mem_base = (CYG_ADDRESS)flash_start; img->size = CYGNUM_REDBOOT_FLASH_RESERVED_BASE; img++; #endif redboot_flash_start = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET; #ifdef CYGOPT_REDBOOT_FIS_REDBOOT memset(img, 0, sizeof(*img)); strcpy(img->name, "RedBoot"); img->flash_base = redboot_flash_start; img->mem_base = redboot_flash_start; img->size = redboot_image_size; img++; redboot_flash_start += redboot_image_size; #endif #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_POST #ifdef CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET // Take care to place the POST entry at the right offset: redboot_flash_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET; #endif memset(img, 0, sizeof(*img)); strcpy(img->name, "RedBoot[post]"); img->flash_base = redboot_flash_start; img->mem_base = redboot_flash_start; img->size = redboot_image_size; img++; redboot_flash_start += redboot_image_size; #endif #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP // And a backup image memset(img, 0, sizeof(*img)); strcpy(img->name, "RedBoot[backup]"); img->flash_base = redboot_flash_start; img->mem_base = redboot_flash_start; img->size = redboot_image_size; img++; redboot_flash_start += redboot_image_size; #endif #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH) // And a descriptor for the configuration data memset(img, 0, sizeof(*img)); strcpy(img->name, "RedBoot config"); img->flash_base = (CYG_ADDRESS)cfg_base; img->mem_base = (CYG_ADDRESS)cfg_base; img->size = cfg_size; img++; #endif // And a descriptor for the descriptor table itself memset(img, 0, sizeof(*img)); strcpy(img->name, "FIS directory"); img->flash_base = (CYG_ADDRESS)fis_addr; img->mem_base = (CYG_ADDRESS)fis_addr; img->size = fisdir_size; img++; #ifdef CYGOPT_REDBOOT_FIS_DIRECTORY_ARM_SIB_ID // FIS gets the size of a full block - note, this should be changed // if support is added for multi-block FIS structures. img = (struct fis_image_desc *)((CYG_ADDRESS)fis_work_block + fisdir_size); // Add a footer so the FIS will be recognized by the ARM Boot // Monitor as a reserved area. { tFooter* footer_p = (tFooter*)((CYG_ADDRESS)img - sizeof(tFooter)); cyg_uint32 check = 0; cyg_uint32 *check_ptr = (cyg_uint32 *)footer_p; cyg_int32 count = (sizeof(tFooter) - 4) >> 2; // Prepare footer. Try to protect all but the reserved space // and the first RedBoot image (which is expected to be // bootable), but fall back to just protecting the FIS if it's // not at the default position in the flash. #if defined(CYGOPT_REDBOOT_FIS_RESERVED_BASE) && (-1 == CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK) footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(flash_start); footer_p->blockBase += CYGNUM_REDBOOT_FLASH_RESERVED_BASE + redboot_image_size; #else footer_p->blockBase = (char*)_ADDR_REDBOOT_TO_ARM(fis_work_block); #endif footer_p->infoBase = NULL; footer_p->signature = FLASH_FOOTER_SIGNATURE; footer_p->type = TYPE_REDHAT_REDBOOT; // and compute its checksum for ( ; count > 0; count--) { if (*check_ptr > ~check) check++; check += *check_ptr++; } footer_p->checksum = ~check; } #endif // Do this after creating the initialized table because that inherently // calculates where the high water mark of default RedBoot images is. if (full_init) { unsigned long erase_size; CYG_ADDRESS erase_start; // Erase everything except default RedBoot images, fis block, // and config block. // First deal with the possible first part, before RedBoot images: #if (CYGBLD_REDBOOT_FLASH_BOOT_OFFSET > CYGNUM_REDBOOT_FLASH_RESERVED_BASE) erase_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FLASH_RESERVED_BASE; erase_size = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET; if ( erase_size > erase_start ) { erase_size -= erase_start; if ((stat = flash_erase((void *)erase_start, erase_size, (void **)&err_addr)) != 0) { diag_printf(" initialization failed at %p: %s\n", err_addr, flash_errmsg(stat)); } } #endif // second deal with the larger part in the main: erase_start = redboot_flash_start; // high water of created images // Now the empty bits between the end of Redboot and the cfg and dir // blocks. #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && \ defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH) && \ !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG) if (fis_addr > cfg_base) { erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between HWM and config data } else { erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data } if ((stat = flash_erase((void *)erase_start, erase_size, (void **)&err_addr)) != 0) { diag_printf(" initialization failed %p: %s\n", err_addr, flash_errmsg(stat)); } erase_start += (erase_size + flash_block_size); if (fis_addr > cfg_base) { erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between config and fis data } else { erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between fis and config data } if ((stat = flash_erase((void *)erase_start, erase_size, (void **)&err_addr)) != 0) { diag_printf(" initialization failed %p: %s\n", err_addr, flash_errmsg(stat)); } erase_start += (erase_size + flash_block_size); #else // !CYGSEM_REDBOOT_FLASH_CONFIG erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data if ((stat = flash_erase((void *)erase_start, erase_size, (void **)&err_addr)) != 0) { diag_printf(" initialization failed %p: %s\n", err_addr, flash_errmsg(stat)); } erase_start += (erase_size + flash_block_size); #endif // Lastly, anything at the end, if there is any if ( erase_start < (((CYG_ADDRESS)flash_end)+1) ) { erase_size = ((CYG_ADDRESS)flash_end - erase_start) + 1; if ((stat = flash_erase((void *)erase_start, erase_size, (void **)&err_addr)) != 0) { diag_printf(" initialization failed at %p: %s\n", err_addr, flash_errmsg(stat)); } } #ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS // In this case, 'fis free' works by scanning for erased blocks. Since the // "-f" option was not supplied, there may be areas which are not used but // don't appear to be free since they are not erased - thus the warning } else { diag_printf(" Warning: device contents not erased, some blocks may not be usable\n"); #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; } } }