void fis_update_directory(void) { int stat; void *err_addr; fis_endian_fixup(fis_work_block); #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG memcpy((char *)fis_work_block+fisdir_size, config, cfg_size); conf_endian_fixup((char *)fis_work_block+fisdir_size); #endif #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL // Ensure [quietly] that the directory is unlocked before trying to update flash_unlock((void *)fis_addr, flash_block_size, (void **)&err_addr); #endif if ((stat = flash_erase(fis_addr, flash_block_size, (void **)&err_addr)) != 0) { diag_printf("Error erasing FIS directory at %p: %s\n", err_addr, flash_errmsg(stat)); } else { if ((stat = FLASH_PROGRAM(fis_addr, fis_work_block, flash_block_size, (void **)&err_addr)) != 0) { diag_printf("Error writing FIS directory at %p: %s\n", err_addr, flash_errmsg(stat)); } } #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL // Ensure [quietly] that the directory is locked after the update flash_lock((void *)fis_addr, flash_block_size, (void **)&err_addr); #endif fis_endian_fixup(fis_work_block); }
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; }
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; }
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(); } }
static int eCosBoard_erase(struct ecosflash_flash_bank *info, uint32_t address, uint32_t len) { int retval; int timeout = (len / 20480 + 1) * 1000; /*asume 20 KB/s*/ retval = loadDriver(info); if (retval != ERROR_OK) return retval; uint32_t flashErr; retval = runCode(info, info->start_address + OFFSET_ERASE, info->start_address + OFFSET_ERASE + OFFSET_ERASE_SIZE, address, len, 0, &flashErr, timeout ); if (retval != ERROR_OK) return retval; if (flashErr != 0x0) { LOG_ERROR("Flash erase failed with %d (%s)", (int)flashErr, flash_errmsg(flashErr)); return ERROR_FAIL; } return ERROR_OK; }
static void fis_update_directory(void) { int stat; void *err_addr; #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG memcpy((char *)fis_work_block+fisdir_size, config, cfg_size); #endif #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL // Ensure [quietly] that the directory is unlocked before trying to update flash_unlock((void *)fis_addr, flash_block_size, (void **)&err_addr); #endif if ((stat = fis_flash_erase(fis_addr, flash_block_size, (void **)&err_addr)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Error erasing FIS directory at %p: %s\n\r", err_addr, flash_errmsg(stat)); } else { if ((stat = fis_flash_program(fis_addr, fis_work_block, flash_block_size, (void **)&err_addr)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Error writing FIS directory at %p: %s\n\r", err_addr, flash_errmsg(stat)); } } #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL // Ensure [quietly] that the directory is locked after the update flash_lock((void *)fis_addr, flash_block_size, (void **)&err_addr); #endif }
int eCosBoard_flash(ecosflash_flash_bank_t *info, void *data, u32 address, u32 len) { target_t *target=info->target; const int chunk=8192; int retval=ERROR_OK; int timeout = (chunk / 20480 + 1) * 1000; /*asume 20 KB/s + 1 second*/ retval=loadDriver(info); if (retval!=ERROR_OK) return retval; u32 buffer; retval=runCode(info, info->start_address+OFFSET_GET_WORKAREA, info->start_address+OFFSET_GET_WORKAREA+OFFSET_GET_WORKAREA_SIZE, 0, 0, 0, &buffer, 1000); if (retval!=ERROR_OK) return retval; int i; for (i=0; i<len; i+=chunk) { int t=len-i; if (t>chunk) { t=chunk; } int retval; retval=target_write_buffer(target, buffer, t, ((u8 *)data)+i); if (retval != ERROR_OK) return retval; u32 flashErr; retval=runCode(info, info->start_address+OFFSET_FLASH, info->start_address+OFFSET_FLASH+OFFSET_FLASH_SIZE, buffer, address+i, t, &flashErr, timeout); if (retval != ERROR_OK) return retval; if (flashErr != 0x0) { LOG_ERROR("Flash prog failed with %d (%s)\n", flashErr, flash_errmsg(flashErr)); return ERROR_FAIL; } } return ERROR_OK; }
// // 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 } }
static bool do_flash_init(void) { int stat; ram_start = (unsigned char *)CYGMEM_REGION_ram; ram_end = (unsigned char *)(CYGMEM_REGION_ram+CYGMEM_REGION_ram_SIZE); #ifdef CYGMEM_SECTION_heap1 workspace_start = (unsigned char *)CYGMEM_SECTION_heap1; workspace_end = (unsigned char *)(CYGMEM_SECTION_heap1+CYGMEM_SECTION_heap1_SIZE); workspace_size = CYGMEM_SECTION_heap1_SIZE; #endif if (!__flash_init) { if ((stat = flash_init((void *)(workspace_end-FLASH_MIN_WORKSPACE), FLASH_MIN_WORKSPACE, (_printf *)fisPrintf)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "FLASH: driver init failed: %s\n\r", flash_errmsg(stat)); return false; } flash_get_limits((void *)0, (void **)&flash_start, (void **)&flash_end); // Keep 'end' address as last valid location, to avoid wrap around problems flash_end = (void *)((CYG_ADDRESS)flash_end - 1); flash_get_block_info(&flash_block_size, &flash_num_blocks); workspace_end = (unsigned char *)(workspace_end-FLASH_MIN_WORKSPACE); #ifdef CYGOPT_REDBOOT_FIS #ifdef CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER fis_work_block = fis_zlib_common_buffer; if(CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE < flash_block_size) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "FLASH: common buffer too small\n\r"); workspace_end += FLASH_MIN_WORKSPACE; return false; } #else workspace_end = (unsigned char *)(workspace_end-flash_block_size); fis_work_block = workspace_end; #endif fisdir_size = flash_block_size; if (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK < 0) { fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 + (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size)); } else { fis_addr = (void *)((CYG_ADDRESS)flash_start + (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size)); } #endif __flash_init = 1; } return true; }
// Program the current page into flash. void flash_load_finish(void) { cyg_uint32 retcode = FLASH_ERR_OK; void * err_addr; if (init_done && flash_page_init) { flash_page_init = false; retcode = flash_erase(current_flash_page, flash_block_size, &err_addr); if (retcode != FLASH_ERR_OK){ diag_printf("Error erase at %p: %s\n", err_addr, flash_errmsg(retcode)); } else { retcode = flash_program(current_flash_page, flash_buffer, flash_block_size, &err_addr); if (retcode != FLASH_ERR_OK){ diag_printf("Error writing at %p: %s\n", err_addr, flash_errmsg(retcode)); } } } flash_init(diag_printf); }
// Write a byte into flash. We maintain a copy in RAM of the FLASH // page we are currently "writing" into. This copy is loaded with the // current contents of the FLASH page when the first byte is "written" // to the page. The "writes" are then made into the RAM copy. We only // write to FLASH when there is a "write" outside of the current page, // or the flash_load_finish function is called. void flash_load_write(cyg_uint8 *flash_addr, cyg_uint8 value) { cyg_uint32 retcode = FLASH_ERR_OK; void * err_addr; cyg_uint32 addr = (cyg_uint32)flash_addr; cyg_uint32 offset; if (!flash_page_init) { /* First Byte for the current flash block. Read the current contents */ current_flash_page = flash_block_begin(addr); flash_read(flash_buffer, current_flash_page, flash_block_size, &err_addr); flash_page_init = true; } if (flash_block_begin(addr) != current_flash_page) { /* We have moved into the next flash page. Write the current page so we can move on */ retcode = flash_erase(current_flash_page, flash_block_size, &err_addr); if (retcode != FLASH_ERR_OK){ /* Flash ERROR */ diag_printf("Error erase at %p: %s\n", err_addr, flash_errmsg(retcode)); return; } retcode = flash_program(current_flash_page, flash_buffer, flash_block_size, &err_addr); if (retcode != FLASH_ERR_OK){ diag_printf("Error writing at %p: %s\n", err_addr, flash_errmsg(retcode)); return; } current_flash_page = flash_block_begin(addr); flash_read(flash_buffer, current_flash_page, flash_block_size, &err_addr); } offset = flash_addr - current_flash_page; CYG_ASSERT(offset < flash_block_size, "offset not inside flash block"); flash_buffer[offset] = value; }
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)); } }
bool do_flash_init(void) { int stat; if (!__flash_init) { __flash_init = 1; if ((stat = flash_init(diag_printf)) != 0) { diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat)); return false; } flash_get_limits((void *)0, (void **)&flash_start, (void **)&flash_end); // Keep 'end' address as last valid location, to avoid wrap around problems flash_end = (void *)((CYG_ADDRESS)flash_end - 1); flash_get_block_info(&flash_block_size, &flash_num_blocks); #ifdef CYGOPT_REDBOOT_FIS fisdir_size = CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_COUNT * CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_SIZE; fisdir_size = ((fisdir_size + flash_block_size - 1) / flash_block_size) * flash_block_size; # if defined(CYGPRI_REDBOOT_ZLIB_FLASH) && defined(CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER) fis_work_block = fis_zlib_common_buffer; if(CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE < fisdir_size) { diag_printf("FLASH: common buffer too small\n"); return false; } # else workspace_end = (unsigned char *)(workspace_end-fisdir_size); fis_work_block = workspace_end; # endif if (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK < 0) { fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 + (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size)); } else { fis_addr = (void *)((CYG_ADDRESS)flash_start + (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size)); } if (((CYG_ADDRESS)fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) { diag_printf("FIS directory doesn't fit\n"); return false; } fis_read_directory(); #endif } return true; }
void _show_invalid_flash_address(CYG_ADDRESS flash_addr, int stat) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Invalid FLASH address %p: %s\n\r", (void *)flash_addr, flash_errmsg(stat)); SYS_DEBUG(SYSDEBUG_TRACE_FIS, " valid range is %p-%p\n\r", (void *)flash_start, (void *)flash_end); }
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(); }
HRESULT fis_delete_progress(char *name, FIS_PROGRESS_FUNC progressFunc) { int num_reserved, i, stat; void *err_addr; struct fis_image_desc *img; FIS_PROGRESS_STRUCT progress; memset (&progress,0,sizeof(progress)); 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 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG num_reserved++; #endif num_reserved++; memcpy(fis_work_block, fis_addr, fisdir_size); img = fis_lookup(name, &i); if (img) { if (i < num_reserved) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Sorry, '%s' is a reserved image and cannot be deleted\n\r", img->name); return E_FIS_ILLEGAL_IMAGE; } } else { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "No image '%s' found\n\r", name); return E_FIS_ILLEGAL_IMAGE; } if (progressFunc) { progress.func = progressFunc; progress.procur = 0; progress.promax = fis_flash_erase_progressinfo (img->size); progress.promax += 10; //to update the directory progressFunc(progress.promax, progress.procur); } // Erase Data blocks (free space) if ((stat = fis_flash_erase_progress((void *)img->flash_base, img->size, (void **)&err_addr, &progress)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "Error erasing at %p: %s\n\r", err_addr, flash_errmsg(stat)); return E_FIS_FLASH_OP_FAILED; } else { img->name[0] = (unsigned char)0xFF; fis_update_directory(); } progressFunc(progress.promax, progress.promax); return NO_ERROR; }
static void _show_invalid_flash_address(CYG_ADDRESS flash_addr, int stat) { diag_printf("Invalid FLASH address %p: %s\n", (void *)flash_addr, flash_errmsg(stat)); diag_printf(" valid range is %p-%p\n", (void *)flash_start, (void *)flash_end); }
HRESULT fis_init(void) { int stat; struct fis_image_desc *img; void *err_addr; bool full_init = true; CYG_ADDRESS redboot_flash_start; unsigned long redboot_image_size; SYS_DEBUG(SYSDEBUG_TRACE_FIS, "*** Initialize FLASH Image System\n\r"); #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; SYS_DEBUG(SYSDEBUG_TRACE_FIS, "redboot_flash_start = %x.\n\r", redboot_flash_start); #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 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG // 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++; // 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 = fis_flash_erase((void *)erase_start, erase_size, (void **)&err_addr)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, " initialization failed at %p: %s\n\r", err_addr, flash_errmsg(stat)); } } #endif //zluo, hack if(redboot_flash_start < 0x4020000) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, "redboot_flash_start = %p\n\r", redboot_flash_start); return NO_ERROR; } // 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(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 = fis_flash_erase((void *)erase_start, erase_size, (void **)&err_addr)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, " initialization failed %p: %s\n\r", 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 = fis_flash_erase((void *)erase_start, erase_size, (void **)&err_addr)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, " initialization failed %p: %s\n\r", 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 = fis_flash_erase((void *)erase_start, erase_size, (void **)&err_addr)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, " initialization failed %p: %s\n\r", err_addr, flash_errmsg(stat)); } erase_start += (erase_size + flash_block_size); #endif // Lastly, anything at the end erase_size = ((CYG_ADDRESS)flash_end - erase_start) + 1; if ((stat = fis_flash_erase((void *)erase_start, erase_size, (void **)&err_addr)) != 0) { SYS_DEBUG(SYSDEBUG_TRACE_FIS, " initialization failed at %p: %s\n\r", err_addr, flash_errmsg(stat)); } } else { SYS_DEBUG(SYSDEBUG_TRACE_FIS, " Warning: device contents not erased, some blocks may not be usable\n\r"); } fis_update_directory(); return NO_ERROR; }
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; } } }
externC void cyg_start( void ) { int stat; void *err_addr; CYG_ADDRWORD flash_start, flash_end; void **flash_start_addr = (void *)&flash_start; void **flash_end_addr = (void *)&flash_end; void *flash_test_start, *flash_addr; cyg_int32 flash_block_size, flash_num_blocks; CYG_ADDRWORD test_buf1, test_buf2; cyg_uint32 *lp1, *lp2; int i, len; cyg_bool passed, ok; CYG_TEST_INIT(); #if 0 int j; diag_printf("Testing udelay: "); for (i = 0; i < 30; i++) { for (j = 0; j < 1000; j++) { CYGACC_CALL_IF_DELAY_US(1000); // Should be 1 second } diag_printf("."); } diag_printf("\n"); #endif passed = true; if ((stat = flash_init(diag_printf)) != 0) { diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat)); CYG_TEST_FAIL_FINISH("FLASH driver init failed"); } flash_get_limits((void *)0, flash_start_addr, flash_end_addr); // Keep 'end' address as last valid location, to avoid wrap around problems flash_end = flash_end - 1; flash_get_block_info(&flash_block_size, &flash_num_blocks); diag_printf("FLASH: 0x%x - 0x%x, %d blocks of 0x%x bytes each.\n", flash_start, flash_end + 1, flash_num_blocks, flash_block_size); // Verify that the testing limits are within the bounds of the // physical device. Also verify that the size matches with // the erase block size on the device if ((CYGNUM_IO_FLASH_TEST_OFFSET > (flash_end - flash_start)) || ((CYGNUM_IO_FLASH_TEST_OFFSET + CYGNUM_IO_FLASH_TEST_LENGTH) > (flash_end - flash_start))) { CYG_TEST_FAIL_FINISH("FLASH test region outside physical limits"); } if ((CYGNUM_IO_FLASH_TEST_LENGTH % flash_block_size) != 0) { CYG_TEST_FAIL_FINISH("FLASH test region must be integral multiple of erase block size"); } // Allocate two buffers large enough for the test test_buf1 = (CYG_ADDRWORD)CYGMEM_SECTION_heap1; test_buf2 = test_buf1 + CYGNUM_IO_FLASH_TEST_LENGTH; if (CYGMEM_SECTION_heap1_SIZE < (CYGNUM_IO_FLASH_TEST_LENGTH * 2)) { CYG_TEST_FAIL_FINISH("FLASH not enough heap space - reduce size of test region"); } diag_printf("... Using test buffers at %p and %p\n", (void *)test_buf1, (void *)test_buf2); flash_test_start = (void *)(flash_start + CYGNUM_IO_FLASH_TEST_OFFSET); #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING // Unlock test diag_printf("... Unlock test\n"); ok = true; if ((stat = flash_unlock(flash_test_start, CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != CYG_FLASH_ERR_OK) { diag_printf("FLASH: unlock failed: %s\n", flash_errmsg(stat)); ok = false; } #endif // Erase test diag_printf("... Erase test\n"); ok = true; if ((stat = flash_erase(flash_test_start, CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != CYG_FLASH_ERR_OK) { diag_printf("FLASH: erase failed: %s\n", flash_errmsg(stat)); ok = false; } if (ok && (stat = flash_read(flash_test_start, (void *)test_buf1, CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != CYG_FLASH_ERR_OK) { diag_printf("FLASH: read/verify after erase failed: %s\n", flash_errmsg(stat)); ok = false; } lp1 = (cyg_uint32 *)test_buf1; for (i = 0; i < CYGNUM_IO_FLASH_TEST_LENGTH; i += sizeof(cyg_uint32)) { if (*lp1++ != 0xFFFFFFFF) { diag_printf("FLASH: non-erased data found at offset %x\n", (CYG_ADDRWORD)(lp1-1) - test_buf1); diag_dump_buf((void *)(lp1-1), 32); ok = false; break; } } // Try reading in little pieces len = CYGNUM_IO_FLASH_TEST_LENGTH; flash_addr = flash_test_start; while (len > 0) { if ((stat = flash_read(flash_addr, (void *)test_buf1, 0x200, &err_addr)) != CYG_FLASH_ERR_OK) { diag_printf("FLASH: read[short]/verify after erase failed: %s\n", flash_errmsg(stat)); ok = false; break; } flash_addr = (cyg_uint8 *)flash_addr + 0x200; len -= 0x200; lp1 = (cyg_uint32 *)test_buf1; for (i = 0; i < 0x200; i += sizeof(cyg_uint32)) { if (*lp1++ != 0xFFFFFFFF) { diag_printf("FLASH: non-erased data found at offset %p\n", (cyg_uint8 *)flash_addr + (CYG_ADDRWORD)((lp1-1) - test_buf1)); diag_dump_buf((void *)(lp1-1), 32); ok = false; len = 0; break; } } } if (!ok) { CYG_TEST_INFO("FLASH erase failed"); passed = false; } // Simple write/verify test diag_printf("... Write/verify test\n"); lp1 = (cyg_uint32 *)test_buf1; for (i = 0; i < CYGNUM_IO_FLASH_TEST_LENGTH; i += sizeof(cyg_uint32)) { *lp1 = (cyg_uint32)lp1; lp1++; } ok = true; if (ok && (stat = flash_program(flash_test_start, (void *)test_buf1, CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != CYG_FLASH_ERR_OK) { diag_printf("FLASH: write failed: %s\n", flash_errmsg(stat)); ok = false; } if (ok && (stat = flash_read(flash_test_start, (void *)test_buf2, CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != CYG_FLASH_ERR_OK) { diag_printf("FLASH: read/verify after write failed: %s\n", flash_errmsg(stat)); ok = false; } lp1 = (cyg_uint32 *)test_buf1; lp2 = (cyg_uint32 *)test_buf2; for (i = 0; i < CYGNUM_IO_FLASH_TEST_LENGTH; i += sizeof(cyg_uint32)) { if (*lp2++ != *lp1++) { diag_printf("FLASH: incorrect data found at offset %x\n", (CYG_ADDRWORD)(lp2-1) - test_buf2); diag_dump_buf((void *)(lp2-1), 32); ok = false; break; } } // Try reading in little pieces len = CYGNUM_IO_FLASH_TEST_LENGTH; flash_addr = flash_test_start; lp1 = (cyg_uint32 *)test_buf1; lp2 = (cyg_uint32 *)test_buf2; while (len > 0) { if ((stat = flash_read(flash_addr, lp2, 0x200, &err_addr)) != CYG_FLASH_ERR_OK) { diag_printf("FLASH: read[short]/verify after erase failed: %s\n", flash_errmsg(stat)); ok = false; break; } flash_addr = (cyg_uint8 *)flash_addr + 0x200; len -= 0x200; for (i = 0; i < 0x200; i += sizeof(cyg_uint32)) { if (*lp2++ != *lp1++) { diag_printf("FLASH: incorrect data found at offset %p\n", (cyg_uint8 *)flash_addr + (CYG_ADDRWORD)((lp2-1) - test_buf2)); diag_dump_buf((void *)(lp2-1), 32); ok = false; len = 0; break; } } } if (!ok) { CYG_TEST_INFO("FLASH write/verify failed"); } #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING // Lock test diag_printf("... Lock test\n"); ok = true; if ((stat = flash_lock(flash_test_start, CYGNUM_IO_FLASH_TEST_LENGTH, &err_addr)) != CYG_FLASH_ERR_OK) { diag_printf("FLASH: unlock failed: %s\n", flash_errmsg(stat)); ok = false; } #endif if (passed) { CYG_TEST_PASS_FINISH("FLASH test1"); } else { CYG_TEST_FAIL_FINISH("FLASH test1"); } }