📄 flash.c
字号:
//==========================================================================
//
// flash.c
//
// RedBoot - FLASH memory support
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
// Copyright (C) 2003, 2004 Gary Thomas
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas, tkoeller
// Date: 2000-07-28
// Purpose:
// Description:
//
// This code is part of RedBoot (tm).
//
//####DESCRIPTIONEND####
//
//==========================================================================
#include <redboot.h>
#include <cyg/io/flash.h>
#include <fis.h>
#include <sib.h>
#include <cyg/infra/cyg_ass.h> // assertion macros
#ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG
// Note horrid intertwining of functions, to save precious FLASH
extern void conf_endian_fixup(void *p);
#endif
// Round a quantity up
#define _rup(n,s) ((((n)+(s-1))/s)*s)
#ifdef CYGOPT_REDBOOT_FIS
// Image management functions
local_cmd_entry("init",
"Initialize FLASH Image System [FIS]",
"[-f]",
fis_init,
FIS_cmds
);
#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
# define FIS_LIST_OPTS "[-c] [-d]"
#else
# define FIS_LIST_OPTS "[-d]"
#endif
local_cmd_entry("list",
"Display contents of FLASH Image System [FIS]",
FIS_LIST_OPTS,
fis_list,
FIS_cmds
);
local_cmd_entry("free",
"Display free [available] locations within FLASH Image System [FIS]",
"",
fis_free,
FIS_cmds
);
local_cmd_entry("delete",
"Delete an image from FLASH Image System [FIS]",
"name",
fis_delete,
FIS_cmds
);
static char fis_load_usage[] =
#ifdef CYGPRI_REDBOOT_ZLIB_FLASH
"[-d] "
#endif
"[-b <memory_load_address>] [-c] name";
local_cmd_entry("load",
"Load image from FLASH Image System [FIS] into RAM",
fis_load_usage,
fis_load,
FIS_cmds
);
local_cmd_entry("create",
"Create an image",
"[-b <mem_base>] [-l <image_length>] [-s <data_length>]\n"
" [-f <flash_addr>] [-e <entry_point>] [-r <ram_addr>] [-n] <name>",
fis_create,
FIS_cmds
);
#endif
// Raw flash access functions
local_cmd_entry("erase",
"Erase FLASH contents",
"-f <flash_addr> -l <length>",
fis_erase,
FIS_cmds
);
#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
local_cmd_entry("lock",
"LOCK FLASH contents",
"[-f <flash_addr> -l <length>] [name]",
fis_lock,
FIS_cmds
);
local_cmd_entry("unlock",
"UNLOCK FLASH contents",
"[-f <flash_addr> -l <length>] [name]",
fis_unlock,
FIS_cmds
);
#endif
local_cmd_entry("write",
"Write raw data directly to FLASH",
"-f <flash_addr> -b <mem_base> -l <image_length>",
fis_write,
FIS_cmds
);
// Define table boundaries
CYG_HAL_TABLE_BEGIN( __FIS_cmds_TAB__, FIS_cmds);
CYG_HAL_TABLE_END( __FIS_cmds_TAB_END__, FIS_cmds);
extern struct cmd __FIS_cmds_TAB__[], __FIS_cmds_TAB_END__;
// CLI function
static cmd_fun do_fis;
RedBoot_nested_cmd("fis",
"Manage FLASH images",
"{cmds}",
do_fis,
__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__
);
// Local data used by these routines
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
extern struct _config *config;
#endif
static void
fis_usage(char *why)
{
diag_printf("*** invalid 'fis' command: %s\n", why);
cmd_usage(__FIS_cmds_TAB__, &__FIS_cmds_TAB_END__, "fis ");
}
static void
_show_invalid_flash_address(CYG_ADDRESS flash_addr, int stat)
{
diag_printf("Invalid FLASH address %p: %s\n", (void *)flash_addr, flash_errmsg(stat));
diag_printf(" valid range is %p-%p\n", (void *)flash_start, (void *)flash_end);
}
#ifdef CYGOPT_REDBOOT_FIS
// fis_endian_fixup() is used to swap endianess if required.
//
static inline void fis_endian_fixup(void *addr)
{
#ifdef REDBOOT_FLASH_REVERSE_BYTEORDER
struct fis_image_desc *p = addr;
int cnt = fisdir_size / sizeof(struct fis_image_desc);
while (cnt-- > 0) {
p->flash_base = CYG_SWAP32(p->flash_base);
p->mem_base = CYG_SWAP32(p->mem_base);
p->size = CYG_SWAP32(p->size);
p->entry_point = CYG_SWAP32(p->entry_point);
p->data_length = CYG_SWAP32(p->data_length);
p->desc_cksum = CYG_SWAP32(p->desc_cksum);
p->file_cksum = CYG_SWAP32(p->file_cksum);
p++;
}
#endif
}
void
fis_read_directory(void)
{
void *err_addr;
FLASH_READ(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr);
fis_endian_fixup(fis_work_block);
}
struct fis_image_desc *
fis_lookup(char *name, int *num)
{
int i;
struct fis_image_desc *img;
fis_read_directory();
img = (struct fis_image_desc *)fis_work_block;
for (i = 0; i < fisdir_size/sizeof(*img); i++, img++) {
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;
}
int fis_start_update_directory(int autolock)
{
#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
// Ensure [quietly] that the directory is unlocked before trying to update and locked again afterwards
int do_autolock=1;
#else
int do_autolock=autolock;
#endif
#endif
struct fis_image_desc* img=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....
#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
if (do_autolock)
flash_unlock((void *)fis_addr, fisdir_size, (void **)&err_addr);
#endif
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 CYGHWR_IO_FLASH_BLOCK_LOCKING
#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
// Ensure [quietly] that the directory is unlocked before trying to update and locked again afterwards
int do_autolock=1;
#else
int do_autolock=autolock;
#endif
#endif
#ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
struct fis_image_desc* img=(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);
}
#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
if (do_autolock)
flash_lock((void *)fis_addr, fisdir_size, (void **)&err_addr);
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -