/************************************************************/ /* Spidcom Technologies FILE NAME : image_table.c DESCRIPTION : image table management HISTORY : -------------------------------------------------------------- DATE | AUTHOR | Version | Description -------------------------------------------------------------- 05/02/04 | Petillon | 1.0 | Creation */ /************************************************************/ #include #include #include #include "flash_device.h" #include "platform.h" #include "image_table.h" #include "bootloader.h" #ifdef USE_CRC #include "posix_crc.h" #endif #include "overlap.h" #ifdef USE_BOOTSTATS #include "boot_stats.h" #endif #define ENTRY_NAME_LEN (20) #define MAGIC_LEN (16) #define MAGIC_KEY "SPIDCOMMAGICKEY " #define MAX_ENTRIES (16) typedef struct { char name[ENTRY_NAME_LEN]; image_desc_t image_desc; int selected; } entry_t; typedef struct { char magic0[MAGIC_LEN]; #ifdef PLAB int reset_drivers; #endif entry_t entries[MAX_ENTRIES]; char magic1[MAGIC_LEN]; uint32_t crc; } entry_table_t; static entry_table_t *entry_table = NULL; static int entry_table_setup = 0; static char error_string[512]; /* internal */ static entry_table_t *backup_table(void) { entry_table_t *result; result = (entry_table_t *)malloc(sizeof(entry_table_t)); memcpy(result,entry_table,sizeof(entry_table_t)); return result; } static int store_table(entry_table_t *table) { int flash_result; caddr_t address; size_t size; int result = 0; address = (caddr_t )entry_table; size = sizeof(entry_table_t); #ifdef USE_CRC // put the crc table->crc = posix_crc((caddr_t)table,(caddr_t)&table->crc-(caddr_t)table); #endif if ((flash_result=flash_get_area(flash_device,&address, &size))>=0) { if ((flash_result=flash_unlock_blocks(flash_device,address, size))>=0) { if ((flash_result=flash_erase_blocks(flash_device, address, size))>=0) { if ((flash_result=flash_write_area(flash_device, (caddr_t)entry_table, (caddr_t)table, sizeof(entry_table_t)))>=0) flash_lock_blocks(flash_device, address, size); } } } if (flash_result<0) { #ifdef USE_STDIO sprintf(error_string,"Flash error: %s",flash_error()); #endif // USE_STDIO result = FLASH_ERROR; } else if (memcmp(entry_table, table, sizeof(entry_table_t))) { #ifdef USE_STDIO strcpy(error_string,"Flash error: invalid data written"); #endif // USE_STDIO result = FLASH_ERROR; } free(table); return result; } static int find_index_by_addr(caddr_t address) { int result; caddr_t max_addr; int i; result = -1; max_addr = (caddr_t)0xFFFFFFFF; for (i=0; ientries[i].name[0]!='\0' && entry_table->entries[i].image_desc.storage_address>=address && entry_table->entries[i].image_desc.storage_addressentries[i].image_desc.storage_address; } } return result; } static int find_index_by_name(const char *name) { int result; result = 0; while (resultentries[result].name,name)) result++; if (resultentries[result].name[0]=='\0' || !entry_table->entries[result].selected)) result++; if (resultentries[i].name[0]!='\0') && overlap(address,size,entry_table->entries[i].image_desc.storage_address, entry_table->entries[i].image_desc.size); i++; } return result; } int find_free_area(caddr_t *address, size_t size) { int index; int result; caddr_t erase_address; size_t erase_size; result = 0; *address = available_flash_base(); while ((index=find_index_by_addr(*address))>=0 && !result) { erase_address = entry_table->entries[index].image_desc.storage_address; erase_size = entry_table->entries[index].image_desc.size; flash_get_area(flash_device,&erase_address, &erase_size); if (*address+size<=erase_address) result = 1; else *address = erase_address+erase_size; } result |= *address+size<=available_flash_base()+available_flash_size(); return result; } /* exported */ int image_table_init(void) { caddr_t address; size_t size; uint32_t crc; (void) crc; address = (caddr_t)FLASH_BASE + flash_size(flash_device) - sizeof(entry_table_t); size = sizeof(entry_table_t); flash_get_area(flash_device,&address, &size); entry_table = (entry_table_t *) address; #ifdef USE_BOOTSTATS boot_stats_init(address); #endif #ifdef USE_CRC crc = posix_crc((caddr_t)entry_table,(caddr_t)&entry_table->crc-(caddr_t)entry_table); #endif if (strncmp(entry_table->magic0,MAGIC_KEY,MAGIC_LEN) || strncmp(entry_table->magic1,MAGIC_KEY,MAGIC_LEN) #ifdef USE_CRC || crc!=entry_table->crc) #else ) #endif { entry_table_setup = 0; #ifdef USE_STDIO strcpy(error_string,"Table not set-up or corrupted"); #endif // USE_STDIO return TABLE_NOT_SET_UP; } else { entry_table_setup = 1; return 0; } } caddr_t available_flash_base(void) { return (caddr_t)FLASH_BASE+get_locked_size(); } size_t available_flash_size(void) { #ifdef USE_BOOTSTATS return (caddr_t)boot_stats_addr-(caddr_t)FLASH_BASE-get_locked_size(); #else return (caddr_t)entry_table-(caddr_t)FLASH_BASE-get_locked_size(); #endif } int table_is_setup(void) { return entry_table_setup; } int setup_table(void) { entry_table_t *tmp_table; int result; int i; tmp_table = backup_table(); strncpy(tmp_table->magic0,MAGIC_KEY,MAGIC_LEN); strncpy(tmp_table->magic1,MAGIC_KEY,MAGIC_LEN); for(i=0; ientries[i].name,ENTRY_NAME_LEN); #ifdef PLAB tmp_table->reset_drivers = 1; #endif if ((result=store_table(tmp_table))>=0) entry_table_setup = 1; return result; } int add_entry(const char *name, image_desc_t *image_desc) { int i; char real_name[ENTRY_NAME_LEN]; int oldindex; entry_table_t *tmp_table; int result; if ((result=test_add_entry(name,image_desc))<0) return result; bzero(real_name,ENTRY_NAME_LEN); strncpy(real_name,name,ENTRY_NAME_LEN-1); i = 0; while(ientries[i].name,"")) i++; if (ientries[i].name,real_name); tmp_table->entries[i].image_desc = *image_desc; if (oldindex>=0) tmp_table->entries[oldindex].selected = 0; tmp_table->entries[i].selected = 1; return store_table(tmp_table); } else { strcpy(error_string,"Image table full"); return TABLE_FULL; } } int test_add_entry(const char *name, image_desc_t *image_desc) { int i; char real_name[ENTRY_NAME_LEN]; caddr_t erase_address; size_t erase_size; if (!entry_table_setup) { strcpy(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } bzero(real_name,ENTRY_NAME_LEN); strncpy(real_name,name,ENTRY_NAME_LEN-1); if (!strcmp(real_name,"")) { strcpy(error_string,"Unknown image name"); return UNKNOWN_IMAGE_NAME; } else if (find_index_by_name(real_name)>=0) { #ifdef USE_STDIO sprintf(error_string,"Image name \"%s\" already used",real_name); #endif // USE_STDIO return IMAGE_NAME_ALREADY_USED; } if (image_desc->storage_address==0) { if (!find_free_area(&image_desc->storage_address,image_desc->size)) { #ifdef USE_STDIO sprintf(error_string,"No free area of size %u",image_desc->size); #endif // USE_STDIO return UNAVAILABLE_FLASH_AREA; } } if (image_desc->storage_addressstorage_address+image_desc->size-1>available_flash_base()+available_flash_size()-1) { #ifdef USE_STDIO sprintf(error_string,"Invalid flash area: 0x%.8lx-0x%.8lx", (unsigned long)image_desc->storage_address,(unsigned long)image_desc->storage_address+image_desc->size-1); #endif // USE_STDIO return INVALID_FLASH_AREA; } erase_address = image_desc->storage_address; erase_size = image_desc->size; flash_get_area(flash_device,&erase_address, &erase_size); if (image_overlaps(erase_address, erase_size)) { #ifdef USE_STDIO sprintf(error_string,"Flash block area 0x%.8lx-0x%.8lx overlaps with existing images", (unsigned long)image_desc->storage_address,(unsigned long)image_desc->storage_address+image_desc->size-1); #endif // USE_STDIO return UNAVAILABLE_FLASH_AREA; } i = 0; while(ientries[i].name,"")) i++; if (i=0) { tmp_table = backup_table(); bzero(tmp_table->entries[index].name,ENTRY_NAME_LEN); if (tmp_table->entries[index].selected) { if ((index=find_index_by_addr(0))>=0) tmp_table->entries[index].selected = 1; } return store_table(tmp_table); } else { strcpy(error_string,"Unknown image name"); return UNKNOWN_IMAGE_NAME; } } int get_entry(const char *name, image_desc_t *image_desc, int *selected) { int index; if (!entry_table_setup) { strcpy(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } if ((index = find_index_by_name(name))>=0) { *image_desc = entry_table->entries[index].image_desc; *selected = entry_table->entries[index].selected; return 0; } else { strcpy(error_string,"Unknown image name"); return UNKNOWN_IMAGE_NAME; } } int select_entry(const char *name) { int index; int oldindex; entry_table_t *tmp_table; if (!entry_table_setup) { strcpy(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } if ((index = find_index_by_name(name))>=0) { if (entry_table->entries[index].selected) return 0; else { tmp_table = backup_table(); if ((oldindex=find_selected_index())>=0) tmp_table->entries[oldindex].selected = 0; tmp_table->entries[index].selected = 1; return store_table(tmp_table); } } else { strcpy(error_string,"Unknown image name"); return UNKNOWN_IMAGE_NAME; } } const char *get_selected_name(void) { int index; if (!entry_table_setup) { strcpy(error_string,"Table not set-up or corrupted"); return NULL; } if ((index=find_selected_index())>=0) return entry_table->entries[index].name; else { strcpy(error_string,"Image table error"); return NULL; } } const char *next_entry(const char *name) { int index; caddr_t next_addr; if (!entry_table_setup) { strcpy(error_string,"Table not set-up or corrupted"); return NULL; } if (name==NULL) index = find_index_by_addr(0); else { if ((index = find_index_by_name(name))>=0) { next_addr = (caddr_t)entry_table->entries[index].image_desc.storage_address+ entry_table->entries[index].image_desc.size; index = find_index_by_addr(next_addr); } } if (index>=0) return entry_table->entries[index].name; else { strcpy(error_string,"No more images"); return NULL; } } const char *image_table_error(void) { return error_string; }