diff -rbup current.orig/ChangeLog current/ChangeLog --- current.orig/ChangeLog Wed Oct 13 23:22:53 2004 +++ current/ChangeLog Tue Oct 26 18:29:22 2004 @@ -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. Only in current: ChangeLog~ diff -rbup current.orig/cdl/redboot.cdl current/cdl/redboot.cdl --- current.orig/cdl/redboot.cdl Wed Oct 13 23:22:53 2004 +++ current/cdl/redboot.cdl Tue Oct 26 17:58:01 2004 @@ -638,6 +638,32 @@ cdl_package CYGPKG_REDBOOT { 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 FIS + 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" Only in current/cdl: redboot.cdl~ diff -rbup current.orig/include/fis.h current/include/fis.h --- current.orig/include/fis.h Sat Aug 24 13:20:55 2002 +++ current/include/fis.h Tue Oct 26 17:56:07 2004 @@ -58,11 +58,35 @@ #ifdef CYGOPT_REDBOOT_FIS #include +// 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_LENGTH 10 +#define CYG_REDBOOT_RFIS_VALID_MAGIC ".FisValid" //exactly 10 bytes + +#define CYG_REDBOOT_RFIS_VALID (0xa5) +#define CYG_REDBOOT_RFIS_IN_PROGRESS (0xfd) +#define CYG_REDBOOT_RFIS_EMPTY (0xff) + +struct fis_valid_info +{ + char magic_name[CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH]; + unsigned char valid_flag[2]; //this should be safe for all alignment issues + unsigned long version_count; +}; +#endif // CYGOPT_REDBOOT_REDUNDANT_FIS + #define FIS_IMAGE_DESC_SIZE_UNPADDED \ (16 + 4 * sizeof(unsigned long) + 3 * sizeof(CYG_ADDRESS)) struct fis_image_desc { + union + { unsigned char name[16]; // Null terminated name +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + struct fis_valid_info valid_info; +#endif + } u; CYG_ADDRESS flash_base; // Address within FLASH of image CYG_ADDRESS mem_base; // Address in memory where it executes unsigned long size; // Length of image Only in current/include: fis.h~ diff -rbup current.orig/src/flash.c current/src/flash.c --- current.orig/src/flash.c Wed Sep 1 23:21:30 2004 +++ current/src/flash.c Tue Oct 26 18:16:16 2004 @@ -169,6 +169,9 @@ 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 @@ -233,8 +236,8 @@ 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->name[0] != (unsigned char)0xFF) && - (strcasecmp(name, img->name) == 0)) { + if ((img->u.name[0] != (unsigned char)0xFF) && + (strcasecmp(name, img->u.name) == 0)) { if (num) *num = i; return img; } @@ -273,6 +276,57 @@ fis_update_directory(void) fis_endian_fixup(fis_work_block); } +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + +int +fis_get_valid_buf(struct fis_image_desc* img0, struct fis_image_desc* img1) +{ + if (strncmp(img1->u.valid_info.magic_name, CYG_REDBOOT_RFIS_VALID_MAGIC, CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH)!=0) //buf0 must be valid + 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 + 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 + 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 + return 1; + + //now check the version + if (img1->u.valid_info.version_count == (img0->u.valid_info.version_count+1)) //buf1 must be valid + return 1; + + return 0; +} + +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[]) { @@ -301,12 +355,23 @@ fis_init(int argc, char *argv[]) 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 + //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 +380,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 +393,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 +403,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 +413,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 +421,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. @@ -475,6 +550,9 @@ fis_init(int argc, char *argv[]) #endif } fis_update_directory(); +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + fis_erase_redundant_directory(); +#endif } static void @@ -523,7 +601,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->name[0] != (unsigned char)0xFF) { + if (img->u.name[0] != (unsigned char)0xFF) { if ((img->flash_base > last_addr) && (img->flash_base < lowest_addr)) { lowest_addr = img->flash_base; image_found = true; @@ -534,7 +612,7 @@ fis_list(int argc, char *argv[]) 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, + diag_printf("%-16s 0x%08lX 0x%08lX 0x%08lX 0x%08lX\n", img->u.name, img->flash_base, #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK show_cksums ? img->file_cksum : img->mem_base, @@ -572,7 +650,7 @@ find_free(struct free_chunk *chunks) 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) { + if (img->u.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) && @@ -836,8 +914,8 @@ fis_create(int argc, char *argv[]) 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)); + 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) { @@ -902,7 +980,7 @@ fis_create(int argc, char *argv[]) // 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) { + if (img->u.name[0] == (unsigned char)0xFF) { break; } } @@ -931,7 +1009,7 @@ fis_create(int argc, char *argv[]) if (prog_ok) { // Update directory memset(img, 0, sizeof(*img)); - strcpy(img->name, name); + strcpy(img->u.name, name); img->flash_base = flash_addr; img->mem_base = exec_addr_set ? exec_addr : (flash_addr_set ? flash_addr : mem_addr); img->entry_point = entry_addr_set ? entry_addr : (CYG_ADDRESS)entry_address; // Hope it's been set @@ -992,7 +1070,7 @@ 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); + diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->u.name); return; } if (!verify_action("Delete image '%s'", name)) { @@ -1006,7 +1084,7 @@ fis_delete(int argc, char *argv[]) if ((stat = flash_erase((void *)img->flash_base, img->size, (void **)&err_addr)) != 0) { diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat)); } else { - img->name[0] = (unsigned char)0xFF; + img->u.name[0] = (unsigned char)0xFF; fis_update_directory(); } } @@ -1356,6 +1434,19 @@ do_flash_init(void) { int stat; + void *err_addr; +#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS + struct fis_image_desc img0; + struct fis_image_desc img1; + + //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((((unsigned long)&img0.u.valid_info.version_count - (unsigned long)&img0) % sizeof(unsigned long) == 0), "alignment problem"); +#endif + + + if (!__flash_init) { __flash_init = 1; if ((stat = flash_init(diag_printf)) != 0) { @@ -1390,6 +1481,47 @@ do_flash_init(void) 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; + } + FLASH_READ(fis_addr, &img0, sizeof(img0), (void **)&err_addr); + FLASH_READ(redundant_fis_addr, &img1, sizeof(img1), (void **)&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)==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 } Only in current/src: flash.c~