Index: redboot/current/ChangeLog =================================================================== RCS file: /cvs/ecos/ecos/packages/redboot/current/ChangeLog,v retrieving revision 1.213 diff -u -r1.213 ChangeLog --- redboot/current/ChangeLog 13 Oct 2004 21:22:53 -0000 1.213 +++ redboot/current/ChangeLog 22 Oct 2004 19:12:13 -0000 @@ -1,3 +1,13 @@ +2004-10-22 Alexander Neundorf + Andrew Lunn + + * include/fis.h + * src/flash.c: Added basic support for a redundant FIS directory. + Currently there is no way to actually write a redundant directory, + but if such a directory where to exist, we can check if the + primary directory is valid and if not use the redundant one + instead. + 2004-10-10 Iztok Zupet * cdl/redboot.cdl: added CYGSEM_REDBOOT_DISK_IDE_VMWARE option. Index: redboot/current/cdl/redboot.cdl =================================================================== RCS file: /cvs/ecos/ecos/packages/redboot/current/cdl/redboot.cdl,v retrieving revision 1.68 diff -u -r1.68 redboot.cdl --- redboot/current/cdl/redboot.cdl 13 Oct 2004 21:22:53 -0000 1.68 +++ redboot/current/cdl/redboot.cdl 22 Oct 2004 19:12:15 -0000 @@ -638,7 +638,33 @@ Negative block numbers count backwards from the last block. eg 2 means block 2, -2 means the last but one block." } - + + cdl_component CYGOPT_REDBOOT_REDUNDANT_FIS { + display "Redundant Flash Image System Directory Support" + default_value 0 + requires { 0 == CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG } + description " + This option enables the use of a redundant FIR + directory within RedBoot. If enabled a flash block + will be reserved for a second copy of the fis + directory. Doing this allow for power failure safe + updates of the directory by the application." + + cdl_option CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK { + display "Flash block containing the backup Directory" + flavor data + default_value (-3) + requires { CYGNUM_REDBOOT_FIS_REDUNDANT_DIRECTORY_BLOCK != + CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK } + description " + Which block of flash should hold the redundant + directory information. Positive numbers are + absolute block numbers. Negative block numbers + count backwards from the last block. eg 2 means + block 2, -2 means the last but one block." + } + } + cdl_option CYGOPT_REDBOOT_FIS_RESERVED_BASE { display "Pseudo-file to describe reserved area" active_if { 0 != CYGNUM_REDBOOT_FLASH_RESERVED_BASE } Index: redboot/current/include/fis.h =================================================================== RCS file: /cvs/ecos/ecos/packages/redboot/current/include/fis.h,v retrieving revision 1.6 diff -u -r1.6 fis.h --- redboot/current/include/fis.h 24 Aug 2002 11:20:55 -0000 1.6 +++ redboot/current/include/fis.h 22 Oct 2004 19:12:15 -0000 @@ -75,5 +75,22 @@ struct fis_image_desc *fis_lookup(char *name, int *num); +// These will need to move somewhere else when the fisfs needs to use +// the following definitions. +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS +#define CYG_REDBOOT_RFIS_VALID_MAGIC ".FisValid" //exactly 10 bytes + +#define CYG_REDBOOT_RFIS_VALID (0xa5a5) +#define CYG_REDBOOT_RFIS_IN_PROGRESS (0xfdfd) +#define CYG_REDBOOT_RFIS_EMPTY (0xffff) + +struct fis_valid_info +{ + unsigned long version_count; + unsigned short valid_flag; +}; +#endif // CYGOPT_REDBOOT_REDUNDANT_FIS + #endif // CYGOPT_REDBOOT_FIS #endif // _FIS_H_ + Index: redboot/current/src/flash.c =================================================================== RCS file: /cvs/ecos/ecos/packages/redboot/current/src/flash.c,v retrieving revision 1.69 diff -u -r1.69 flash.c --- redboot/current/src/flash.c 1 Sep 2004 21:21:30 -0000 1.69 +++ redboot/current/src/flash.c 22 Oct 2004 19:12:17 -0000 @@ -169,6 +169,9 @@ #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 @@ -273,6 +276,31 @@ fis_endian_fixup(fis_work_block); } +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS +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, flash_block_size, + (void **)&err_addr); +#endif + if ((stat = flash_erase(redundant_fis_addr, flash_block_size, + (void **)&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); +#endif +} +#endif + static void fis_init(int argc, char *argv[]) { @@ -283,6 +311,9 @@ struct option_info opts[1]; CYG_ADDRESS redboot_flash_start; unsigned long redboot_image_size; +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + struct fis_valid_info fvi; +#endif init_opts(&opts[0], 'f', false, OPTION_ARG_TYPE_FLG, (void *)&full_init, (bool *)0, "full initialization, erases all of flash"); @@ -301,9 +332,23 @@ redboot_image_size = flash_block_size > MIN_REDBOOT_IMAGE_SIZE ? flash_block_size : MIN_REDBOOT_IMAGE_SIZE; - // Create a pseudo image for RedBoot img = (struct fis_image_desc *)fis_work_block; memset(img, 0xFF, fisdir_size); // Start with erased data + +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + CYG_ASSERT(sizeof(fvi)+sizeof(EFIS_MAGIC) <= sizeof(img->name), + "Size mismatch"); + + //create the valid flag entry + memset(img, 0, sizeof(struct fis_image_desc)); + strcpy(img->name, CYG_REDBOOT_RFIS_VALID_MAGIC); + fvi.valid_flag=CYG_REDBOOT_RFIS_VALID; + fvi.version_count=0; + memcpy(&img->name[sizeof(CYG_REDBOOT_RFIS_VALID_MAGIC)],&fvi,sizeof(fvi)); + img++; +#endif + + // Create a pseudo image for RedBoot #ifdef CYGOPT_REDBOOT_FIS_RESERVED_BASE memset(img, 0, sizeof(*img)); strcpy(img->name, "(reserved)"); @@ -361,6 +406,14 @@ img->mem_base = (CYG_ADDRESS)fis_addr; img->size = fisdir_size; img++; +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + memset(img, 0, sizeof(*img)); + strcpy(img->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 @@ -475,6 +528,9 @@ #endif } fis_update_directory(); +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + fis_erase_redundant_directory(); +#endif } static void @@ -1355,7 +1411,13 @@ do_flash_init(void) { int stat; - +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + void *err_addr=0; + struct fis_valid_info fvi0; + struct fis_valid_info fvi1; + struct fis_image_desc img0; + struct fis_image_desc img1; +#endif if (!__flash_init) { __flash_init = 1; if ((stat = flash_init(diag_printf)) != 0) { @@ -1379,17 +1441,79 @@ 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 + + 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; } + +#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 false; + } + + // Read the first img from each directory and see if it + // contains the appropriate magic + FLASH_READ(fis_addr, &img0, sizeof(img0), (void **)&err_addr); + FLASH_READ(redundant_fis_addr, &img1, sizeof(img1), (void **)&err_addr); + + if (!strncmp(img0.name, CYG_REDBOOT_RFIS_VALID_MAGIC, + sizeof(CYG_REDBOOT_RFIS_VALID_MAGIC))) { + memcpy(&fvi0,&img0.name[sizeof(CYG_REDBOOT_RFIS_VALID_MAGIC)], + sizeof(fvi0)); + } else { + memset(&fvi0, 0, sizeof(fvi0)); + } + if (!strncmp(img1.name, CYG_REDBOOT_RFIS_VALID_MAGIC, + sizeof(CYG_REDBOOT_RFIS_VALID_MAGIC))) { + memcpy(&fvi1,&img1.name[sizeof(CYG_REDBOOT_RFIS_VALID_MAGIC)], + sizeof(fvi1)); + } else { + memset(&fvi1, 0, sizeof(fvi1)); + } + +#ifdef REDBOOT_FLASH_REVERSE_BYTEORDER + fvi0.valid_flag = CYG_SWAP32(fvi0.valid_flag); + fvi0.version_count = CYG_SWAP32(fvi0.version_count); + fvi1.valid_flag = CYG_SWAP32(fvi1.valid_flag); + fvi1.version_count = CYG_SWAP32(fvi1.version_count); +#endif + // Now check if the primary FIS directory is valid + if (fvi0.valid_flag != CYG_REDBOOT_RFIS_VALID) { + // Primary is not valid, try the secondary + if (fvi1.valid_flag == CYG_REDBOOT_RFIS_VALID) { + // Valid, so swap primary and secondary + void * tmp; + tmp = fis_addr; + fis_addr = redundant_fis_addr; + redundant_fis_addr = tmp; + } else { + // Both are invalid, stick with the invalid primary + } + } +#endif fis_read_directory(); #endif }