📄 flash.c
字号:
#endif
footer_p->infoBase = NULL;
footer_p->signature = FLASH_FOOTER_SIGNATURE;
footer_p->type = TYPE_REDHAT_REDBOOT;
// and compute its checksum
for ( ; count > 0; count--) {
if (*check_ptr > ~check)
check++;
check += *check_ptr++;
}
footer_p->checksum = ~check;
}
#endif
// Do this after creating the initialized table because that inherently
// calculates where the high water mark of default RedBoot images is.
if (full_init) {
unsigned long erase_size;
CYG_ADDRESS erase_start;
// Erase everything except default RedBoot images, fis block,
// and config block.
// First deal with the possible first part, before RedBoot images:
#if (CYGBLD_REDBOOT_FLASH_BOOT_OFFSET > CYGNUM_REDBOOT_FLASH_RESERVED_BASE)
erase_start = (CYG_ADDRESS)flash_start + CYGNUM_REDBOOT_FLASH_RESERVED_BASE;
erase_size = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET;
if ( erase_size > erase_start ) {
erase_size -= erase_start;
if ((stat = flash_erase((void *)erase_start, erase_size,
(void **)&err_addr)) != 0) {
diag_printf(" initialization failed at %p: %s\n",
err_addr, flash_errmsg(stat));
}
}
#endif
// second deal with the larger part in the main:
erase_start = redboot_flash_start; // high water of created images
// Now the empty bits between the end of Redboot and the cfg and dir
// blocks.
#if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && \ defined(CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH) && \ !defined(CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG)
if (fis_addr > cfg_base) {
erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between HWM and config data
} else {
erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
}
if ((stat = flash_erase((void *)erase_start, erase_size,
(void **)&err_addr)) != 0) {
diag_printf(" initialization failed %p: %s\n",
err_addr, flash_errmsg(stat));
}
erase_start += (erase_size + flash_block_size);
if (fis_addr > cfg_base) {
erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between config and fis data
} else {
erase_size = (CYG_ADDRESS)cfg_base - erase_start; // the gap between fis and config data
}
if ((stat = flash_erase((void *)erase_start, erase_size,
(void **)&err_addr)) != 0) {
diag_printf(" initialization failed %p: %s\n",
err_addr, flash_errmsg(stat));
}
erase_start += (erase_size + flash_block_size);
#else // !CYGSEM_REDBOOT_FLASH_CONFIG
erase_size = (CYG_ADDRESS)fis_addr - erase_start; // the gap between HWM and fis data
if ((stat = flash_erase((void *)erase_start, erase_size,
(void **)&err_addr)) != 0) {
diag_printf(" initialization failed %p: %s\n",
err_addr, flash_errmsg(stat));
}
erase_start += (erase_size + flash_block_size);
#endif
// Lastly, anything at the end
erase_size = ((CYG_ADDRESS)flash_end - erase_start) + 1;
if ((stat = flash_erase((void *)erase_start, erase_size,
(void **)&err_addr)) != 0) {
diag_printf(" initialization failed at %p: %s\n",
err_addr, flash_errmsg(stat));
}
#ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
// In this case, 'fis free' works by scanning for erased blocks. Since the
// "-f" option was not supplied, there may be areas which are not used but
// 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();
}
static void
fis_list(int argc, char *argv[])
{
struct fis_image_desc *img;
int i, image_indx;
bool show_cksums = false;
bool show_datalen = false;
struct option_info opts[2];
void *err_addr;
unsigned long last_addr, lowest_addr;
bool image_found;
#ifdef CYGHWR_REDBOOT_ARM_FLASH_SIB
// FIXME: this is somewhat half-baked
extern void arm_fis_list(void);
arm_fis_list();
return;
#endif
init_opts(&opts[0], 'd', false, OPTION_ARG_TYPE_FLG,
(void *)&show_datalen, (bool *)0, "display data length");
#ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK
init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG,
(void *)&show_cksums, (bool *)0, "display checksums");
i = 2;
#else
i = 1;
#endif
if (!scan_opts(argc, argv, 2, opts, i, 0, 0, "")) {
return;
}
flash_read(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr);
// Let diag_printf do the formatting in both cases, rather than counting
// cols by hand....
diag_printf("%-16s %-10s %-10s %-10s %-s\n",
"Name","FLASH addr",
show_cksums ? "Checksum" : "Mem addr",
show_datalen ? "Datalen" : "Length",
"Entry point" );
last_addr = 0;
image_indx = 0;
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->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,
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
img->mem_base,
img->size,
#endif
img->entry_point);
}
last_addr = lowest_addr;
} while (image_found == true);
}
#ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
struct free_chunk {
CYG_ADDRESS start, end;
};
static int
find_free(struct free_chunk *chunks)
{
CYG_ADDRESS *fis_ptr, *fis_end;
void *err_addr;
struct fis_image_desc *img;
int i, idx;
int num_chunks = 1;
// Do not search the area reserved for pre-RedBoot systems:
fis_ptr = (CYG_ADDRESS *)((CYG_ADDRESS)flash_start +
CYGNUM_REDBOOT_FLASH_RESERVED_BASE +
CYGBLD_REDBOOT_MIN_IMAGE_SIZE);
fis_end = (CYG_ADDRESS *)flash_end;
chunks[num_chunks-1].start = (CYG_ADDRESS)fis_ptr;
chunks[num_chunks-1].end = (CYG_ADDRESS)fis_end;
flash_read(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr);
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) {
// 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) {
chunks[idx].start += img->size;
if (chunks[idx].start >= chunks[idx].end) {
// This free chunk has collapsed
while (idx < (num_chunks-1)) {
chunks[idx] = chunks[idx+1];
}
num_chunks--;
}
} else if ((img->flash_base+img->size) == chunks[idx].end) {
chunks[idx].end = img->flash_base;
} else {
// Split chunk into two parts
if ((img->flash_base+img->size) < (CYG_ADDRESS)fis_end) {
chunks[idx+1].start = img->flash_base + img->size;
chunks[idx+1].end = chunks[idx].end;
if (++num_chunks == CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS) {
diag_printf("Warning: too many free chunks\n");
return num_chunks;
}
}
chunks[idx].end = img->flash_base;
}
break;
}
}
}
}
return num_chunks;
}
#endif // CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
static void
fis_free(int argc, char *argv[])
{
#ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
unsigned long *fis_ptr, *fis_end, flash_data;
unsigned long *area_start;
void *err_addr;
// Do not search the area reserved for pre-RedBoot systems:
fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +
CYGNUM_REDBOOT_FLASH_RESERVED_BASE +
CYGBLD_REDBOOT_MIN_IMAGE_SIZE);
fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
area_start = fis_ptr;
while (fis_ptr < fis_end) {
flash_read(fis_ptr, &flash_data, sizeof(unsigned long), (void **)&err_addr);
if (flash_data != (unsigned long)0xFFFFFFFF) {
if (area_start != fis_ptr) {
// Assume that this is something
diag_printf(" 0x%08lX .. 0x%08lX\n",
(CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
}
// Find next blank block
area_start = fis_ptr;
while (area_start < fis_end) {
flash_read(area_start, &flash_data, sizeof(unsigned long), (void **)&err_addr);
if (flash_data == (unsigned long)0xFFFFFFFF) {
break;
}
area_start += flash_block_size / sizeof(CYG_ADDRESS);
}
fis_ptr = area_start;
} else {
fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
}
}
if (area_start != fis_ptr) {
diag_printf(" 0x%08lX .. 0x%08lX\n",
(CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
}
#else
struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
int idx, num_chunks;
num_chunks = find_free(chunks);
for (idx = 0; idx < num_chunks; idx++) {
diag_printf(" 0x%08lX .. 0x%08lX\n", chunks[idx].start, chunks[idx].end);
}
#endif
}
// Find the first unused area of flash which is long enough
static bool
fis_find_free(CYG_ADDRESS *addr, unsigned long length)
{
#ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
unsigned long *fis_ptr, *fis_end, flash_data;
unsigned long *area_start;
void *err_addr;
// Do not search the area reserved for pre-RedBoot systems:
fis_ptr = (unsigned long *)((CYG_ADDRESS)flash_start +
CYGNUM_REDBOOT_FLASH_RESERVED_BASE +
CYGBLD_REDBOOT_MIN_IMAGE_SIZE);
fis_end = (unsigned long *)(CYG_ADDRESS)flash_end;
area_start = fis_ptr;
while (fis_ptr < fis_end) {
flash_read(fis_ptr, &flash_data, sizeof(unsigned long), (void **)&err_addr);
if (flash_data != (unsigned long)0xFFFFFFFF) {
if (area_start != fis_ptr) {
// Assume that this is something
if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) {
*addr = (CYG_ADDRESS)area_start;
return true;
}
}
// Find next blank block
area_start = fis_ptr;
while (area_start < fis_end) {
flash_read(area_start, &flash_data, sizeof(unsigned long), (void **)&err_addr);
if (flash_data == (unsigned long)0xFFFFFFFF) {
break;
}
area_start += flash_block_size / sizeof(CYG_ADDRESS);
}
fis_ptr = area_start;
} else {
fis_ptr += flash_block_size / sizeof(CYG_ADDRESS);
}
}
if (area_start != fis_ptr) {
if ((fis_ptr-area_start) >= (length/sizeof(unsigned))) {
*addr = (CYG_ADDRESS)area_start;
return true;
}
}
return false;
#else
struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
int idx, num_chunks;
num_chunks = find_free(chunks);
for (idx = 0; idx < num_chunks; idx++) {
if ((chunks[idx].end - chunks[idx].start) >= length) {
*addr = (CYG_ADDRESS)chunks[idx].start;
return true;
}
}
return false;
#endif
}
static void
fis_create(int argc, char *argv[])
{
int i, stat;
unsigned long length, img_size;
CYG_ADDRESS mem_addr, exec_addr, flash_addr, entry_addr;
char *name;
bool mem_addr_set = false;
bool exec_addr_set = false;
bool entry_addr_set = false;
bool flash_addr_set = false;
bool length_set = false;
bool img_size_set = false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -