/************************************************************/ /* 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"*/ #include "posix_crc.h" #include "overlap.h" #include "nvram.h" #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]; 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); // put the crc table->crc = posix_crc((caddr_t)table,(caddr_t)&table->crc-(caddr_t)table); if ((flash_result=flash_get_area(&address, &size))>=0) { if ((flash_result=flash_unlock_blocks(address, size))>=0) { if ((flash_result=flash_erase_blocks(address, size))>=0) { if ((flash_result=flash_write_area((caddr_t)entry_table, (uint8_t*)table, sizeof(entry_table_t)))>=0) flash_lock_blocks(address, size); } } } if (flash_result<0) { sprintf(error_string,"Flash error: %s",flash_error()); result = FLASH_ERR; } else if (memcmp(entry_table, table, sizeof(entry_table_t))) { sprintf(error_string,"Flash error: invalid data written"); result = FLASH_ERR; } 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(&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; address = (caddr_t)FLASH_BASE + flash_size() - sizeof(entry_table_t); size = sizeof(entry_table_t); flash_get_area(&address, &size); entry_table = (entry_table_t *) address; crc = posix_crc((caddr_t)entry_table,(caddr_t)&entry_table->crc-(caddr_t)entry_table); if (strncmp(entry_table->magic0,MAGIC_KEY,MAGIC_LEN) || strncmp(entry_table->magic1,MAGIC_KEY,MAGIC_LEN) || crc!=entry_table->crc) { entry_table_setup = 0; sprintf(error_string,"Table not set-up or corrupted"); printf("Table not set-up or corrupted (%s) (%s) (%d,%d)",entry_table->magic0,entry_table->magic1,crc,entry_table->crc); return TABLE_NOT_SET_UP; } else { entry_table_setup = 1; return 0; } } caddr_t available_flash_base(void) { return (caddr_t)FLASH_BASE+/*get_flash_code_size()*/ (128*1024) + NVRAM_SIZE; } size_t available_flash_size(void) { return (caddr_t)entry_table-(caddr_t)FLASH_BASE-(128*1024) - NVRAM_SIZE/*get_flash_code_size()*/; } 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);*/ memset(tmp_table->entries[i].name,0,ENTRY_NAME_LEN); 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);*/ memset(real_name,0,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 { sprintf(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) { sprintf(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } /* bzero(real_name,ENTRY_NAME_LEN);*/ memset(real_name,0,ENTRY_NAME_LEN); strncpy(real_name,name,ENTRY_NAME_LEN-1); if (!strcmp(real_name,"")) { sprintf(error_string,"Unknown image name"); return UNKNOWN_IMAGE_NAME; } else if (find_index_by_name(real_name)>=0) { sprintf(error_string,"Image name \"%s\" already used",real_name); return IMAGE_NAME_ALREADY_USED; } if (image_desc->storage_address==0) { if (!find_free_area(&image_desc->storage_address,image_desc->size)) { sprintf(error_string,"No free area of size %lu",image_desc->size); return UNAVAILABLE_FLASH_AREA; } } if (image_desc->storage_addressstorage_address+image_desc->size-1>available_flash_base()+available_flash_size()-1) { 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); return INVALID_FLASH_AREA; } erase_address = image_desc->storage_address; erase_size = image_desc->size; flash_get_area(&erase_address, &erase_size); if (image_overlaps(erase_address, erase_size)) { 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); return UNAVAILABLE_FLASH_AREA; } i = 0; while(ientries[i].name,"")) i++; if (i=0) { sprintf(error_string,"Image name already exist"); return UNKNOWN_IMAGE_NAME; } if ((index = find_index_by_name(oldName))>=0) { tmp_table = backup_table(); strcpy(tmp_table->entries[index].name,newName); return store_table(tmp_table); } else { sprintf(error_string,"Unknown image name"); return UNKNOWN_IMAGE_NAME; } } int update_entry(const char *name, image_desc_t *image_desc) { int index; entry_table_t *tmp_table; if (!entry_table_setup) { sprintf(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } if ((index = find_index_by_name(name))>=0) { tmp_table = backup_table(); tmp_table->entries[index].image_desc = *image_desc; return store_table(tmp_table); } else { sprintf(error_string,"Unknown image name"); return UNKNOWN_IMAGE_NAME; } } int remove_entry(const char *name) { int index; entry_table_t *tmp_table; if (!entry_table_setup) { sprintf(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } if ((index = find_index_by_name(name))>=0) { tmp_table = backup_table(); memset(tmp_table->entries[index].name,0,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 { sprintf(error_string,"Unknown image name"); return UNKNOWN_IMAGE_NAME; } } int remove_all_entries() { int i; entry_table_t *tmp_table; if (!entry_table_setup) { sprintf(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } tmp_table = backup_table(); for(i=0;ientries[i].selected) memset(tmp_table->entries[i].name,0,ENTRY_NAME_LEN); } return store_table(tmp_table); } int get_running_entry_name(char* name) { int index; if (!entry_table_setup) return TABLE_NOT_SET_UP; #if 0 for (index=0;indexentries[index].image_desc.isRunning) { strcpy(name, entry_table->entries[index].name); return 0; } } #endif if ((index = find_index_by_name("active"))>=0) { strcpy(name,"active"); return 0; } return 1; } int get_entry(const char *name, image_desc_t *image_desc, int *selected) { int index; if (!entry_table_setup) { sprintf(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 { sprintf(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) { sprintf(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 { sprintf(error_string,"Unknown image name"); return UNKNOWN_IMAGE_NAME; } } const char *get_selected_name(void) { int index; if (!entry_table_setup) { sprintf(error_string,"Table not set-up or corrupted"); return NULL; } if ((index=find_selected_index())>=0) return entry_table->entries[index].name; else { sprintf(error_string,"Image table error"); return NULL; } } const char *next_entry(const char *name) { int index; caddr_t next_addr; if (!entry_table_setup) { sprintf(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 { sprintf(error_string,"No more images"); return NULL; } } const char *image_table_error(void) { return error_string; }