This is the mail archive of the ecos-patches@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RedBoot FIS improvements


>From Alexander Neundorf - proposed quite a while ago and discussed
over the last year [or so].

-- 
------------------------------------------------------------
Gary Thomas                 |  Consulting for the
MLB Associates              |    Embedded world
------------------------------------------------------------
Index: hal/common/current/ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/hal/common/current/ChangeLog,v
retrieving revision 1.112
diff -u -5 -p -r1.112 ChangeLog
--- hal/common/current/ChangeLog	9 May 2006 15:28:56 -0000	1.112
+++ hal/common/current/ChangeLog	9 May 2006 15:47:45 -0000
@@ -1,10 +1,15 @@
 2006-05-09  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* src/hal_if.c (cyg_hal_diag_mangler_gdb_flush): Fix compiler
 	warning about signed/unsigned.
 
+2006-04-19  Alexander Neundorf <alexander.neundorf@jenoptik.com
+
+	* include/hal_if.h, src/hal_if.c: add a VV call for modifying
+        the FIS table from eCos applications
+
 2005-06-27  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* include/hal_tables.h (CYG_HAL_TABLE_{QUALIFIED_}ENTRY): added
 	CYGBLD_ATTRIB_USED so that gcc 3.4.4 does not discard entries
 	which are not refereced explicitly. Problem reported by
