This is the mail archive of the
ecos-patches@sourceware.org
mailing list for the eCos project.
RedBoot FIS improvements
- From: Gary Thomas <gary at mlbassoc dot com>
- To: eCos patches <ecos-patches at ecos dot sourceware dot org>
- Date: Tue, 09 May 2006 09:54:43 -0600
- Subject: RedBoot FIS improvements
- Organization: MLB Associates
>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();