Mercurial > ecos
diff packages/redboot/current/src/flash.c @ 2631:13376f3cfc60 jifl-post-flashv2-merge-20081118
Merge flashv2 branch to trunk, with eCosCentric additions
| author | jlarmour |
|---|---|
| date | Tue, 18 Nov 2008 01:28:11 +0000 |
| parents | 82aabda670f8 |
| children | 74dbf4c3f2e1 |
line wrap: on
line diff
--- a/packages/redboot/current/src/flash.c +++ b/packages/redboot/current/src/flash.c @@ -8,6 +8,7 @@ //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2004, 2005, 2006, 2007, 2008 eCosCentric Limited // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. // Copyright (C) 2003, 2004 Gary Thomas // @@ -33,9 +34,6 @@ // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. -// -// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -// at http://sources.redhat.com/ecos/ecos-license/ // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== @@ -164,19 +162,20 @@ RedBoot_nested_cmd("fis", ); // Local data used by these routines -void *flash_start, *flash_end; -int flash_block_size, flash_num_blocks; +cyg_flashaddr_t flash_start, flash_end; +size_t flash_block_size; +cyg_uint32 flash_num_blocks; #ifdef CYGOPT_REDBOOT_FIS void *fis_work_block; -void *fis_addr; +cyg_flashaddr_t fis_addr; #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS void *redundant_fis_addr; #endif int fisdir_size; // Size of FIS directory. #endif #ifdef CYGSEM_REDBOOT_FLASH_CONFIG -extern void *cfg_base; // Location in Flash of config data -extern int cfg_size; // Length of config data - rounded to Flash block size +extern cyg_flashaddr_t cfg_base; // Location in Flash of config data +extern size_t cfg_size; // Length of config data - rounded to Flash block size extern struct _config *config; #endif @@ -190,8 +189,37 @@ fis_usage(char *why) 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); + cyg_uint32 i=0; + cyg_flash_info_t info; + int ret; + + diag_printf("Invalid FLASH address %p: %s\n", (void *)flash_addr, + cyg_flash_errmsg(stat)); + do { + ret = cyg_flash_get_info(i, &info); + if (ret == CYG_FLASH_ERR_OK) { + diag_printf(" valid range is %p - %p\n", (void*)info.start, (void*)info.end); + } + i++; + } while (ret != CYG_FLASH_ERR_INVALID); +} + +// Avoid overwriting the current executable. This is not a complete +// implementation, there may be code outside the text region, but it +// is generally good enough. If either the start of the text region or +// the end of the text region is within the specified range then at +// least some of the code is in the area of flash about to be erased +// or programmed. +static cyg_bool +check_code_overlaps(cyg_flashaddr_t start, cyg_flashaddr_t end) +{ + extern char _stext[], _etext[]; + + return ((((unsigned long)&_stext >= (unsigned long)start) && + ((unsigned long)&_stext < (unsigned long)end)) + || + (((unsigned long)&_etext >= (unsigned long)start) && + ((unsigned long)&_etext < (unsigned long)end))); } #ifdef CYGOPT_REDBOOT_FIS @@ -220,9 +248,9 @@ static inline void fis_endian_fixup(void void fis_read_directory(void) { - void *err_addr; + cyg_flashaddr_t err_addr; - FLASH_READ(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr); + cyg_flash_read(fis_addr, fis_work_block, fisdir_size, &err_addr); fis_endian_fixup(fis_work_block); } @@ -236,7 +264,7 @@ fis_lookup(char *name, int *num) img = (struct fis_image_desc *)fis_work_block; for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) { - if ((img->u.name[0] != (unsigned char)0xFF) && + if ((img->u.name[0] != '\xFF') && (strcasecmp(name, img->u.name) == 0)) { if (num) *num = i; return img; @@ -258,8 +286,9 @@ int fis_start_update_directory(int autol #endif struct fis_image_desc* img=NULL; - void* err_addr=NULL; - void* tmp_fis_addr=NULL; + cyg_flashaddr_t err_addr=NULL; + cyg_flashaddr_t tmp_fis_addr=NULL; + int stat; /*exchange old and new valid fis tables*/ tmp_fis_addr=fis_addr; @@ -277,13 +306,20 @@ int fis_start_update_directory(int autol //ready to go.... #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING if (do_autolock) - flash_unlock((void *)fis_addr, fisdir_size, (void **)&err_addr); + cyg_flash_unlock(fis_addr, fisdir_size, &err_addr); #endif - flash_erase(fis_addr, fisdir_size, (void **)&err_addr); + if ((stat = cyg_flash_erase(fis_addr, fisdir_size, &err_addr)) != 0) { + diag_printf("Error erasing FIS directory at %p: %s\n", err_addr, cyg_flash_errmsg(stat)); + return 1; + } //now magic is 0xffffffff fis_endian_fixup(fis_work_block); - flash_program(fis_addr, fis_work_block, flash_block_size, (void **)&err_addr); + if ((stat = cyg_flash_program(fis_addr, fis_work_block, flash_block_size, &err_addr)) != 0) { + diag_printf("Error writing FIS directory at %p: %s\n", + err_addr, cyg_flash_errmsg(stat)); + return 1; + } fis_endian_fixup(fis_work_block); //now magic is 0xff1234ff, valid is IN_PROGRESS, version_count is the old one +1 @@ -297,7 +333,8 @@ int fis_start_update_directory(int autol int fis_update_directory(int autolock, int error) { - void* err_addr=0; + cyg_flashaddr_t err_addr; + int stat; #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL @@ -334,7 +371,11 @@ fis_update_directory(int autolock, int e img->u.valid_info.valid_flag[0]=CYG_REDBOOT_RFIS_VALID; img->u.valid_info.valid_flag[1]=CYG_REDBOOT_RFIS_VALID; - flash_program(tmp_fis_addr, img->u.valid_info.valid_flag, sizeof(img->u.valid_info.valid_flag), (void **)&err_addr); + if ((stat = cyg_flash_program(tmp_fis_addr, img->u.valid_info.valid_flag, + sizeof(img->u.valid_info.valid_flag), &err_addr)) != 0) { + diag_printf("Error writing FIS directory at %p: %s\n", + err_addr, cyg_flash_errmsg(stat)); + } } #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING if (do_autolock) @@ -343,7 +384,6 @@ fis_update_directory(int autolock, int e #else // CYGOPT_REDBOOT_REDUNDANT_FIS int blk_size = fisdir_size; - int stat; fis_endian_fixup(fis_work_block); #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG @@ -353,22 +393,22 @@ fis_update_directory(int autolock, int e #endif #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING if (do_autolock) - flash_unlock((void *)fis_addr, blk_size, (void **)&err_addr); + cyg_flash_unlock(fis_addr, blk_size, &err_addr); #endif - if ((stat = flash_erase(fis_addr, blk_size, (void **)&err_addr)) != 0) { - diag_printf("Error erasing FIS directory at %p: %s\n", err_addr, flash_errmsg(stat)); + if ((stat = cyg_flash_erase(fis_addr, blk_size, &err_addr)) != 0) { + diag_printf("Error erasing FIS directory at %p: %s\n", (void*)err_addr, cyg_flash_errmsg(stat)); } else { - if ((stat = FLASH_PROGRAM(fis_addr, fis_work_block, - blk_size, (void **)&err_addr)) != 0) { + if ((stat = cyg_flash_program(fis_addr, fis_work_block, blk_size, + &err_addr)) != 0) { diag_printf("Error writing FIS directory at %p: %s\n", - err_addr, flash_errmsg(stat)); + (void*)err_addr, cyg_flash_errmsg(stat)); } } fis_endian_fixup(fis_work_block); #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING if (do_autolock) - flash_lock((void *)fis_addr, blk_size, (void **)&err_addr); + cyg_flash_lock(fis_addr, blk_size, &err_addr); #endif #endif // CYGOPT_REDBOOT_REDUNDANT_FIS @@ -428,17 +468,17 @@ fis_erase_redundant_directory(void) #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL // Ensure [quietly] that the directory is unlocked before trying // to update - flash_unlock((void *)redundant_fis_addr, fisdir_size, - (void **)&err_addr); + cyg_flash_unlock(redundant_fis_addr, fisdir_size, + &err_addr); #endif - if ((stat = flash_erase(redundant_fis_addr, fisdir_size, - (void **)&err_addr)) != 0) { + if ((stat = cyg_flash_erase(redundant_fis_addr, fisdir_size, + &err_addr)) != 0) { diag_printf("Error erasing FIS directory at %p: %s\n", - err_addr, flash_errmsg(stat)); + err_addr, cyg_flash_errmsg(stat)); } #ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL // Ensure [quietly] that the directory is locked after the update - flash_lock((void *)redundant_fis_addr, fisdir_size, (void **)&err_addr); + cyg_flash_lock(redundant_fis_addr, fisdir_size, &err_addr); #endif } #endif @@ -448,7 +488,7 @@ fis_init(int argc, char *argv[]) { int stat; struct fis_image_desc *img; - void *err_addr; + cyg_flashaddr_t err_addr; bool full_init = false; struct option_info opts[1]; CYG_ADDRESS redboot_flash_start; @@ -472,7 +512,7 @@ fis_init(int argc, char *argv[]) flash_block_size : MIN_REDBOOT_IMAGE_SIZE; img = (struct fis_image_desc *)fis_work_block; - memset(img, 0xFF, fisdir_size); // Start with erased data + memset(img, '\xFF', fisdir_size); // Start with erased data #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS //create the valid flag entry @@ -491,6 +531,7 @@ fis_init(int argc, char *argv[]) img->flash_base = (CYG_ADDRESS)flash_start; img->mem_base = (CYG_ADDRESS)flash_start; img->size = CYGNUM_REDBOOT_FLASH_RESERVED_BASE; + img->data_length = img->size; img++; #endif redboot_flash_start = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET; @@ -500,6 +541,7 @@ fis_init(int argc, char *argv[]) img->flash_base = redboot_flash_start; img->mem_base = redboot_flash_start; img->size = redboot_image_size; + img->data_length = img->size; img++; redboot_flash_start += redboot_image_size; #endif @@ -513,6 +555,7 @@ fis_init(int argc, char *argv[]) img->flash_base = redboot_flash_start; img->mem_base = redboot_flash_start; img->size = redboot_image_size; + img->data_length = img->size; img++; redboot_flash_start += redboot_image_size; #endif @@ -523,6 +566,7 @@ fis_init(int argc, char *argv[]) img->flash_base = redboot_flash_start; img->mem_base = redboot_flash_start; img->size = redboot_image_size; + img->data_length = img->size; img++; redboot_flash_start += redboot_image_size; #endif @@ -533,6 +577,7 @@ fis_init(int argc, char *argv[]) img->flash_base = (CYG_ADDRESS)cfg_base; img->mem_base = (CYG_ADDRESS)cfg_base; img->size = cfg_size; + img->data_length = img->size; img++; #endif // And a descriptor for the descriptor table itself @@ -541,6 +586,7 @@ fis_init(int argc, char *argv[]) img->flash_base = (CYG_ADDRESS)fis_addr; img->mem_base = (CYG_ADDRESS)fis_addr; img->size = fisdir_size; + img->data_length = img->size; img++; //create the entry for the redundant fis table @@ -603,10 +649,10 @@ fis_init(int argc, char *argv[]) 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) { + if ((stat = cyg_flash_erase((void *)erase_start, erase_size, + &err_addr)) != 0) { diag_printf(" initialization failed at %p: %s\n", - err_addr, flash_errmsg(stat)); + err_addr, cyg_flash_errmsg(stat)); } } #endif @@ -622,10 +668,9 @@ fis_init(int argc, char *argv[]) } 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) { + if ((stat = cyg_flash_erase(erase_start, erase_size,&err_addr)) != 0) { diag_printf(" initialization failed %p: %s\n", - err_addr, flash_errmsg(stat)); + err_addr, cyg_flash_errmsg(stat)); } erase_start += (erase_size + flash_block_size); if (fis_addr > cfg_base) { @@ -633,29 +678,26 @@ fis_init(int argc, char *argv[]) } 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) { + if ((stat = cyg_flash_erase(erase_start, erase_size,&err_addr)) != 0) { diag_printf(" initialization failed %p: %s\n", - err_addr, flash_errmsg(stat)); + err_addr, cyg_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) { + if ((stat = cyg_flash_erase(erase_start, erase_size,&err_addr)) != 0) { diag_printf(" initialization failed %p: %s\n", - err_addr, flash_errmsg(stat)); + (void*)err_addr, cyg_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)); - } + // Lastly, anything at the end + erase_size = ((CYG_ADDRESS)flash_end - erase_start) + 1; + if ((erase_size > 0) && + ((stat = cyg_flash_erase(erase_start, erase_size, + &err_addr))) != 0) { + diag_printf(" initialization failed at %p: %s\n", + (void*)err_addr, cyg_flash_errmsg(stat)); } #ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS // In this case, 'fis free' works by scanning for erased blocks. Since the @@ -718,7 +760,7 @@ fis_list(int argc, char *argv[]) lowest_addr = 0xFFFFFFFF; img = (struct fis_image_desc *) fis_work_block; for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) { - if (img->u.name[0] != (unsigned char)0xFF) { + if (img->u.name[0] != '\xFF') { if ((img->flash_base >= last_addr) && (img->flash_base < lowest_addr)) { lowest_addr = img->flash_base; image_found = true; @@ -744,6 +786,21 @@ fis_list(int argc, char *argv[]) } while (image_found == true); } +#ifdef CYGNUM_REDBOOT_FLASH_RESERVED_DEVICES +static CYG_ADDRESS flash_reserved_devices[] = { CYGNUM_REDBOOT_FLASH_RESERVED_DEVICES, 0xFFFFFFFF }; + +static cyg_bool flash_reserved( CYG_ADDRESS start ) +{ + int i; + for( i = 0; flash_reserved_devices[i] != 0xFFFFFFFF; i++ ) + if( start == flash_reserved_devices[i] ) + return true; + return false; +} +#else +#define flash_reserved(__start) false +#endif + #ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS struct free_chunk { CYG_ADDRESS start, end; @@ -752,21 +809,46 @@ struct free_chunk { static int find_free(struct free_chunk *chunks) { - CYG_ADDRESS *fis_ptr, *fis_end; + cyg_flash_info_t info; struct fis_image_desc *img; - int i, idx; - int num_chunks = 1; + int i=0, idx; + int num_chunks = 0; + int ret; + + do { + // get info for each flash device + ret = cyg_flash_get_info(i, &info); - // Do not search the area reserved for pre-RedBoot systems: - fis_ptr = (CYG_ADDRESS *)((CYG_ADDRESS)flash_start + - CYGNUM_REDBOOT_FLASH_RESERVED_BASE); - fis_end = (CYG_ADDRESS *)flash_end; - chunks[num_chunks-1].start = (CYG_ADDRESS)fis_ptr; - chunks[num_chunks-1].end = (CYG_ADDRESS)fis_end; + if (ret == CYG_FLASH_ERR_OK && !flash_reserved( info.start )) { + +#ifdef CYGNUM_REDBOOT_FLASH_BASE + if ( CYGNUM_REDBOOT_FLASH_BASE == info.start ) +#else + if (i == 0 ) +#endif + { + // Do not search the area reserved for pre-RedBoot systems: + chunks[num_chunks].start = (info.start + + CYGNUM_REDBOOT_FLASH_RESERVED_BASE); + chunks[num_chunks].end = info.end; + num_chunks++; + } else { // Contiguous flash? If so collapse the chunks together. + if (chunks[num_chunks-1].end == (info.start -1)) { + chunks[num_chunks-1].end = info.end; + } else { + chunks[num_chunks].start = info.start; + chunks[num_chunks].end = info.end; + num_chunks++; + } + } + } + i++; + } while (ret != CYG_FLASH_ERR_INVALID); + fis_read_directory(); img = (struct fis_image_desc *) fis_work_block; for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) { - if (img->u.name[0] != (unsigned char)0xFF) { + if (img->u.name[0] != '\xFF') { // Figure out which chunk this is in and split it for (idx = 0; idx < num_chunks; idx++) { if ((img->flash_base >= chunks[idx].start) && @@ -775,29 +857,31 @@ find_free(struct free_chunk *chunks) chunks[idx].start += img->size; if (chunks[idx].start >= chunks[idx].end) { // This free chunk has collapsed - while (idx < (num_chunks-1)) { + num_chunks--; + while (idx < num_chunks) { chunks[idx] = chunks[idx+1]; idx++; } - num_chunks--; } - } else if ((img->flash_base+img->size) == chunks[idx].end) { - chunks[idx].end = img->flash_base; + } else if ((img->flash_base+img->size-1) >= chunks[idx].end) { + chunks[idx].end = img->flash_base - 1; } else { // Split chunk into two parts - if ((img->flash_base+img->size) < (CYG_ADDRESS)fis_end) { - int j; - // make room for new chunk - for (j = num_chunks; j > (idx+1); j--) - chunks[j] = chunks[j-1]; - chunks[idx+1].start = img->flash_base + img->size; - chunks[idx+1].end = chunks[idx].end; - if (++num_chunks == CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS) { - diag_printf("Warning: too many free chunks\n"); - return num_chunks; - } + int idxtmp; + + // shift chunks along one so we insert the new one + for (idxtmp=num_chunks; idxtmp > (idx+1); idxtmp--) + { + chunks[idxtmp] = chunks[idxtmp-1]; } - chunks[idx].end = img->flash_base; + + chunks[idx+1].start = img->flash_base + img->size; + chunks[idx+1].end = chunks[idx].end; + chunks[idx].end = img->flash_base - 1; + if (++num_chunks == CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS) { + diag_printf("Warning: too many free chunks\n"); + return num_chunks; + } } break; } @@ -811,42 +895,108 @@ find_free(struct free_chunk *chunks) static void fis_free(int argc, char *argv[]) { -#ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS - unsigned long *fis_ptr, *fis_end, flash_data; - unsigned long *area_start; - void *err_addr; +#if !defined(CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS) + cyg_uint32 flash_data; + cyg_flashaddr_t area_start; + cyg_flashaddr_t err_addr; + cyg_uint32 flash_dev_no; + int flash_err; + cyg_flash_info_t flash_info; + cyg_uint32 curr_block, curr_block_info; + cyg_flashaddr_t curr_flash_addr, next_flash_addr; + + // For each flash device + for (flash_dev_no=0;; flash_dev_no++) + { + flash_err = cyg_flash_get_info( flash_dev_no, &flash_info ); + if ( CYG_FLASH_ERR_OK != flash_err ) // assume all done + break; + + if( flash_reserved( flash_info.start ) ) // Ignore reserved devices + continue; + + // Once more, from the top... + curr_flash_addr = area_start = flash_info.start; - // Do not search the area reserved for pre-RedBoot systems: - fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start + - CYGNUM_REDBOOT_FLASH_RESERVED_BASE); - fis_end = (unsigned long *)(CYG_ADDRESS)flash_end; - area_start = fis_ptr; - while (fis_ptr < fis_end) { - flash_read(fis_ptr, &flash_data, sizeof(unsigned long), (void **)&err_addr); - if (flash_data != (unsigned long)0xFFFFFFFF) { - if (area_start != fis_ptr) { - // Assume that this is something - diag_printf(" 0x%08lX .. 0x%08lX\n", - (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr); - } - // Find next blank block - area_start = fis_ptr; - while (area_start < fis_end) { - flash_read(area_start, &flash_data, sizeof(unsigned long), (void **)&err_addr); - if (flash_data == (unsigned long)0xFFFFFFFF) { - break; + // We must not search the area reserved for pre-RedBoot systems, + // but this is only the case for the first flash device, or + // the one corresponding to CYGNUM_REDBOOT_FLASH_BASE. + // FIXME: this is insufficiently generic by design - can only + // reserve on one flash. +#ifdef CYGNUM_REDBOOT_FLASH_BASE + if ( CYGNUM_REDBOOT_FLASH_BASE == area_start ) +#else + if ( 0 == flash_dev_no ) +#endif + { + //cyg_flashaddr_t asold = area_start; + area_start += CYGNUM_REDBOOT_FLASH_RESERVED_BASE; + //diag_printf("area_start was %08x now %08x\n", asold, area_start ); + } + // For each region of blocks + for ( curr_block_info = 0; + curr_block_info < flash_info.num_block_infos; + curr_block_info++ ) + { + // For each individual block + for ( curr_block = 0; + curr_block < flash_info.block_info[curr_block_info].blocks; + curr_flash_addr = next_flash_addr, curr_block++ ) + { + cyg_ucount32 i; + cyg_bool is_blank = true; // until proved otherwise + size_t amount_to_check; + + // determine this now to avoid recalculating it later in this block, so we know the + // end of this block + next_flash_addr = curr_flash_addr + flash_info.block_info[curr_block_info].block_size; + + // If area_start got adjusted further up, skip until we reach it + if ( curr_flash_addr < area_start ) + continue; + + //diag_printf("block region %d, block %d, flashaddr %08x\n",curr_block_info,curr_block,curr_flash_addr); + + // check 32 bytes at most. Reading it all will take too long on many devices. + // Perhaps this should be a config option. + amount_to_check = 32; + if ( amount_to_check > flash_info.block_info[curr_block_info].block_size ) // paranoia + amount_to_check = flash_info.block_info[curr_block_info].block_size; + + for ( i=0; i<amount_to_check; i += sizeof(cyg_uint32) ) + { + flash_err = cyg_flash_read(curr_flash_addr+i, &flash_data, sizeof(cyg_uint32), &err_addr); + if ( (CYG_FLASH_ERR_OK != flash_err) || (flash_data != 0xffffffff) ) + { + is_blank = false; + break; // no point continuing + } + } // for + + if (!is_blank) + { + /* If not blank, output the preceding region if any */ + if ( curr_flash_addr != area_start ) + { + diag_printf(" 0x%08lX .. 0x%08lX\n", + area_start, + next_flash_addr-1 ); + } + area_start = next_flash_addr; } - area_start += flash_block_size / sizeof(CYG_ADDRESS); - } - fis_ptr = area_start; - } else { - fis_ptr += flash_block_size / sizeof(CYG_ADDRESS); + } // for block + } // for block region + + /* If the blank region extended to the very end of the device, we need to do one + * final check at the end of the device. + */ + if ( curr_flash_addr != area_start ) + { + diag_printf(" 0x%08lX .. 0x%08lX\n", + area_start, + next_flash_addr-1 ); } - } - if (area_start != fis_ptr) { - diag_printf(" 0x%08lX .. 0x%08lX\n", - (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr); - } + } // for flash device #else struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS]; int idx, num_chunks; @@ -865,59 +1015,124 @@ static bool fis_find_free(CYG_ADDRESS *addr, unsigned long length) { #ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS - unsigned long *fis_ptr, *fis_end, flash_data; - unsigned long *area_start; - void *err_addr; + cyg_uint32 flash_data; + cyg_flashaddr_t area_start; + cyg_flashaddr_t err_addr; + cyg_uint32 flash_dev_no; + int flash_err; + cyg_flash_info_t flash_info; + cyg_uint32 curr_block, curr_block_info; + cyg_flashaddr_t curr_flash_addr, next_flash_addr; + + // For each flash device + for (flash_dev_no=0;; flash_dev_no++) + { + flash_err = cyg_flash_get_info( flash_dev_no, &flash_info ); + if ( CYG_FLASH_ERR_OK != flash_err ) // assume all done + break; + + if( flash_reserved( flash_info.start ) ) // Ignore reserved devices + continue; + + // Once more, from the top... + curr_flash_addr = area_start = flash_info.start; - // Do not search the area reserved for pre-RedBoot systems: - fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start + - CYGNUM_REDBOOT_FLASH_RESERVED_BASE); - fis_end = (unsigned long *)(CYG_ADDRESS)flash_end; - area_start = fis_ptr; - while (fis_ptr < fis_end) { - flash_read(fis_ptr, &flash_data, sizeof(unsigned long), (void **)&err_addr); - if (flash_data != (unsigned long)0xFFFFFFFF) { - if (area_start != fis_ptr) { - // Assume that this is something - if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) { - *addr = (CYG_ADDRESS)area_start; - return true; + // We must not search the area reserved for pre-RedBoot systems, + // but this is only the case for the first flash device, or + // the one corresponding to CYGNUM_REDBOOT_FLASH_BASE. + // FIXME: this is insufficiently generic by design - can only + // reserve on one flash. +#ifdef CYGNUM_REDBOOT_FLASH_BASE + if ( CYGNUM_REDBOOT_FLASH_BASE == area_start ) +#else + if ( 0 == flash_dev_no ) +#endif + { + //cyg_flashaddr_t asold = area_start; + area_start += CYGNUM_REDBOOT_FLASH_RESERVED_BASE; + //diag_printf("area_start was %08x now %08x\n", asold, area_start ); + } + // For each region of blocks + for ( curr_block_info = 0; + curr_block_info < flash_info.num_block_infos; + curr_block_info++ ) + { + // For each individual block + for ( curr_block = 0; + curr_block < flash_info.block_info[curr_block_info].blocks; + curr_flash_addr = next_flash_addr, curr_block++ ) + { + cyg_ucount32 i; + cyg_bool is_blank = true; // until proved otherwise + size_t amount_to_check; + + // determine this now to avoid recalculating it later in this block, so we know the + // end of this block + next_flash_addr = curr_flash_addr + flash_info.block_info[curr_block_info].block_size; + + // If area_start got adjusted further up, skip until we reach it + if ( curr_flash_addr < area_start ) + continue; + + //diag_printf("block region %d, block %d, flashaddr %08x\n",curr_block_info,curr_block,curr_flash_addr); + + // check 32 bytes at most. Reading it all will take too long on many devices. + // Perhaps this should be a config option. + amount_to_check = 32; + if ( amount_to_check > flash_info.block_info[curr_block_info].block_size ) // paranoia + amount_to_check = flash_info.block_info[curr_block_info].block_size; + + for ( i=0; i<amount_to_check; i += sizeof(cyg_uint32) ) + { + flash_err = cyg_flash_read(curr_flash_addr+i, &flash_data, sizeof(cyg_uint32), &err_addr); + if ( (CYG_FLASH_ERR_OK != flash_err) || (flash_data != 0xffffffff) ) + { + is_blank = false; + break; // no point continuing + } + } // for + + if (!is_blank) + { + /* If not blank, output the preceding region if any */ + if ( curr_flash_addr != area_start ) + { + if ( length <= (next_flash_addr - area_start) ) + { + *addr = (CYG_ADDRESS)area_start; + return true; + } + } + area_start = next_flash_addr; } - } - // Find next blank block - area_start = fis_ptr; - while (area_start < fis_end) { - flash_read(area_start, &flash_data, sizeof(unsigned long), (void **)&err_addr); - if (flash_data == (unsigned long)0xFFFFFFFF) { - break; - } - area_start += flash_block_size / sizeof(CYG_ADDRESS); - } - fis_ptr = area_start; - } else { - fis_ptr += flash_block_size / sizeof(CYG_ADDRESS); + } // for block + } // for block region + + /* If the blank region extended to the very end of the device, we need to do one + * final check at the end of the device. + */ + if ( curr_flash_addr != area_start ) + { + if ( length <= (next_flash_addr - area_start) ) + { + *addr = (CYG_ADDRESS)area_start; + return true; + } } - } - if (area_start != fis_ptr) { - if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) { - *addr = (CYG_ADDRESS)area_start; - return true; - } - } - return false; + } // for flash device #else struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS]; int idx, num_chunks; num_chunks = find_free(chunks); for (idx = 0; idx < num_chunks; idx++) { - if ((chunks[idx].end - chunks[idx].start) >= length) { + if ((chunks[idx].end - chunks[idx].start + 1) >= length) { *addr = (CYG_ADDRESS)chunks[idx].start; return true; } } +#endif return false; -#endif } static void @@ -925,7 +1140,7 @@ fis_create(int argc, char *argv[]) { int i, stat; unsigned long length, img_size; - CYG_ADDRESS mem_addr, exec_addr, flash_addr, entry_addr; + CYG_ADDRESS mem_addr, exec_addr, flash_addr, entry_addr, flash_offset; char *name; bool mem_addr_set = false; bool exec_addr_set = false; @@ -934,12 +1149,13 @@ fis_create(int argc, char *argv[]) bool length_set = false; bool img_size_set = false; bool no_copy = false; - void *err_addr; + cyg_flashaddr_t err_addr; struct fis_image_desc *img = NULL; bool defaults_assumed; struct option_info opts[7]; bool prog_ok = true; - + size_t block_size; + 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, @@ -974,14 +1190,16 @@ fis_create(int argc, char *argv[]) } } } - if (!mem_addr_set && (load_address >= (CYG_ADDRESS)ram_start) && + if ((!mem_addr_set || mem_addr == load_address) && !no_copy && (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) + if (!entry_addr_set) { entry_addr = entry_address; + entry_addr_set = true; + } if (!length_set) { length = load_address_end - load_address; length_set = true; @@ -1006,7 +1224,7 @@ fis_create(int argc, char *argv[]) } } - if ((!no_copy && !mem_addr_set) || (no_copy && !flash_addr_set) || + if ((!no_copy && !mem_addr_set) || !length_set || !name) { fis_usage("required parameter missing"); return; @@ -1014,44 +1232,57 @@ fis_create(int argc, char *argv[]) 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 (strlen(name) >= sizeof(img->u.name)) { + diag_printf("Name is too long, must be less than %d chars\n", (int)sizeof(img->u.name)); + 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)) != 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->u.name)) { - diag_printf("Name is too long, must be less than %d chars\n", (int)sizeof(img->u.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; - } + } + 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; + } + flash_addr_set = true; + + block_size = cyg_flash_block_size(flash_addr + length); + length = ((length + block_size - 1) / block_size) * block_size; + if (length < img_size) { + diag_printf("Invalid FLASH image size/length combination\n"); + return; } + if ((stat = cyg_flash_verify_addr(flash_addr)) || + (stat = cyg_flash_verify_addr((flash_addr+length-1)))) { + _show_invalid_flash_address(flash_addr, stat); + return; + } + block_size = cyg_flash_block_size(flash_addr); + flash_offset = (flash_addr-flash_start)/block_size; + if( flash_start + (flash_offset * block_size) != flash_addr ) { + diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr); + diag_printf(" must be 0x%x aligned\n", (unsigned int)flash_block_size); + return; + } + // First, see if the image by this name has agreable properties if (img) { - if (flash_addr_set && (img->flash_base != flash_addr)) { + if (img->flash_base != flash_addr) { diag_printf("Image found, but flash address (%p)\n" " is incorrect (present image location %p)\n", (void*)flash_addr, (void*)img->flash_base); @@ -1079,13 +1310,14 @@ fis_create(int argc, char *argv[]) } 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) { + if (!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++) { + //diag_printf("addr %08x, length %d chunk start %08x, end %08x\n",flash_addr, length, chunks[idx].start, chunks[idx].end); if ((flash_addr >= chunks[idx].start) && ((flash_addr+length-1) <= chunks[idx].end)) { is_free = true; @@ -1097,10 +1329,10 @@ fis_create(int argc, char *argv[]) } } #endif - // If not image by that name, try and find an empty slot + // If no 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->u.name[0] == (unsigned char)0xFF) { + if (img->u.name[0] == '\xFF') { break; } } @@ -1111,24 +1343,44 @@ fis_create(int argc, char *argv[]) } 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))) { + if (check_code_overlaps(flash_addr, (flash_addr+img_size-1))) { diag_printf("Can't program this region - contains code in use!\n"); return; } +#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING + if (prog_ok) { + // Unlock area to be programmed + if ((stat = cyg_flash_unlock((cyg_flashaddr_t)flash_addr, length, &err_addr)) != 0) { + diag_printf("Can't unlock region at %p: %s\n", (void*)err_addr, flash_errmsg(stat)); + prog_ok = false; + } + } +#endif 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)); + if ((stat = cyg_flash_erase(flash_addr, length, &err_addr)) != 0) { + diag_printf("Can't erase region at %p: %s\n", (void*)err_addr, cyg_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)); + if ((stat = cyg_flash_program(flash_addr, (void *)mem_addr, img_size, + &err_addr)) != 0) { + diag_printf("Can't program region at %p: %s\n", (void*)err_addr, + cyg_flash_errmsg(stat)); prog_ok = false; } } +#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING + if (prog_ok) { + // Lock area programmed + if ((stat = cyg_flash_lock((cyg_flashaddr_t)flash_addr, length, &err_addr)) != 0) { + diag_printf("Can't lock region at %p: %s\n", (void*)err_addr, flash_errmsg(stat)); + prog_ok = false; + } + } +#endif } if (prog_ok) { // Update directory @@ -1158,7 +1410,7 @@ fis_delete(int argc, char *argv[]) { char *name; int num_reserved, i, stat; - void *err_addr; + cyg_flashaddr_t err_addr; struct fis_image_desc *img; if (!scan_opts(argc, argv, 2, 0, 0, (void *)&name, OPTION_ARG_TYPE_STR, "image name")) @@ -1206,10 +1458,10 @@ fis_delete(int argc, char *argv[]) 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)); + if ((stat = cyg_flash_erase(img->flash_base, img->size, &err_addr)) != 0) { + diag_printf("Error erasing at %p: %s\n", (void*)err_addr, cyg_flash_errmsg(stat)); } else { - img->u.name[0] = (unsigned char)0xFF; + img->u.name[0] = '\xFF'; fis_start_update_directory(0); fis_update_directory(0, 0); } @@ -1231,7 +1483,7 @@ fis_load(int argc, char *argv[]) #if defined(CYGPRI_REDBOOT_ZLIB_FLASH) || defined(CYGSEM_REDBOOT_FIS_CRC_CHECK) bool decompress = false; #endif - void *err_addr; + cyg_flashaddr_t err_addr; init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, (void *)&mem_addr, (bool *)&mem_addr_set, "memory [load] base address"); @@ -1299,7 +1551,8 @@ fis_load(int argc, char *argv[]) } else // dangling block #endif { - flash_read((void *)img->flash_base, (void *)mem_addr, img->data_length, (void **)&err_addr); + cyg_flash_read(img->flash_base, (void *)mem_addr, img->data_length, + &err_addr); // Set load address/top load_address = mem_addr; @@ -1329,14 +1582,15 @@ fis_write(int argc, char *argv[]) { int stat; unsigned long length; - CYG_ADDRESS mem_addr, flash_addr; + CYG_ADDRESS mem_addr, flash_addr, flash_offset; bool mem_addr_set = false; bool flash_addr_set = false; bool length_set = false; - void *err_addr; + cyg_flashaddr_t err_addr; struct option_info opts[3]; bool prog_ok; - + size_t block_size; + 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, @@ -1355,18 +1609,19 @@ fis_write(int argc, char *argv[]) } // 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))))) { + block_size = cyg_flash_block_size(flash_addr + length); + length = ((length + block_size - 1) / block_size) * block_size; + if ((stat = cyg_flash_verify_addr(flash_addr)) || + (stat = cyg_flash_verify_addr((flash_addr+length-1)))) { _show_invalid_flash_address(flash_addr, stat); return; } - if (flash_addr_set && flash_addr & (flash_block_size-1)) { + + block_size = cyg_flash_block_size(flash_addr); + flash_offset = (flash_addr-flash_start)/block_size; + if( flash_start + (flash_offset * block_size) != flash_addr ) { diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr); - diag_printf(" must be 0x%x aligned\n", flash_block_size); + diag_printf(" must be 0x%x aligned\n", (unsigned int)block_size); return; } if ((mem_addr < (CYG_ADDRESS)ram_start) || @@ -1375,7 +1630,7 @@ fis_write(int argc, char *argv[]) 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))) { + if (check_code_overlaps(flash_addr, (flash_addr+length-1))) { diag_printf("Can't program this region - contains code in use!\n"); return; } @@ -1387,15 +1642,18 @@ fis_write(int argc, char *argv[]) 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)); + if ((stat = cyg_flash_erase(flash_addr, length, &err_addr)) != 0) { + diag_printf("Can't erase region at %p: %s\n", (void*)err_addr, + cyg_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)); + if ((stat = cyg_flash_program(flash_addr, (void *)mem_addr, length, + &err_addr)) != 0) { + diag_printf("Can't program region at %p: %s\n", (void*)err_addr, + cyg_flash_errmsg(stat)); prog_ok = false; } } @@ -1406,11 +1664,13 @@ fis_erase(int argc, char *argv[]) { int stat; unsigned long length; - CYG_ADDRESS flash_addr; + CYG_ADDRESS flash_addr, flash_offset; bool flash_addr_set = false; bool length_set = false; - void *err_addr; + cyg_flashaddr_t err_addr; struct option_info opts[2]; + size_t block_size; + init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, (void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address"); @@ -1427,23 +1687,25 @@ fis_erase(int argc, char *argv[]) return; } if (flash_addr_set && - ((stat = flash_verify_addr((void *)flash_addr)) || - (stat = flash_verify_addr((void *)(flash_addr+length-1))))) { + ((stat = cyg_flash_verify_addr(flash_addr)) || + (stat = cyg_flash_verify_addr((flash_addr+length-1))))) { _show_invalid_flash_address(flash_addr, stat); return; } - if (flash_addr_set && flash_addr & (flash_block_size-1)) { + block_size = cyg_flash_block_size(flash_addr); + flash_offset = (flash_addr-flash_start)/block_size; + if( flash_addr_set && (flash_start + (flash_offset * block_size) != flash_addr) ) { diag_printf("Invalid FLASH address: %p\n", (void *)flash_addr); - diag_printf(" must be 0x%x aligned\n", flash_block_size); + diag_printf(" must be 0x%x aligned\n", (unsigned int)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))) { + if (check_code_overlaps(flash_addr, (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)); + if ((stat = cyg_flash_erase(flash_addr, length, &err_addr)) != 0) { + diag_printf("Error erasing at %p: %s\n", (void*)err_addr, cyg_flash_errmsg(stat)); } } @@ -1458,7 +1720,7 @@ fis_lock(int argc, char *argv[]) CYG_ADDRESS flash_addr; bool flash_addr_set = false; bool length_set = false; - void *err_addr; + cyg_flashaddr_t err_addr; struct option_info opts[2]; init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, @@ -1488,13 +1750,13 @@ fis_lock(int argc, char *argv[]) return; } if (flash_addr_set && - ((stat = flash_verify_addr((void *)flash_addr)) || - (stat = flash_verify_addr((void *)(flash_addr+length-1))))) { + ((stat = cyg_flash_verify_addr(flash_addr)) || + (stat = cyg_flash_verify_addr((flash_addr+length-1))))) { _show_invalid_flash_address(flash_addr, stat); return; } - if ((stat = flash_lock((void *)flash_addr, length, (void **)&err_addr)) != 0) { - diag_printf("Error locking at %p: %s\n", err_addr, flash_errmsg(stat)); + if ((stat = cyg_flash_lock(flash_addr, length, &err_addr)) != 0) { + diag_printf("Error locking at %p: %s\n", (void*)err_addr, cyg_flash_errmsg(stat)); } } @@ -1507,7 +1769,7 @@ fis_unlock(int argc, char *argv[]) CYG_ADDRESS flash_addr; bool flash_addr_set = false; bool length_set = false; - void *err_addr; + cyg_flashaddr_t err_addr; struct option_info opts[2]; init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, @@ -1536,27 +1798,43 @@ fis_unlock(int argc, char *argv[]) return; } if (flash_addr_set && - ((stat = flash_verify_addr((void *)flash_addr)) || - (stat = flash_verify_addr((void *)(flash_addr+length-1))))) { + ((stat = cyg_flash_verify_addr(flash_addr)) || + (stat = cyg_flash_verify_addr((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)); + if ((stat = cyg_flash_unlock(flash_addr, length, &err_addr)) != 0) { + diag_printf("Error unlocking at %p: %s\n", (void*)err_addr, cyg_flash_errmsg(stat)); } } #endif // This is set non-zero if the FLASH subsystem has successfully been initialized -int __flash_init = 0; +int __flash_init; void _flash_info(void) -{ +{ + cyg_uint32 i=0,j; + cyg_flash_info_t info; + int ret; + if (!__flash_init) return; - diag_printf("FLASH: %p - 0x%x, %d blocks of %p bytes each.\n", - flash_start, (CYG_ADDRWORD)flash_end + 1, flash_num_blocks, (void *)flash_block_size); + + do { + ret = cyg_flash_get_info(i, &info); + if (ret == CYG_FLASH_ERR_OK) { + diag_printf("FLASH: %p-%p", (void*)info.start, (void*)info.end); + for (j=0;j < info.num_block_infos; j++) { + diag_printf(", %d x 0x%x blocks", + info.block_info[j].blocks, + (unsigned int)info.block_info[j].block_size); + } + diag_printf("\n"); + } + i++; + } while (ret != CYG_FLASH_ERR_INVALID); } /* Returns -1 on failure, 0 on success, 1 if it was successfull @@ -1564,13 +1842,14 @@ void int do_flash_init(void) { - int stat; + int stat, i; + cyg_flash_info_t info; #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS struct fis_image_desc img0; struct fis_image_desc img1; int fis_update_was_interrupted=0; - void *err_addr; + cyg_flashaddr_t err_addr; //check the size of fis_valid_info CYG_ASSERT((sizeof(struct fis_valid_info)<=sizeof(img0.u.name)), "fis_valid_info size mismatch"); @@ -1582,14 +1861,39 @@ do_flash_init(void) if (!__flash_init) { __flash_init = 1; - if ((stat = flash_init(diag_printf)) != 0) { - diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat)); + + if ((stat = cyg_flash_init(diag_printf)) != 0) { + diag_printf("FLASH: driver init failed: %s\n", cyg_flash_errmsg(stat)); return -1; } - 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 CYGNUM_REDBOOT_FLASH_BASE + stat = cyg_flash_get_info_addr(CYGNUM_REDBOOT_FLASH_BASE, &info); +#else + stat = cyg_flash_get_info(0, &info); +#endif + if (stat != CYG_FLASH_ERR_OK) { + diag_printf("FLASH: driver init failed: %s\n", + cyg_flash_errmsg(stat)); + return false; + } + flash_start = info.start; + flash_end = info.end; + + // No bootblock support yet, so we merge any bootblocks we might + // find into full size blocks + for (i=0; i < info.num_block_infos; i++) { + if (info.block_info[i].block_size > flash_block_size) { + flash_block_size = info.block_info[i].block_size; + } + } + flash_num_blocks = 0; + for (i=0; i < info.num_block_infos; i++) { + flash_num_blocks += (info.block_info[i].block_size * + info.block_info[i].blocks) / + flash_block_size; + } + #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; @@ -1603,12 +1907,13 @@ do_flash_init(void) 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)); + fis_addr = ((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)); + fis_addr = ((CYG_ADDRESS)flash_start + + (CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK*flash_block_size)); } if (((CYG_ADDRESS)fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) { @@ -1629,8 +1934,8 @@ do_flash_init(void) diag_printf("Redundant FIS directory doesn't fit\n"); return -1; } - FLASH_READ(fis_addr, &img0, sizeof(img0), (void **)&err_addr); - FLASH_READ(redundant_fis_addr, &img1, sizeof(img1), (void **)&err_addr); + cyg_flash_read(fis_addr, &img0, sizeof(img0), &err_addr); + cyg_flash_read(redundant_fis_addr, &img1, sizeof(img1), &err_addr); if (strncmp(img0.u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC, CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH)!=0) {