Index: hal/common/current/include/hal_if.h
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/hal/common/current/include/hal_if.h,v
retrieving revision 1.24
diff -u -5 -p -r1.24 hal_if.h
--- hal/common/current/include/hal_if.h	12 Aug 2004 13:04:48 -0000	1.24
+++ hal/common/current/include/hal_if.h	9 May 2006 15:49:51 -0000
@@ -365,12 +365,13 @@ __call_COMM1(IF_GETC_TIMEOUT, cyg_bool, 
 #define CYGNUM_CALL_IF_DELAY_US                   18
 #define CYGNUM_CALL_IF_DBG_DATA                   19
 #define CYGNUM_CALL_IF_FLASH_CFG_OP               20
 #define CYGNUM_CALL_IF_MONITOR_RETURN             21
 #define CYGNUM_CALL_IF_FLASH_FIS_OP               22
+#define CYGNUM_CALL_IF_FLASH_FIS_OP2              23
 
-#define CYGNUM_CALL_IF_LAST_ENTRY                 CYGNUM_CALL_IF_FLASH_FIS_OP
+#define CYGNUM_CALL_IF_LAST_ENTRY                 CYGNUM_CALL_IF_FLASH_FIS_OP2
 
 #define CYGNUM_CALL_IF_INSTALL_BPT_FN             35
 
 #define CYGNUM_CALL_IF_TABLE_SIZE                 64
 
@@ -424,10 +425,26 @@ typedef int __call_if_console_interrupt_
 typedef void (__call_if_delay_us_t)(cyg_int32 usecs);
 typedef void (__call_if_install_bpt_fn_t)(void *__epc);
 typedef char *__call_if_monitor_version_t;
 typedef void (__call_if_monitor_return_t)(int status);
 typedef cyg_bool (__call_if_flash_fis_op_fn_t)(int __oper, char *__name, void *__val);
+
+//
+// This structure is used to pass parameters to/from the fis routines
+//
+struct fis_table_entry {
+   unsigned char name[16];
+   CYG_ADDRESS   flash_base;
+   CYG_ADDRESS   mem_base;
+   unsigned long size;
+   CYG_ADDRESS   entry_point;
+   unsigned long data_length;
+   unsigned long desc_cksum;
+   unsigned long file_cksum;
+};
+
+typedef int (__call_if_flash_fis_op2_fn_t)(int __oper, unsigned int index, struct fis_table_entry *__fis_entry);
 //
 // This structure is used to pass parameters to/from the fconfig routines.
 // This allows a single virtual vector interface, with widely varying functionality
 //
 struct cyg_fconfig {
@@ -688,10 +705,24 @@ __call_VV3(CYGNUM_CALL_IF_FLASH_FIS_OP, 
 #define CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY_POINT (3)
 #define CYGNUM_CALL_IF_FLASH_FIS_GET_DATA_LENGTH (4)
 #define CYGNUM_CALL_IF_FLASH_FIS_GET_DESC_CKSUM  (5)
 #define CYGNUM_CALL_IF_FLASH_FIS_GET_FILE_CKSUM  (6)
 
+#define CYGACC_CALL_IF_FLASH_FIS_OP2(_o_,_k_,_d_) \
+ CYGACC_CALL_VV3(__call_if_flash_fis_op2_fn_t*, CYGNUM_CALL_IF_FLASH_FIS_OP2, (_o_),(_k_),(_d_))
+__call_VV3(CYGNUM_CALL_IF_FLASH_FIS_OP2, __call_if_flash_fis_op2_fn_t, int, int, unsigned int, struct fis_table_entry *)
+#define CYGACC_CALL_IF_FLASH_FIS_OP2_SET(_x_) \
+ hal_virtual_vector_table[CYGNUM_CALL_IF_FLASH_FIS_OP2]=(CYG_ADDRWORD)(_x_)
+#define CYGNUM_CALL_IF_FLASH_FIS_GET_VERSION     (0)
+#define CYGNUM_CALL_IF_FLASH_FIS_INIT            (1)
+#define CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY_COUNT (2)
+#define CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY       (3)
+#define CYGNUM_CALL_IF_FLASH_FIS_START_UPDATE    (4)
+#define CYGNUM_CALL_IF_FLASH_FIS_FINISH_UPDATE   (5)
+#define CYGNUM_CALL_IF_FLASH_FIS_MODIFY_ENTRY    (6)
+
+
 
 // These need to be kept uptodate with the (unadorned) masters
 // in RedBoot's flash_config.h:
 #define CYGNUM_FLASH_CFG_TYPE_CONFIG_EMPTY   0
 #define CYGNUM_FLASH_CFG_TYPE_CONFIG_BOOL    1
Index: hal/common/current/src/hal_if.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/hal/common/current/src/hal_if.c,v
retrieving revision 1.29
diff -u -5 -p -r1.29 hal_if.c
--- hal/common/current/src/hal_if.c	9 May 2006 15:28:56 -0000	1.29
+++ hal/common/current/src/hal_if.c	9 May 2006 15:49:39 -0000
@@ -172,10 +172,98 @@ flash_fis_op( int op, char *name, void *
         }
     }
     CYGARC_HAL_RESTORE_GP();
     return res;
 }
+
+#include <cyg/io/flash.h>
+
+extern int __flash_init;
+extern int fisdir_size;
+extern int flash_block_size;
+extern void* fis_addr;
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+extern void* redundant_fis_addr;
+#endif
+extern void* fis_work_block;
+extern int do_flash_init(void);
+extern int fis_start_update_directory(int autolock);
+extern int fis_update_directory(int autolock, int error);
+
+static __call_if_flash_fis_op2_fn_t flash_fis_op2;
+
+static int
+flash_fis_op2( int op, unsigned int index, struct fis_table_entry *entry)
+{
+   int res=0;
+   CYGARC_HAL_SAVE_GP();
+   switch ( op ) {
+      case CYGNUM_CALL_IF_FLASH_FIS_GET_VERSION:
+         res=CYG_REDBOOT_FIS_VERSION;
+         break;
+      case CYGNUM_CALL_IF_FLASH_FIS_INIT:
+         __flash_init=0;  //force reinitialization
+         res=do_flash_init();
+         break;
+      case CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY_COUNT:
+         res=fisdir_size / sizeof(struct fis_image_desc);
+         break;
+      case CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY:
+         {
+            struct fis_image_desc* img = (struct fis_image_desc *)fis_work_block;
+            CYG_ASSERT(entry!=0, "fis_table_entry == 0 !");
+            memcpy(entry->name, img[index].u.name, 16);
+            entry->flash_base=img[index].flash_base;
+            entry->mem_base=img[index].mem_base;
+            entry->size=img[index].size;
+            entry->entry_point=img[index].entry_point;
+            entry->data_length=img[index].data_length;
+            entry->desc_cksum=img[index].desc_cksum;
+            entry->file_cksum=img[index].file_cksum;
+            res=0;
+         }
+         break;
+      case CYGNUM_CALL_IF_FLASH_FIS_START_UPDATE:
+         fis_start_update_directory(1);
+         break;
+      case CYGNUM_CALL_IF_FLASH_FIS_FINISH_UPDATE:
+         fis_update_directory(1, index);
+         break;
+      case CYGNUM_CALL_IF_FLASH_FIS_MODIFY_ENTRY:
+         {
+            res=0;
+            if (entry->name[0]!=0xff)
+            {
+               if ((entry->size==0)
+                   || ((entry->size % flash_block_size) !=0)
+                   || (flash_verify_addr((void*)entry->flash_base)!=0)
+                   || (flash_verify_addr((void*)(entry->flash_base+entry->size-1))!=0)
+                   || (entry->size < entry->data_length))
+                  res=-1;
+            }
+
+            if (res==0)
+            {
+               struct fis_image_desc* img = (struct fis_image_desc *)fis_work_block;
+               memcpy(img[index].u.name, entry->name, 16);
+               img[index].flash_base=entry->flash_base;
+               img[index].mem_base=entry->mem_base;
+               img[index].size=entry->size;
+               img[index].entry_point=entry->entry_point;
+               img[index].data_length=entry->data_length;
+               img[index].desc_cksum=entry->desc_cksum;
+               img[index].file_cksum=entry->file_cksum;
+            }
+         }
+         break;
+      default:
+         break;
+   }
+   CYGARC_HAL_RESTORE_GP();
+   return res;
+}
+
 #endif
 
 //----------------------------
 // Delay uS
 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_DELAY_US
@@ -976,10 +1064,11 @@ hal_if_init(void)
     CYGACC_CALL_IF_FLASH_CFG_OP_SET(flash_config_op);
 #endif
 
 #ifdef CYGOPT_REDBOOT_FIS
     CYGACC_CALL_IF_FLASH_FIS_OP_SET(flash_fis_op);
+    CYGACC_CALL_IF_FLASH_FIS_OP2_SET(flash_fis_op2);
 #endif
 
     // Data entries not currently supported in eCos
 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_DATA
     CYGACC_CALL_IF_DBG_DATA_SET(0);
Index: redboot/current/ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/ChangeLog,v
retrieving revision 1.242
diff -u -5 -p -r1.242 ChangeLog
--- redboot/current/ChangeLog	7 Apr 2006 23:00:00 -0000	1.242
+++ redboot/current/ChangeLog	9 May 2006 15:34:01 -0000
@@ -1,5 +1,11 @@
+2006-04-19 Alexander Neundorf <alexander.neundorf@jenoptik.com>
+	* src/flash.c, src/main.c, src/fconfig.c: 
+        * include/fis.h, include/redboot.h:
+        * cdl/redboot.cdl:
+        add support for redundant FIS tables, configurable via CYGOPT_REDBOOT_REDUNDANT_FIS
+
 2006-04-07  Grant Edwards <grante@visi.com>
 
 	* src/net/net_io.c (net_io_getc_nonblock): 
 	Handle TELNET_WILL (reject same as TELNET_DO)
 
Index: redboot/current/cdl/redboot.cdl
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/cdl/redboot.cdl,v
retrieving revision 1.74
diff -u -5 -p -r1.74 redboot.cdl
--- redboot/current/cdl/redboot.cdl	25 Feb 2006 14:21:12 -0000	1.74
+++ redboot/current/cdl/redboot.cdl	9 May 2006 15:34:01 -0000
@@ -689,10 +689,36 @@ cdl_package CYGPKG_REDBOOT {
                       numbers.  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"
                     active_if       { 0 != CYGNUM_REDBOOT_FLASH_RESERVED_BASE }
                     default_value   1
                     description "
Index: redboot/current/include/fis.h
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/include/fis.h,v
retrieving revision 1.6
diff -u -5 -p -r1.6 fis.h
--- redboot/current/include/fis.h	24 Aug 2002 11:20:55 -0000	1.6
+++ redboot/current/include/fis.h	9 May 2006 15:33:59 -0000
@@ -56,15 +56,44 @@
 
 #include <pkgconf/redboot.h>
 #ifdef CYGOPT_REDBOOT_FIS
 #include <cyg/infra/cyg_type.h>
 
+//the version can be tested via the VV calls to check for compatibility
+#define CYG_REDBOOT_FIS_VERSION      (1)
+
+// the following defines will be used if RedBoot is configured
+// with support for redundant FIS tables, which enable failsafe updating
+#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)       // this FIS table is valid, the only "good" value
+#define CYG_REDBOOT_RFIS_IN_PROGRESS (0xfd)       // this FIS table is being modified
+#define CYG_REDBOOT_RFIS_EMPTY       (0xff)       // this FIS table is empty
+
+struct fis_valid_info
+{
+   char magic_name[CYG_REDBOOT_RFIS_VALID_MAGIC_LENGTH];
+   unsigned char valid_flag[2];   // one of the flags defined above
+   unsigned long version_count;   // with each successfull update the version count will increase by 1
+};
+
+#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
     CYG_ADDRESS   entry_point;   // Execution entry point
     unsigned long data_length;   // Length of actual data
Index: redboot/current/include/redboot.h
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/include/redboot.h,v
retrieving revision 1.35
diff -u -5 -p -r1.35 redboot.h
--- redboot/current/include/redboot.h	8 Sep 2005 12:14:31 -0000	1.35
+++ redboot/current/include/redboot.h	9 May 2006 15:34:01 -0000
@@ -87,11 +87,11 @@ EXTERN struct _mem_segment {
     unsigned char *start, *end;
 } mem_segments[CYGBLD_REDBOOT_MAX_MEM_SEGMENTS];
 #define NO_MEMORY (unsigned char *)0xFFFFFFFF
 EXTERN bool valid_address(unsigned char *addr);
 EXTERN void cyg_plf_memory_segment(int seg, unsigned char **start, unsigned char **end);
-EXTERN unsigned char *workspace_start, *workspace_end;
+EXTERN unsigned char *workspace_start, *workspace_end, *workspace_end_init;
 
 // Data squirreled away after a load operation
 EXTERN unsigned long entry_address;
 EXTERN unsigned long load_address;
 EXTERN unsigned long load_address_end;
Index: redboot/current/src/fconfig.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/src/fconfig.c,v
retrieving revision 1.12
diff -u -5 -p -r1.12 fconfig.c
--- redboot/current/src/fconfig.c	6 Jul 2005 18:41:21 -0000	1.12
+++ redboot/current/src/fconfig.c	9 May 2006 15:34:01 -0000
@@ -73,11 +73,11 @@ externC void read_eeprom(void *buf, int 
 #ifdef CYGSEM_REDBOOT_PLF_ESA_VALIDATE
 externC bool cyg_plf_redboot_esa_validate(unsigned char *val);
 #endif
 
 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
-externC bool do_flash_init(void);
+externC int do_flash_init(void);
 externC int flash_read(void *flash_base, void *ram_base, int len, void **err_address);
 #endif
 
 // Round a quantity up
 #define _rup(n,s) ((((n)+(s-1))/s)*s)
@@ -1135,11 +1135,11 @@ load_flash_config(void)
     cfg_temp -= sizeof(struct _config);  // Space for readonly copy of config data
     readonly_config = (struct _config *)cfg_temp;
 #endif
     workspace_end = cfg_temp;
 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
-    if (!do_flash_init()) return;
+    if (do_flash_init()<0) return;
 #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
     cfg_size = _rup(sizeof(struct _config), sizeof(struct fis_image_desc));
     if ((fisdir_size-cfg_size) < (CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_COUNT *
                                   CYGNUM_REDBOOT_FIS_DIRECTORY_ENTRY_SIZE)) {
         // Too bad this can't be checked at compile/build time
Index: redboot/current/src/flash.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/src/flash.c,v
retrieving revision 1.78
diff -u -5 -p -r1.78 flash.c
--- redboot/current/src/flash.c	4 Apr 2006 16:15:32 -0000	1.78
+++ redboot/current/src/flash.c	9 May 2006 15:34:01 -0000
@@ -167,10 +167,13 @@ RedBoot_nested_cmd("fis", 
 void *flash_start, *flash_end;
 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
@@ -231,51 +234,204 @@ 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 ((img->u.name[0] != (unsigned char)0xFF) &&
+            (strcasecmp(name, img->u.name) == 0)) {
             if (num) *num = i;
             return img;
         }
     }
     return (struct fis_image_desc *)0;
 }
 
-void
-fis_update_directory(void)
+int fis_start_update_directory(int autolock)
 {
-    int blk_size = fisdir_size;
+#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
+
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+   struct fis_image_desc* img=NULL;
+   void* err_addr=NULL;
+   void* tmp_fis_addr=NULL;
+
+   /*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=(struct fis_image_desc*)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....
+   if (do_autolock)
+      flash_unlock((void *)fis_addr, fisdir_size, (void **)&err_addr);
+
+   flash_erase(fis_addr, fisdir_size, (void **)&err_addr);
+   //now magic is 0xffffffff
+   fis_endian_fixup(fis_work_block);
+   flash_program(fis_addr, fis_work_block, flash_block_size, (void **)&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=0;
+
+#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
+
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+
+   struct fis_image_desc* img=(struct fis_image_desc*)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), (void **)&err_addr);
+   }
+   if (do_autolock)
+      flash_lock((void *)fis_addr, fisdir_size, (void **)&err_addr);
+
+#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
+    if (do_autolock)
     flash_unlock((void *)fis_addr, blk_size, (void **)&err_addr);
-#endif
+
     if ((stat = flash_erase(fis_addr, blk_size, (void **)&err_addr)) != 0) {
         diag_printf("Error erasing FIS directory at %p: %s\n", err_addr, flash_errmsg(stat));
     } else {
         if ((stat = FLASH_PROGRAM(fis_addr, fis_work_block,
                                   blk_size, (void **)&err_addr)) != 0) {
             diag_printf("Error writing FIS directory at %p: %s\n", 
                         err_addr, flash_errmsg(stat));
         }
     }
+    fis_endian_fixup(fis_work_block);
+    if (do_autolock)
+       flash_lock((void *)fis_addr, blk_size, (void **)&err_addr);
+
+#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
+   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, fisdir_size,
+                 (void **)&err_addr);
+#endif
+    if ((stat = flash_erase(redundant_fis_addr, fisdir_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, blk_size, (void **)&err_addr);
+    flash_lock((void *)redundant_fis_addr, fisdir_size, (void **)&err_addr);
 #endif
-    fis_endian_fixup(fis_work_block);
 }
+#endif
 
 static void
 fis_init(int argc, char *argv[])
 {
     int stat;
@@ -301,25 +457,36 @@ fis_init(int argc, char *argv[])
 
 #define MIN_REDBOOT_IMAGE_SIZE CYGBLD_REDBOOT_MIN_IMAGE_SIZE
     redboot_image_size = flash_block_size > MIN_REDBOOT_IMAGE_SIZE ? 
                          flash_block_size : MIN_REDBOOT_IMAGE_SIZE;
 
-    // Create a pseudo image for RedBoot
     img = (struct fis_image_desc *)fis_work_block;
     memset(img, 0xFF, fisdir_size);  // Start with erased data
+
+#ifdef CYGOPT_REDBOOT_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;
     img++;
 #endif
     redboot_flash_start = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT
     memset(img, 0, sizeof(*img));
-    strcpy(img->name, "RedBoot");
+    strcpy(img->u.name, "RedBoot");
     img->flash_base = redboot_flash_start;
     img->mem_base = redboot_flash_start;
     img->size = redboot_image_size;
     img++;
     redboot_flash_start += redboot_image_size;
@@ -328,44 +495,54 @@ fis_init(int argc, char *argv[])
 #ifdef CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET
     // Take care to place the POST entry at the right offset:
     redboot_flash_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FIS_REDBOOT_POST_OFFSET;
 #endif
     memset(img, 0, sizeof(*img));
-    strcpy(img->name, "RedBoot[post]");
+    strcpy(img->u.name, "RedBoot[post]");
     img->flash_base = redboot_flash_start;
     img->mem_base = redboot_flash_start;
     img->size = redboot_image_size;
     img++;
     redboot_flash_start += redboot_image_size;
 #endif
 #ifdef CYGOPT_REDBOOT_FIS_REDBOOT_BACKUP
     // And a backup image
     memset(img, 0, sizeof(*img));
-    strcpy(img->name, "RedBoot[backup]");
+    strcpy(img->u.name, "RedBoot[backup]");
     img->flash_base = redboot_flash_start;
     img->mem_base = redboot_flash_start;
     img->size = redboot_image_size;
     img++;
     redboot_flash_start += redboot_image_size;
 #endif
 #if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH)
     // And a descriptor for the configuration data
     memset(img, 0, sizeof(*img));
-    strcpy(img->name, "RedBoot config");
+    strcpy(img->u.name, "RedBoot config");
     img->flash_base = (CYG_ADDRESS)cfg_base;
     img->mem_base = (CYG_ADDRESS)cfg_base;
     img->size = cfg_size;
     img++;
 #endif
     // And a descriptor for the descriptor table itself
     memset(img, 0, sizeof(*img));
-    strcpy(img->name, "FIS directory");
+    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.
     img = (struct fis_image_desc *)((CYG_ADDRESS)fis_work_block + fisdir_size);
     // Add a footer so the FIS will be recognized by the ARM Boot
@@ -474,11 +651,15 @@ fis_init(int argc, char *argv[])
     // don't appear to be free since they are not erased - thus the warning
     } else {
         diag_printf("    Warning: device contents not erased, some blocks may not be usable\n");
 #endif
     }
-    fis_update_directory();
+    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[])
 {
@@ -523,22 +704,22 @@ fis_list(int argc, char *argv[])
     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->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;
                     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, 
+            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, 
 #else
@@ -571,11 +752,11 @@ find_free(struct free_chunk *chunks)
     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;
     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) && 
                     (img->flash_base <= chunks[idx].end)) {
                     if (img->flash_base == chunks[idx].start) {
@@ -839,12 +1020,12 @@ fis_create(int argc, char *argv[])
     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));
+    if (strlen(name) >= sizeof(img->u.name)) {
+        diag_printf("Name is too long, must be less than %d chars\n", (int)sizeof(img->u.name));
         return;
     }
     if (!no_copy) {
         if ((mem_addr < (CYG_ADDRESS)ram_start) ||
             ((mem_addr+img_size) >= (CYG_ADDRESS)ram_end)) {
@@ -905,11 +1086,11 @@ fis_create(int argc, char *argv[])
         }
 #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) {
+            if (img->u.name[0] == (unsigned char)0xFF) {
                 break;
             }
         }
 	if (i >= fisdir_size/sizeof(*img)) {
 	    diag_printf("Can't find an empty slot in FIS directory!\n");
@@ -938,11 +1119,11 @@ 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 : (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;
@@ -952,11 +1133,12 @@ fis_create(int argc, char *argv[])
         } else {
             // No way to compute this, sorry
             img->file_cksum = 0;
         }
 #endif
-        fis_update_directory();
+        fis_start_update_directory(0);
+        fis_update_directory(0, 0);
     }
 }
 
 extern void arm_fis_delete(char *);
 static void
@@ -999,11 +1181,11 @@ fis_delete(int argc, char *argv[])
 #endif
 
     img = fis_lookup(name, &i);
     if (img) {
         if (i < num_reserved) {
-            diag_printf("Sorry, '%s' is a reserved image and cannot be deleted\n", img->name);
+            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;
         }
@@ -1013,12 +1195,13 @@ fis_delete(int argc, char *argv[])
     }
     // Erase Data blocks (free space)
     if ((stat = flash_erase((void *)img->flash_base, img->size, (void **)&err_addr)) != 0) {
         diag_printf("Error erasing at %p: %s\n", err_addr, flash_errmsg(stat));
     } else {
-        img->name[0] = (unsigned char)0xFF;    
-        fis_update_directory();
+        img->u.name[0] = (unsigned char)0xFF;    
+        fis_start_update_directory(0);
+        fis_update_directory(0, 0);
     }
 }
 
 static void
 fis_load(int argc, char *argv[])
@@ -1362,20 +1545,36 @@ _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);
 }
 
-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;
 
+    void *err_addr;
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+    struct fis_image_desc img0;
+    struct fis_image_desc img1;
+    int fis_update_was_interrupted=0;
+
+    //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) {
             diag_printf("FLASH: driver init failed: %s\n", flash_errmsg(stat));
-            return false;
+            return -1;
         }
         flash_get_limits((void *)0, (void **)&flash_start, (void **)&flash_end);
         // Keep 'end' address as last valid location, to avoid wrap around problems
         flash_end = (void *)((CYG_ADDRESS)flash_end - 1);
         flash_get_block_info(&flash_block_size, &flash_num_blocks);
@@ -1384,14 +1583,14 @@ do_flash_init(void)
         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;
+            return -1;
 	}
 # else
-        workspace_end = (unsigned char *)(workspace_end-fisdir_size);
+        workspace_end = (unsigned char *)(workspace_end_init-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));
@@ -1400,16 +1599,64 @@ do_flash_init(void)
                                 (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;
+            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), (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, &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
     }
-    return true;
+#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
+    if (fis_update_was_interrupted)
+       return 1;
+    else
+       return 0;
+#else
+    return 0;
+#endif
 }
 
 // Wrapper to avoid compiler warnings
 static void
 _do_flash_init(void)
@@ -1429,11 +1676,11 @@ do_fis(int argc, char *argv[])
 
     if (argc < 2) {
         fis_usage("too few arguments");
         return;
     }
-    if (!do_flash_init()) {
+    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) {
Index: redboot/current/src/main.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/src/main.c,v
retrieving revision 1.64
diff -u -5 -p -r1.64 main.c
--- redboot/current/src/main.c	25 Feb 2006 14:21:12 -0000	1.64
+++ redboot/current/src/main.c	9 May 2006 15:34:01 -0000
@@ -296,10 +296,12 @@ cyg_start(void)
         // when *less* SDRAM is installed than the possible maximum,
         // but the heap1 region remains greater...
         workspace_end = ram_end;
     }
 
+    workspace_end_init=workspace_end;
+
     // Nothing has ever been loaded into memory
     entry_address = (unsigned long)NO_MEMORY;
 
     bist();
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]