X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=packages%2Fredboot%2Fv2_0%2Fsrc%2Fflash.c;h=b3f0beaa4ab56514e3fbf6ff9ed61ec6deba6338;hb=50b52bf012fcf261e5ebf8fca86bfd3a863a114e;hp=5a2cbfc492f8d386e87f925ff0d0aed44ca01d61;hpb=29ac1edaf5f12d706179ec87816ee1506ba4c9a1;p=karo-tx-redboot.git diff --git a/packages/redboot/v2_0/src/flash.c b/packages/redboot/v2_0/src/flash.c index 5a2cbfc4..b3f0beaa 100644 --- a/packages/redboot/v2_0/src/flash.c +++ b/packages/redboot/v2_0/src/flash.c @@ -1,8 +1,8 @@ //========================================================================== // -// flash.c +// flash.c // -// RedBoot - FLASH memory support +// RedBoot - FLASH memory support // //========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### @@ -41,12 +41,12 @@ //========================================================================== //#####DESCRIPTIONBEGIN#### // -// Author(s): gthomas +// Author(s): gthomas // Contributors: gthomas, tkoeller -// Date: 2000-07-28 -// Purpose: -// Description: -// +// Date: 2000-07-28 +// Purpose: +// Description: +// // This code is part of RedBoot (tm). // //####DESCRIPTIONEND#### @@ -54,10 +54,15 @@ //========================================================================== #include +#define _FLASH_PRIVATE_ #include #include #include -#include // assertion macros +#include // assertion macros + +#ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT +#include +#endif #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG // Note horrid intertwining of functions, to save precious FLASH @@ -70,10 +75,10 @@ extern void conf_endian_fixup(void *p); #ifdef CYGOPT_REDBOOT_FIS // Image management functions local_cmd_entry("init", - "Initialize FLASH Image System [FIS]", - "[-f]", - fis_init, - FIS_cmds + "Initialize FLASH Image System [FIS]", + "[-f]", + fis_init, + FIS_cmds ); #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK # define FIS_LIST_OPTS "[-c] [-d]" @@ -81,71 +86,84 @@ local_cmd_entry("init", # define FIS_LIST_OPTS "[-d]" #endif local_cmd_entry("list", - "Display contents of FLASH Image System [FIS]", - FIS_LIST_OPTS, - fis_list, - FIS_cmds + "Display contents of FLASH Image System [FIS]", + FIS_LIST_OPTS, + fis_list, + FIS_cmds ); local_cmd_entry("free", - "Display free [available] locations within FLASH Image System [FIS]", - "", - fis_free, - FIS_cmds + "Display free [available] locations within FLASH Image System [FIS]", + "", + fis_free, + FIS_cmds ); local_cmd_entry("delete", - "Delete an image from FLASH Image System [FIS]", - "name", - fis_delete, - FIS_cmds + "Delete an image from FLASH Image System [FIS]", + "name", + fis_delete, + FIS_cmds ); -static char fis_load_usage[] = +static char fis_load_usage[] = +#ifdef CYGPRI_REDBOOT_ZLIB_FLASH + "[-d] " +#endif + "[-b ] [-c] " +#ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT + "[-w]" +#endif + "name\n" + "Options:\n" #ifdef CYGPRI_REDBOOT_ZLIB_FLASH - "[-d] " + "\t-d: decompress\n" +#endif + "\t-c: print checksum\n" +#ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT + "\t-w: load as Windows CE image\n" #endif - "[-b ] [-c] name"; + ; local_cmd_entry("load", - "Load image from FLASH Image System [FIS] into RAM", - fis_load_usage, - fis_load, - FIS_cmds + "Load image from FLASH Image System [FIS] into RAM", + fis_load_usage, + fis_load, + FIS_cmds ); local_cmd_entry("create", - "Create an image", - "[-b ] [-l ] [-s ]\n" - " [-f ] [-e ] [-r ] [-n] ", - fis_create, - FIS_cmds + "Create an image", + "[-b ] [-l ] [-s ]\n" + " [-f ] [-e ] [-r ] [-n] ", + fis_create, + FIS_cmds ); #endif // Raw flash access functions local_cmd_entry("erase", - "Erase FLASH contents", - "-f -l ", - fis_erase, - FIS_cmds + "Erase FLASH contents", + "-f -l ", + fis_erase, + FIS_cmds ); #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING local_cmd_entry("lock", - "LOCK FLASH contents", - "[-f -l ] [name]", - fis_lock, - FIS_cmds + "LOCK FLASH contents", + "[-f -l ] [name]", + fis_lock, + FIS_cmds ); local_cmd_entry("unlock", - "UNLOCK FLASH contents", - "[-f -l ] [name]", - fis_unlock, - FIS_cmds + "UNLOCK FLASH contents", + "[-f -l ] [name]", + fis_unlock, + FIS_cmds ); #endif local_cmd_entry("write", - "Write raw data directly to FLASH", - "-f -b -l ", - fis_write, - FIS_cmds + "Write raw data directly to FLASH", + "-f -b -l ", + fis_write, + FIS_cmds ); // Define table boundaries @@ -156,11 +174,11 @@ extern struct cmd __FIS_cmds_TAB__[], __FIS_cmds_TAB_END__; // CLI function static cmd_fun do_fis; -RedBoot_nested_cmd("fis", - "Manage FLASH images", - "{cmds}", - do_fis, - __FIS_cmds_TAB__, &__FIS_cmds_TAB_END__ +RedBoot_nested_cmd("fis", + "Manage FLASH images", + "{cmds}", + do_fis, + __FIS_cmds_TAB__, &__FIS_cmds_TAB_END__ ); // Local data used by these routines @@ -169,11 +187,14 @@ int flash_block_size, flash_num_blocks; #ifdef CYGOPT_REDBOOT_FIS void *fis_work_block; void *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 void *cfg_base; // Location in Flash of config data +extern int cfg_size; // Length of config data - rounded to Flash block size extern struct _config *config; #endif @@ -184,11 +205,11 @@ fis_usage(char *why) cmd_usage(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__, "fis "); } -static void +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); + diag_printf(" valid range is %p-%p\n", flash_start, flash_end); } #ifdef CYGOPT_REDBOOT_FIS @@ -202,14 +223,14 @@ static inline void fis_endian_fixup(void *addr) int cnt = fisdir_size / sizeof(struct fis_image_desc); while (cnt-- > 0) { - p->flash_base = CYG_SWAP32(p->flash_base); - p->mem_base = CYG_SWAP32(p->mem_base); - p->size = CYG_SWAP32(p->size); - p->entry_point = CYG_SWAP32(p->entry_point); - p->data_length = CYG_SWAP32(p->data_length); - p->desc_cksum = CYG_SWAP32(p->desc_cksum); - p->file_cksum = CYG_SWAP32(p->file_cksum); - p++; + p->flash_base = CYG_SWAP32(p->flash_base); + p->mem_base = CYG_SWAP32(p->mem_base); + p->size = CYG_SWAP32(p->size); + p->entry_point = CYG_SWAP32(p->entry_point); + p->data_length = CYG_SWAP32(p->data_length); + p->desc_cksum = CYG_SWAP32(p->desc_cksum); + p->file_cksum = CYG_SWAP32(p->file_cksum); + p++; } #endif } @@ -219,7 +240,7 @@ fis_read_directory(void) { void *err_addr; - FLASH_READ(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr); + FLASH_READ(fis_addr, fis_work_block, fisdir_size, &err_addr); fis_endian_fixup(fis_work_block); } @@ -232,46 +253,208 @@ fis_lookup(char *name, int *num) fis_read_directory(); 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) && - (strcasecmp(name, img->name) == 0)) { - if (num) *num = i; - return img; - } - } - return (struct fis_image_desc *)0; + for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) { + if ((img->u.name[0] != 0xFF) && + (strcasecmp(name, img->u.name) == 0)) { + if (num) *num = i; + return img; + } + } + return NULL; } -void -fis_update_directory(void) +int fis_start_update_directory(int autolock) +{ +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS +#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING +#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL + // Ensure [quietly] that the directory is unlocked before trying to update and locked again afterwards + int do_autolock = 1; +#else + int do_autolock = autolock; +#endif +#endif + + struct fis_image_desc *img; + void *err_addr; + void *tmp_fis_addr; + + /*exchange old and new valid fis tables*/ + tmp_fis_addr = fis_addr; + fis_addr = redundant_fis_addr; + redundant_fis_addr = tmp_fis_addr; + + //adjust the contents of the new fis table + img = fis_work_block; + + memcpy(img->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC, + CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH); + img->u.valid_info.valid_flag[0] = CYG_REDBOOT_RFIS_IN_PROGRESS; + img->u.valid_info.valid_flag[1] = CYG_REDBOOT_RFIS_IN_PROGRESS; + img->u.valid_info.version_count = img->u.valid_info.version_count+1; + + //ready to go.... +#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING + if (do_autolock) + flash_unlock((void *)fis_addr, fisdir_size, &err_addr); +#endif + + flash_erase(fis_addr, fisdir_size, &err_addr); + //now magic is 0xffffffff + fis_endian_fixup(fis_work_block); + flash_program(fis_addr, fis_work_block, flash_block_size, &err_addr); + fis_endian_fixup(fis_work_block); + //now magic is 0xff1234ff, valid is IN_PROGRESS, version_count is the old one +1 + +#else + /* nothing to do here without redundant fis */ +#endif + return 0; + +} + +int +fis_update_directory(int autolock, int error) { + void *err_addr; + +#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING +#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL + // Ensure [quietly] that the directory is unlocked before trying to update and locked again afterwards + int do_autolock = 1; +#else + int do_autolock = autolock; +#endif +#endif + +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + + struct fis_image_desc *img = fis_work_block; + + // called from invalid state + if (img->u.valid_info.valid_flag[0] != CYG_REDBOOT_RFIS_IN_PROGRESS) + return -1; + + //if it failed, reset is0Valid to the state before startUpdateDirectory() + //g_data.fisTable hasn't been changed yet, so it doesn't have to be reset now + //then reread the contents from flash + //setting the valid flag of the failed table to "INVALID" might also be not too bad + //but IN_PROGRESS is also good enough I think + if (error != 0) { + void *swap_fis_addr = fis_addr; + fis_addr = redundant_fis_addr; + redundant_fis_addr = swap_fis_addr; + } else { + //success + void *tmp_fis_addr = (void *)((CYG_ADDRESS)fis_addr + + CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH); + + 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), &err_addr); + } +#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING + if (do_autolock) + flash_lock((void *)fis_addr, fisdir_size, &err_addr); +#endif + +#else // CYGOPT_REDBOOT_REDUNDANT_FIS + int blk_size = fisdir_size; 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); + blk_size += 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); +#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING + if (do_autolock) + flash_unlock((void *)fis_addr, blk_size, &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)); + if ((stat = flash_erase(fis_addr, flash_block_size, &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)); - } + if ((stat = 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, 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, &err_addr); +#endif + +#endif // CYGOPT_REDBOOT_REDUNDANT_FIS + + return 0; +} + +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + +int +fis_get_valid_buf(struct fis_image_desc *img0, struct fis_image_desc *img1, int *update_was_interrupted) +{ + *update_was_interrupted = 0; + if (strncmp(img1->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC, + CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) { + //buf0 must be valid + if (img0->u.valid_info.version_count > 0) { + *update_was_interrupted = 1; + } + return 0; + } else if (strncmp(img0->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC, + CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) { + //buf1 must be valid + if (img1->u.valid_info.version_count > 0) { + *update_was_interrupted = 1; + } + return 1; + } + //magic is ok for both, now check the valid flag + if ((img1->u.valid_info.valid_flag[0] != CYG_REDBOOT_RFIS_VALID) || + (img1->u.valid_info.valid_flag[1] != CYG_REDBOOT_RFIS_VALID)) { + //buf0 must be valid + *update_was_interrupted = 1; + return 0; + } else if ((img0->u.valid_info.valid_flag[0] != CYG_REDBOOT_RFIS_VALID) || + (img0->u.valid_info.valid_flag[1] != CYG_REDBOOT_RFIS_VALID)) { + //buf1 must be valid + *update_was_interrupted = 1; + return 1; + } + + //now check the version + return img1->u.valid_info.version_count == (img0->u.valid_info.version_count + 1); +} + +void +fis_erase_redundant_directory(void) +{ + int stat; + void *err_addr; + +#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, + &err_addr); +#endif + if ((stat = 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)); } #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); + flash_lock((void *)redundant_fis_addr, fisdir_size, &err_addr); #endif - fis_endian_fixup(fis_work_block); } +#endif static void fis_init(int argc, char *argv[]) @@ -284,29 +467,39 @@ fis_init(int argc, char *argv[]) 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; + init_opts(&opts[0], 'f', false, OPTION_ARG_TYPE_FLG, + &full_init, NULL, "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("** 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; + 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; + img = fis_work_block; memset(img, 0xFF, fisdir_size); // Start with erased data + +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + //create the valid flag entry + memset(img, 0, sizeof(struct fis_image_desc)); + strcpy(img->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC); + img->u.valid_info.valid_flag[0] = CYG_REDBOOT_RFIS_VALID; + img->u.valid_info.valid_flag[1] = CYG_REDBOOT_RFIS_VALID; + img->u.valid_info.version_count = 0; + img++; +#endif + + // Create a pseudo image for RedBoot #ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE memset(img, 0, sizeof(*img)); - strcpy(img->name, "(reserved)"); + strcpy(img->u.name, "(reserved)"); img->flash_base = (CYG_ADDRESS)flash_start; img->mem_base = (CYG_ADDRESS)flash_start; img->size = CYGNUM_REDBOOT_FLASH_RESERVED_BASE; @@ -315,7 +508,7 @@ fis_init(int argc, char *argv[]) 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"); + strcpy(img->u.name, "RedBoot"); img->flash_base = redboot_flash_start; img->mem_base = redboot_flash_start; img->size = redboot_image_size; @@ -328,7 +521,7 @@ fis_init(int argc, char *argv[]) redboot_flash_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET; #endif memset(img, 0, sizeof(*img)); - strcpy(img->name, "RedBoot[post]"); + strcpy(img->u.name, "RedBoot[post]"); img->flash_base = redboot_flash_start; img->mem_base = redboot_flash_start; img->size = redboot_image_size; @@ -338,7 +531,7 @@ fis_init(int argc, char *argv[]) #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP // And a backup image memset(img, 0, sizeof(*img)); - strcpy(img->name, "RedBoot[backup]"); + strcpy(img->u.name, "RedBoot[backup]"); img->flash_base = redboot_flash_start; img->mem_base = redboot_flash_start; img->size = redboot_image_size; @@ -348,7 +541,7 @@ fis_init(int argc, char *argv[]) #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"); + strcpy(img->u.name, "RedBoot config"); img->flash_base = (CYG_ADDRESS)cfg_base; img->mem_base = (CYG_ADDRESS)cfg_base; img->size = cfg_size; @@ -356,12 +549,22 @@ fis_init(int argc, char *argv[]) #endif // And a descriptor for the descriptor table itself memset(img, 0, sizeof(*img)); - strcpy(img->name, "FIS directory"); + strcpy(img->u.name, "FIS directory"); img->flash_base = (CYG_ADDRESS)fis_addr; img->mem_base = (CYG_ADDRESS)fis_addr; img->size = fisdir_size; img++; + //create the entry for the redundant fis table +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + memset(img, 0, sizeof(*img)); + strcpy(img->u.name, "Redundant FIS"); + img->flash_base = (CYG_ADDRESS)redundant_fis_addr; + img->mem_base = (CYG_ADDRESS)redundant_fis_addr; + img->size = fisdir_size; + img++; +#endif + #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. @@ -369,32 +572,32 @@ fis_init(int argc, char *argv[]) // 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. + 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; + 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; + 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 @@ -402,86 +605,90 @@ fis_init(int argc, char *argv[]) // 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: + 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. + 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, + &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)); - } - } + 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, + &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, + &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, + &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, + &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 + // 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"); + diag_printf(" Warning: device contents not erased, some blocks may not be usable\n"); #endif } - fis_update_directory(); + fis_start_update_directory(0); + fis_update_directory(0, 0); +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + fis_erase_redundant_directory(); +#endif } static void fis_list(int argc, char *argv[]) { struct fis_image_desc *img; - int i, image_indx; + int i = 0, image_indx; bool show_cksums = false; bool show_datalen = false; struct option_info opts[2]; @@ -495,57 +702,54 @@ fis_list(int argc, char *argv[]) return; #endif - init_opts(&opts[0], 'd', false, OPTION_ARG_TYPE_FLG, - (void *)&show_datalen, (bool *)0, "display data length"); + init_opts(&opts[i++], 'd', false, OPTION_ARG_TYPE_FLG, + &show_datalen, NULL, "display data length"); #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK - init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG, - (void *)&show_cksums, (bool *)0, "display checksums"); - i = 2; -#else - i = 1; + init_opts(&opts[i++], 'c', false, OPTION_ARG_TYPE_FLG, + &show_cksums, NULL, "display checksums"); #endif if (!scan_opts(argc, argv, 2, opts, i, 0, 0, "")) { - return; + return; } fis_read_directory(); // Let diag_printf do the formatting in both cases, rather than counting // cols by hand.... diag_printf("%-16s %-10s %-10s %-10s %-s\n", - "Name","FLASH addr", - show_cksums ? "Checksum" : "Mem addr", - show_datalen ? "Datalen" : "Length", - "Entry point" ); + "Name","FLASH addr", + show_cksums ? "Checksum" : "Mem addr", + show_datalen ? "Datalen" : "Length", + "Entry point" ); last_addr = 0; image_indx = 0; do { - image_found = false; - lowest_addr = 0xFFFFFFFF; - 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) { - if ((img->flash_base > last_addr) && (img->flash_base < lowest_addr)) { - lowest_addr = img->flash_base; - image_found = true; - image_indx = i; - } - } - } - if (image_found) { - img = (struct fis_image_desc *) fis_work_block; - img += image_indx; - diag_printf("%-16s 0x%08lX 0x%08lX 0x%08lX 0x%08lX\n", img->name, - (unsigned long)img->flash_base, + image_found = false; + lowest_addr = 0xFFFFFFFF; + img = fis_work_block; + for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) { + if (img->u.name[0] != 0xFF) { + if ((img->flash_base >= last_addr) && (img->flash_base < lowest_addr)) { + lowest_addr = img->flash_base; + image_found = true; + image_indx = i; + } + } + } + if (image_found) { + img = fis_work_block; + img += image_indx; + diag_printf("%-16s 0x%08lX 0x%08lX 0x%08lX 0x%08lX\n", img->u.name, + (unsigned long)img->flash_base, #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK - show_cksums ? img->file_cksum : img->mem_base, - show_datalen ? img->data_length : img->size, + show_cksums ? img->file_cksum : (unsigned long)img->mem_base, + show_datalen ? img->data_length : img->size, #else - img->mem_base, - img->size, + (unsigned long)img->mem_base, + img->size, #endif - (unsigned long)img->entry_point); - } - last_addr = lowest_addr; + (unsigned long)img->entry_point); + } + last_addr = lowest_addr + 1; } while (image_found == true); } @@ -563,51 +767,51 @@ find_free(struct free_chunk *chunks) int num_chunks = 1; // Do not search the area reserved for pre-RedBoot systems: - fis_ptr = (CYG_ADDRESS *)((CYG_ADDRESS)flash_start + - CYGNUM_REDBOOT_FLASH_RESERVED_BASE); + 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; + chunks[num_chunks - 1].start = (CYG_ADDRESS)fis_ptr; + chunks[num_chunks - 1].end = (CYG_ADDRESS)fis_end; fis_read_directory(); - img = (struct fis_image_desc *) fis_work_block; + img = fis_work_block; for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) { - if (img->name[0] != (unsigned char)0xFF) { - // Figure out which chunk this is in and split it - for (idx = 0; idx < num_chunks; idx++) { - if ((img->flash_base >= chunks[idx].start) && - (img->flash_base <= chunks[idx].end)) { - if (img->flash_base == chunks[idx].start) { - chunks[idx].start += img->size; - if (chunks[idx].start >= chunks[idx].end) { - // This free chunk has collapsed - while (idx < (num_chunks-1)) { - 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 { - // 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; - } - } - chunks[idx].end = img->flash_base; - } - break; - } - } - } + if (img->u.name[0] != 0xFF) { + // Figure out which chunk this is in and split it + for (idx = 0; idx < num_chunks; idx++) { + if ((img->flash_base >= chunks[idx].start) && + (img->flash_base <= chunks[idx].end)) { + if (img->flash_base == chunks[idx].start) { + chunks[idx].start += img->size; + if (chunks[idx].start >= chunks[idx].end) { + // This free chunk has collapsed + while (idx < (num_chunks-1)) { + 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 { + // 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; + } + } + chunks[idx].end = img->flash_base; + } + break; + } + } + } } return num_chunks; } @@ -621,46 +825,48 @@ fis_free(int argc, char *argv[]) unsigned long *area_start; void *err_addr; + FLASH_Enable(flash_start, flash_end); // Do not search the area reserved for pre-RedBoot systems: - fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start + - CYGNUM_REDBOOT_FLASH_RESERVED_BASE); + 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; - } - area_start += flash_block_size / sizeof(CYG_ADDRESS); - } - fis_ptr = area_start; - } else { - fis_ptr += flash_block_size / sizeof(CYG_ADDRESS); - } + flash_read(fis_ptr, &flash_data, sizeof(unsigned long), &err_addr); + if (flash_data != 0xFFFFFFFF) { + if (area_start != fis_ptr) { + // Assume that this is something + diag_printf(" 0x%08x .. 0x%08x\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), &err_addr); + if (flash_data == 0xFFFFFFFF) { + break; + } + area_start += flash_block_size / sizeof(CYG_ADDRESS); + } + fis_ptr = area_start; + } else { + fis_ptr += flash_block_size / sizeof(CYG_ADDRESS); + } } if (area_start != fis_ptr) { - diag_printf(" 0x%08lX .. 0x%08lX\n", - (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr); + diag_printf(" 0x%08x .. 0x%08x\n", + (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr); } + FLASH_Disable(flash_start, flash_end); #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++) { - diag_printf(" 0x%08lX .. 0x%08lX\n", - (unsigned long)chunks[idx].start, - (unsigned long)chunks[idx].end); + for (idx = 0; idx < num_chunks; idx++) { + diag_printf(" 0x%08x .. 0x%08x\n", + chunks[idx].start, + chunks[idx].end); } #endif } @@ -675,39 +881,42 @@ fis_find_free(CYG_ADDRESS *addr, unsigned long length) void *err_addr; // Do not search the area reserved for pre-RedBoot systems: - fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start + - CYGNUM_REDBOOT_FLASH_RESERVED_BASE); + fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start + + CYGNUM_REDBOOT_FLASH_RESERVED_BASE); fis_end = (unsigned long *)(CYG_ADDRESS)flash_end; + FLASH_Enable(fis_ptr, fis_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; - } - } - // 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); - } - } + flash_read(fis_ptr, &flash_data, sizeof(unsigned long), &err_addr); + if (flash_data != 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; + } + } + // Find next blank block + area_start = fis_ptr; + while (area_start < fis_end) { + flash_read(area_start, &flash_data, sizeof(unsigned long), &err_addr); + if (flash_data == 0xFFFFFFFF) { + break; + } + area_start += flash_block_size / sizeof(CYG_ADDRESS); + } + fis_ptr = area_start; + } else { + fis_ptr += flash_block_size / sizeof(CYG_ADDRESS); + } + } + FLASH_Disable((void *)((CYG_ADDRESS)flash_start + + CYGNUM_REDBOOT_FLASH_RESERVED_BASE), fis_end); if (area_start != fis_ptr) { - if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) { - *addr = (CYG_ADDRESS)area_start; - return true; - } + if (fis_ptr - area_start >= length / sizeof(unsigned)) { + *addr = (CYG_ADDRESS)area_start; + return true; + } } return false; #else @@ -715,11 +924,11 @@ fis_find_free(CYG_ADDRESS *addr, unsigned long length) int idx, num_chunks; num_chunks = find_free(chunks); - for (idx = 0; idx < num_chunks; idx++) { - if ((chunks[idx].end - chunks[idx].start) >= length) { - *addr = (CYG_ADDRESS)chunks[idx].start; - return true; - } + for (idx = 0; idx < num_chunks; idx++) { + if (chunks[idx].end + 1 - chunks[idx].start >= length) { + *addr = (CYG_ADDRESS)chunks[idx].start; + return true; + } } return false; #endif @@ -745,214 +954,224 @@ fis_create(int argc, char *argv[]) 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; - } + init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, + &mem_addr, &mem_addr_set, "memory base address"); + init_opts(&opts[1], 'r', true, OPTION_ARG_TYPE_NUM, + &exec_addr, &exec_addr_set, "ram base address"); + init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM, + &entry_addr, &entry_addr_set, "entry point address"); + init_opts(&opts[3], 'f', true, OPTION_ARG_TYPE_NUM, + &flash_addr, &flash_addr_set, "FLASH memory base address"); + init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM, + &length, &length_set, "image length [in FLASH]"); + init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM, + &img_size, &img_size_set, "image size [actual data]"); + init_opts(&opts[6], 'n', false, OPTION_ARG_TYPE_FLG, + &no_copy, NULL, "don't copy from RAM to FLASH, just update directory"); + if (!scan_opts(argc, argv, 2, opts, 7, &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; - } - } + // 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; - } + (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 (!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; + !length_set || !name) { + fis_usage("required parameter missing"); + return; } if (!img_size_set) { - img_size = length; + 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; + 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; + ((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 (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 (strlen(name) >= sizeof(img->u.name)) { + diag_printf("Name is too long, must be less than %d chars\n", + 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 ((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", - (void*)flash_addr, (void*)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 - } - } - } + 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", + (void *)flash_addr, (void *)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 (i >= fisdir_size/sizeof(*img)) { - diag_printf("Can't find an empty slot in FIS directory!\n"); - return; - } + // 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 = fis_work_block; + for (i = 0; i < fisdir_size / sizeof(*img); i++, img++) { + if (img->u.name[0] == 0xFF) { + break; + } + } + if (i >= fisdir_size / sizeof(*img)) { + diag_printf("Can't find an empty slot in FIS directory!\n"); + return; + } } 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; - } - } + // 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) { + FLASH_Enable((void *)flash_addr, (void *)(flash_addr + length)); + // Erase area to be programmed + stat = flash_erase((void *)flash_addr, length, &err_addr); + FLASH_Disable((void *)flash_addr, (void *)(flash_addr + length)); + if (stat != 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 + FLASH_Enable((void *)flash_addr, (void *)(flash_addr + length)); + stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, + img_size, &err_addr); + FLASH_Disable((void *)flash_addr, (void *)(flash_addr + length)); + if (stat != 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 : (mem_addr_set ? mem_addr : flash_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; + // Update directory + memset(img, 0, sizeof(*img)); + strcpy(img->u.name, name); + img->flash_base = flash_addr; + img->mem_base = exec_addr_set ? exec_addr : (mem_addr_set ? mem_addr : flash_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(); + 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_start_update_directory(0); + fis_update_directory(0, 0); } } @@ -965,11 +1184,10 @@ fis_delete(int argc, char *argv[]) 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; - } + if (!scan_opts(argc, argv, 2, 0, 0, &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); @@ -998,23 +1216,24 @@ fis_delete(int argc, char *argv[]) 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; - } + if (i < num_reserved) { + diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->u.name); + return; + } + if (!verify_action("Delete image '%s'", name)) { + return; + } } else { - diag_printf("No image '%s' found\n", name); - return; + 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)); + if ((stat = flash_erase((void *)img->flash_base, img->size, &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(); + img->u.name[0] = 0xFF; + fis_start_update_directory(0); + fis_update_directory(0, 0); } } @@ -1026,104 +1245,142 @@ fis_load(int argc, char *argv[]) CYG_ADDRESS mem_addr; bool mem_addr_set = false; bool show_cksum = false; - struct option_info opts[3]; + bool load_ce = false; + struct option_info opts[4]; #if defined(CYGSEM_REDBOOT_FIS_CRC_CHECK) unsigned long cksum; #endif - int num_options; + int num_options = 0; #if defined(CYGPRI_REDBOOT_ZLIB_FLASH) || defined(CYGSEM_REDBOOT_FIS_CRC_CHECK) bool decompress = false; #endif void *err_addr; - init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, - (void *)&mem_addr, (bool *)&mem_addr_set, "memory [load] base address"); - init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG, - (void *)&show_cksum, (bool *)0, "display checksum"); - num_options = 2; + init_opts(&opts[num_options++], 'b', true, OPTION_ARG_TYPE_NUM, + &mem_addr, &mem_addr_set, "memory [load] base address"); + init_opts(&opts[num_options++], 'c', false, OPTION_ARG_TYPE_FLG, + &show_cksum, NULL, "display checksum"); +#ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT + init_opts(&opts[num_options++], 'w', false, OPTION_ARG_TYPE_FLG, + &load_ce, NULL, "parse as Windows CE image"); +#endif #ifdef CYGPRI_REDBOOT_ZLIB_FLASH - init_opts(&opts[num_options], 'd', false, OPTION_ARG_TYPE_FLG, - (void *)&decompress, 0, "decompress"); - num_options++; + init_opts(&opts[num_options++], 'd', false, OPTION_ARG_TYPE_FLG, + &decompress, 0, "decompress"); #endif - CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options"); + CYG_ASSERT(num_options <= num_options, "Too many options"); - if (!scan_opts(argc, argv, 2, opts, num_options, (void *)&name, OPTION_ARG_TYPE_STR, "image name")) - { - fis_usage("invalid arguments"); - return; + if (!scan_opts(argc, argv, 2, opts, num_options, &name, + OPTION_ARG_TYPE_STR, "image name")) { + fis_usage("invalid arguments"); + return; } - if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) { - diag_printf("No image '%s' found\n", name); - return; + if ((img = fis_lookup(name, NULL)) == NULL) { + diag_printf("No image '%s' found\n", name); + return; } - if (!mem_addr_set) { - mem_addr = img->mem_base; + if (!mem_addr_set || load_ce) { + mem_addr = img->mem_base; } // Load image from FLASH into RAM #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (!valid_address((void *)mem_addr)) { - diag_printf("Not a loadable image - try using -b ADDRESS option\n"); - return; + if (!load_ce) { + diag_printf("Not a loadable image - try using -b ADDRESS option\n"); + } else { + diag_printf("Not a loadable image\n"); + } + return; + } +#endif +#ifdef CYGBLD_BUILD_REDBOOT_WITH_WINCE_SUPPORT + if (load_ce) { + if (mem_addr_set) { + diag_printf("Warning: -b argument ignored for Windows CE image\n"); + } + FLASH_Enable((void *)img->flash_base, (void *)(img->flash_base + img->size)); + if (!ce_is_bin_image((void *)img->flash_base, img->size)) { + diag_printf("** Error: This does not seem to be a valid Windows CE image\n"); + return; + } + if (!ce_bin_load((void *)img->flash_base, img->size)) { + diag_printf("** Error: Failed to load Windows CE image\n"); + } + FLASH_Disable((void *)img->flash_base, (void *)(img->flash_base + img->size)); + // Set load address/top + load_address = mem_addr; + load_address_end = mem_addr + img->data_length; + return; } #endif #ifdef CYGPRI_REDBOOT_ZLIB_FLASH if (decompress) { - int err; - _pipe_t fis_load_pipe; - _pipe_t* p = &fis_load_pipe; - p->out_buf = (unsigned char*) mem_addr; - p->out_max = p->out_size = -1; - p->in_buf = (unsigned char*) img->flash_base; - p->in_avail = img->data_length; - - err = (*_dc_init)(p); - - if (0 == err) - err = (*_dc_inflate)(p); - - // Free used resources, do final translation of - // error value. - err = (*_dc_close)(p, err); - - if (0 != err && p->msg) { - diag_printf("decompression error: %s\n", p->msg); - } else { - diag_printf("Image loaded from %p-%p\n", (unsigned char *)mem_addr, p->out_buf); - } - - // Set load address/top - load_address = mem_addr; - load_address_end = (unsigned long)p->out_buf; - - // Reload fis directory - fis_read_directory(); + int err; + _pipe_t fis_load_pipe; + _pipe_t *p = &fis_load_pipe; + p->out_buf = (unsigned char*) mem_addr; + p->out_max = p->out_size = -1; + p->in_buf = (unsigned char*) img->flash_base; + p->in_avail = img->data_length; + + err = (*_dc_init)(p); + + if (0 == err) + err = (*_dc_inflate)(p); + + // Free used resources, do final translation of + // error value. + err = (*_dc_close)(p, err); + + if (0 != err && p->msg) { + diag_printf("decompression error: %s\n", p->msg); + } else { + diag_printf("Image loaded from %p-%p\n", (unsigned char *)mem_addr, p->out_buf); + } + + // Set load address/top + load_address = mem_addr; + load_address_end = (unsigned long)p->out_buf; + + // Reload fis directory + fis_read_directory(); } else // dangling block #endif - { - flash_read((void *)img->flash_base, (void *)mem_addr, img->data_length, (void **)&err_addr); - - // Set load address/top - load_address = mem_addr; - load_address_end = mem_addr + img->data_length; - } + { + int err; + + FLASH_Enable((void *)img->flash_base, (void *)(img->flash_base + img->size)); + err = flash_read((void *)img->flash_base, (void *)mem_addr, + img->data_length, &err_addr); + FLASH_Disable((void *)img->flash_base, (void *)(img->flash_base + img->size)); + if (err != FLASH_ERR_OK) { + diag_printf("** Error: Failed to load image from flash\n"); + return; + } + + // Set load address/top + load_address = mem_addr; + load_address_end = mem_addr + img->data_length; + } entry_address = (unsigned long)img->entry_point; #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK cksum = cyg_crc32((unsigned char *)mem_addr, img->data_length); if (show_cksum) { - diag_printf("Checksum: 0x%08lx\n", cksum); + diag_printf("Checksum: 0x%08lx\n", cksum); } // When decompressing, leave CRC checking to decompressor if (!decompress && img->file_cksum) { - if (cksum != img->file_cksum) { - diag_printf("** Warning - checksum failure. stored: 0x%08lx, computed: 0x%08lx\n", - img->file_cksum, cksum); - entry_address = (unsigned long)NO_MEMORY; - } + if (cksum != img->file_cksum) { + diag_printf("** Warning - checksum failure. stored: 0x%08lx, computed: 0x%08lx\n", + img->file_cksum, cksum); + entry_address = (unsigned long)NO_MEMORY; + } } #endif + diag_printf("image loaded 0x%08lx-0x%08lx, assumed entry at 0x%08lx\n", + load_address, load_address_end - 1, entry_address); } #endif // CYGOPT_REDBOOT_FIS @@ -1140,21 +1397,21 @@ fis_write(int argc, char *argv[]) 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]"); + init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, + &mem_addr, &mem_addr_set, "memory base address"); + init_opts(&opts[1], 'f', true, OPTION_ARG_TYPE_NUM, + &flash_addr, &flash_addr_set, "FLASH memory base address"); + init_opts(&opts[2], 'l', true, OPTION_ARG_TYPE_NUM, + &length, &length_set, "image length [in FLASH]"); if (!scan_opts(argc, argv, 2, opts, 3, 0, 0, 0)) - { - fis_usage("invalid arguments"); - return; - } + { + fis_usage("invalid arguments"); + return; + } if (!mem_addr_set || !flash_addr_set || !length_set) { - fis_usage("required parameter missing"); - return; + fis_usage("required parameter missing"); + return; } // Round up length to FLASH block size @@ -1162,45 +1419,46 @@ fis_write(int argc, char *argv[]) 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; + ((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; + 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); + ((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 (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 + 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; - } + // Erase area to be programmed + if ((stat = flash_erase((void *)flash_addr, length, &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; - } + // Now program it + stat = FLASH_PROGRAM((void *)flash_addr, (void *)mem_addr, length, &err_addr); + if (stat != 0) { + diag_printf("Can't program region at %p: %s\n", err_addr, flash_errmsg(stat)); + prog_ok = false; + } } } @@ -1215,38 +1473,38 @@ fis_erase(int argc, char *argv[]) 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; - } + init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, + &flash_addr, &flash_addr_set, "FLASH memory base address"); + init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, + &length, &length_set, "length"); + if (!scan_opts(argc, argv, 2, opts, 2, NULL, 0, NULL)) + { + fis_usage("invalid arguments"); + return; + } if (!flash_addr_set || !length_set) { - fis_usage("missing argument"); - return; + 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; + ((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; + 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 (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)); + if ((stat = flash_erase((void *)flash_addr, length, &err_addr)) != 0) { + diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat)); } } @@ -1264,38 +1522,39 @@ fis_lock(int argc, char *argv[]) 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; - } - + init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, + &flash_addr, &flash_addr_set, "FLASH memory base address"); + init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, + &length, &length_set, "length"); + if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name")) { + fis_usage("invalid arguments"); + return; + } +#ifdef CYGOPT_REDBOOT_FIS /* Get parameters from image if specified */ 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; - } + struct fis_image_desc *img; + if ((img = fis_lookup(name, NULL)) == NULL) { + diag_printf("No image '%s' found\n", name); + return; + } + + flash_addr = img->flash_base; + length = img->size; + } else +#endif + 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; + ((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_lock((void *)flash_addr, length, (void **)&err_addr)) != 0) { - diag_printf("Error locking at %p: %s\n", err_addr, flash_errmsg(stat)); + if ((stat = flash_lock((void *)flash_addr, length, &err_addr)) != 0) { + diag_printf("Error locking at %p: %s\n", err_addr, flash_errmsg(stat)); } } @@ -1311,38 +1570,39 @@ fis_unlock(int argc, char *argv[]) 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; - } - + init_opts(&opts[0], 'f', true, OPTION_ARG_TYPE_NUM, + &flash_addr, &flash_addr_set, "FLASH memory base address"); + init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, + &length, &length_set, "length"); + if (!scan_opts(argc, argv, 2, opts, 2, &name, OPTION_ARG_TYPE_STR, "image name")) { + fis_usage("invalid arguments"); + return; + } +#ifdef CYGOPT_REDBOOT_FIS 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; - } + struct fis_image_desc *img; + if ((img = fis_lookup(name, NULL)) == NULL) { + diag_printf("No image '%s' found\n", name); + return; + } + + flash_addr = img->flash_base; + length = img->size; + } else +#endif + 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; + ((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)); + if ((stat = flash_unlock((void *)flash_addr, length, &err_addr)) != 0) { + diag_printf("Error unlocking at %p: %s\n", err_addr, flash_errmsg(stat)); } } #endif @@ -1354,53 +1614,137 @@ void _flash_info(void) { 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); + diag_printf("FLASH: %p - 0x%x, %d blocks of 0x%08x bytes each.\n", + flash_start, (CYG_ADDRWORD)flash_end + 1, flash_num_blocks, flash_block_size); } -bool +/* Returns -1 on failure, 0 on success, 1 if it was successfull + but a failed fis update was detected */ +int 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); + int stat; + +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + struct fis_image_desc img0; + struct fis_image_desc img1; + int fis_update_was_interrupted = 0; + void *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"); + //try to check the alignment of version_count + CYG_ASSERT(((&img0.u.valid_info.version_count - &img0) % sizeof(unsigned long) == 0), + "alignment problem"); +#endif + 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 -1; + } + flash_get_limits(NULL, &flash_start, &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; + 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; - } + 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 -1; + } # else - workspace_end = (unsigned char *)(workspace_end-fisdir_size); - fis_work_block = workspace_end; + 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(); + 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 defined(CYGHWR_DEVS_FLASH_MXC_MULTI) && defined(MXCFLASH_SELECT_NAND) + extern int mxc_nand_fis_start(void); + if (IS_FIS_FROM_NAND()) { + fis_addr = (void *)((CYG_ADDRESS)flash_start + mxc_nand_fis_start()); + } +#endif + +#if defined(IMXFLASH_SELECT_SPI_NOR) + extern int mxc_spi_nor_fis_start(void); + if (IS_FIS_FROM_SPI_NOR()) { + fis_addr = (void *)((CYG_ADDRESS)flash_start + mxc_spi_nor_fis_start()); + } +#endif + +#if defined(MXCFLASH_SELECT_MMC) + if (IS_FIS_FROM_MMC()) { + fis_addr = (void *)REDBOOT_IMAGE_SIZE; + } +#endif + + if (((CYG_ADDRESS)fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) { + diag_printf("FIS directory doesn't fit\n"); + return -1; + } +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + + if (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK < 0) { + redundant_fis_addr = (void *)((CYG_ADDRESS)flash_end + 1 + + (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK * + flash_block_size)); + } else { + redundant_fis_addr = (void *)((CYG_ADDRESS)flash_start + + (CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK * + flash_block_size)); + } + + if (((CYG_ADDRESS)redundant_fis_addr + fisdir_size - 1) > (CYG_ADDRESS)flash_end) { + diag_printf("Redundant FIS directory doesn't fit\n"); + return -1; + } + FLASH_READ(fis_addr, &img0, sizeof(img0), &err_addr); + 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) { + memset(&img0, 0, sizeof(img0)); + } + + if (strncmp(img1.u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC, + CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH) != 0) { + memset(&img1, 0, sizeof(img0)); + } + +#ifdef REDBOOT_FLASH_REVERSE_BYTEORDER + img0.u.valid_info.version_count = CYG_SWAP32(img0.u.valid_info.version_count); + img1.u.valid_info.version_count = CYG_SWAP32(img1.u.valid_info.version_count); +#endif + + if (fis_get_valid_buf(&img0, &img1, &fis_update_was_interrupted) == 1) { + // Valid, so swap primary and secondary + void *tmp; + tmp = fis_addr; + fis_addr = redundant_fis_addr; + redundant_fis_addr = tmp; + } +#endif + fis_read_directory(); +#endif + } +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + if (fis_update_was_interrupted) + return 1; + else + return 0; +#else + return 0; #endif - } - return true; } // Wrapper to avoid compiler warnings @@ -1421,19 +1765,17 @@ do_fis(int argc, char *argv[]) struct cmd *cmd; if (argc < 2) { - fis_usage("too few arguments"); - return; + fis_usage("too few arguments"); + return; } - if (!do_flash_init()) { - diag_printf("Sorry, no FLASH memory is available\n"); - return; + if (do_flash_init() < 0) { + diag_printf("Sorry, no FLASH memory is available\n"); + return; } - if ((cmd = cmd_search(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__, - argv[1])) != (struct cmd *)0) { - (cmd->fun)(argc, argv); - return; + if ((cmd = cmd_search(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__, + argv[1])) != NULL) { + (cmd->fun)(argc, argv); + return; } fis_usage("unrecognized command"); } - -// EOF flash.c