📄 flash.c
字号:
#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;
}
fis_read_directory();
// 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->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->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
img->mem_base,
img->size,
#endif
(unsigned long)img->entry_point);
}
last_addr = lowest_addr + 1;
} 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;
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);
fis_end = (CYG_ADDRESS *)flash_end;
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->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) {
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];
idx++;
}
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) {
int j;
// make room for new chunk
for (j = num_chunks; j > (idx+1); j--)
chunks[j] = chunks[j-1];
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);
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",
(unsigned long)chunks[idx].start,
(unsigned long)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);
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;
bool no_copy = false;
void *err_addr;
struct fis_image_desc *img = NULL;
bool defaults_assumed;
struct option_info opts[7];
bool prog_ok = true;
init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
(void *)&mem_addr, (bool *)&mem_addr_set, "memory base address");
init_opts(&opts[1], 'r', true, OPTION_ARG_TYPE_NUM,
(void *)&exec_addr, (bool *)&exec_addr_set, "ram base address");
init_opts(&opts[2], 'e', true, OPTION_ARG_TYPE_NUM,
(void *)&entry_addr, (bool *)&entry_addr_set, "entry point address");
init_opts(&opts[3], 'f', true, OPTION_ARG_TYPE_NUM,
(void *)&flash_addr, (bool *)&flash_addr_set, "FLASH memory base address");
init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM,
(void *)&length, (bool *)&length_set, "image length [in FLASH]");
init_opts(&opts[5], 's', true, OPTION_ARG_TYPE_NUM,
(void *)&img_size, (bool *)&img_size_set, "image size [actual data]");
init_opts(&opts[6], 'n', false, OPTION_ARG_TYPE_FLG,
(void *)&no_copy, (bool *)0, "don't copy from RAM to FLASH, just update directory");
if (!scan_opts(argc, argv, 2, opts, 7, (void *)&name, OPTION_ARG_TYPE_STR, "file name"))
{
fis_usage("invalid arguments");
return;
}
fis_read_directory();
defaults_assumed = false;
if (name) {
// Search existing files to acquire defaults for params not specified:
img = fis_lookup(name, NULL);
if (img) {
// Found it, so get image size from there
if (!length_set) {
length_set = true;
length = img->size;
defaults_assumed = true;
}
}
}
if (!mem_addr_set && (load_address >= (CYG_ADDRESS)ram_start) &&
(load_address_end) < (CYG_ADDRESS)ram_end) {
mem_addr = load_address;
mem_addr_set = true;
defaults_assumed = true;
// Get entry address from loader, unless overridden
if (!entry_addr_set)
entry_addr = entry_address;
if (!length_set) {
length = load_address_end - load_address;
length_set = true;
} else if (defaults_assumed && !img_size_set) {
/* We got length from the FIS table, so the size of the
actual loaded image becomes img_size */
img_size = load_address_end - load_address;
img_size_set = true;
}
}
// Get the remaining fall-back values from the fis
if (img) {
if (!exec_addr_set) {
// Preserve "normal" behaviour
exec_addr_set = true;
exec_addr = flash_addr_set ? flash_addr : mem_addr;
}
if (!flash_addr_set) {
flash_addr_set = true;
flash_addr = img->flash_base;
defaults_assumed = true;
}
}
if ((!no_copy && !mem_addr_set) || (no_copy && !flash_addr_set) ||
!length_set || !name) {
fis_usage("required parameter missing");
return;
}
if (!img_size_set) {
img_size = length;
}
// 'length' is size of FLASH image, 'img_size' is actual data size
// Round up length to FLASH block size
#ifndef CYGPKG_HAL_MIPS // FIXME: compiler is b0rken
length = ((length + flash_block_size - 1) / flash_block_size) * flash_block_size;
if (length < img_size) {
diag_printf("Invalid FLASH image size/length combination\n");
return;
}
#endif
if (flash_addr_set &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -