/************************************************************/ /* Spidcom Technologies FILE NAME : image_table.c DESCRIPTION : image table management HISTORY : -------------------------------------------------------------- DATE | AUTHOR | Version | Description -------------------------------------------------------------- 05/02/04 | Petillon | 1.0 | Creation */ /************************************************************/ #ifndef __LINUX__ #include #include #include #endif #include "platform.h" #include "mtd_part.h" #include "image_table.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; typedef struct { entry_table_t entry; int fd; } context_table_t; //static int entry_table_part = -1; //static entry_table_t entry_table; static int entry_table_setup = 0; static char error_string[512]; static caddr_t av_flash_base; static size_t av_flash_size; /* internal */ static int load_table(context_table_t *table) { //Load Btable if ((table->fd=mtd_part_open("btable"))!=ERROR) { caddr_t address; size_t size; address = (caddr_t)(mtd_part_size(table->fd)-sizeof(entry_table_t)); size = sizeof(entry_table_t); mtd_part_get_area(table->fd, &address, &size); mtd_part_read(table->fd,address,(uint8_t*)&table->entry,sizeof(entry_table_t)); return 0; } return -1; } static int store_table(context_table_t *table, int really_store) { int mtd_part_result; caddr_t address; int result = 0; size_t size; entry_table_t tmp_table; if(really_store) { address = (caddr_t)(mtd_part_size(table->fd) - sizeof(entry_table_t)); size = sizeof(entry_table_t); /* Put the crc */ table->entry.crc = posix_crc((caddr_t)&table->entry, (caddr_t)&table->entry.crc - (caddr_t)&table->entry); if((mtd_part_result = mtd_part_get_area(table->fd, &address, &size)) >= 0){ if((mtd_part_result = mtd_part_unlock_blocks(table->fd, address, size)) >= 0){ if((mtd_part_result = mtd_part_erase_blocks(table->fd, address, size)) >= 0){ if((mtd_part_result = mtd_part_write(table->fd, address, (uint8_t*)&table->entry, sizeof(entry_table_t))) >= 0) mtd_part_lock_blocks(table->fd, address, size); } } } if(mtd_part_result < 0){ sprintf(error_string, "Flash error"); result = FLASH_ERR; }else{ mtd_part_read(table->fd, address, (uint8_t*)&tmp_table, sizeof(entry_table_t)); if(!!memcmp(&tmp_table, &table->entry, sizeof(entry_table_t))){ sprintf(error_string, "Flash error: invalid data written"); result = FLASH_ERR; } } } mtd_part_close(table->fd); return result; } static int find_index_by_addr(caddr_t address, entry_table_t *entry_table) { int result; caddr_t max_addr; int i; result = -1; max_addr = (caddr_t)0xFFFFFFFF; if(entry_table) { 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, entry_table_t *entry_table) { 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, entry_table_t *entry_table) { int Mindex; int result; caddr_t next_image_address; size_t next_image_size; int images_part; result = 0; *address = available_flash_base(); if ((images_part=mtd_part_open("images"))) { while ((Mindex=find_index_by_addr(*address, entry_table))>=0 && !result) { // get block-rounded address // adjust with available_flash_base() to get offset within partition next_image_address = entry_table->entries[Mindex].image_desc.storage_address-(size_t)available_flash_base(); next_image_size = entry_table->entries[Mindex].image_desc.size; mtd_part_get_area(images_part, &next_image_address, &next_image_size); // adjust back with available_flash_base() to get physical address next_image_address+=(size_t)available_flash_base(); // does address+size fit in the free block before the image? if (*address+size<=next_image_address) result = 1; else *address = next_image_address+next_image_size; } mtd_part_close(images_part); } result = result || *address+size<=available_flash_base()+available_flash_size(); return result; } /* exported */ int image_table_init(void) { caddr_t address; int entry_table_part; entry_table_t entry_table; size_t size; uint32_t crc; int part; if ((part=mtd_part_open("images"))!=ERROR) { av_flash_base = (caddr_t)FLASH_BASE+mtd_part_offset(part); av_flash_size = mtd_part_size(part); mtd_part_close(part); } if ((entry_table_part=mtd_part_open("btable"))!=ERROR) { address = (caddr_t)(mtd_part_size(entry_table_part)-sizeof(entry_table_t)); size = sizeof(entry_table_t); mtd_part_get_area(entry_table_part, &address, &size); mtd_part_read(entry_table_part,address,(uint8_t*)&entry_table,sizeof(entry_table_t)); 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"); mtd_part_close(entry_table_part); return TABLE_NOT_SET_UP; } else { entry_table_setup = 1; mtd_part_close(entry_table_part); return 0; } } else { entry_table_setup = 0; sprintf(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } } caddr_t available_flash_base(void) { return av_flash_base; } size_t available_flash_size(void) { return av_flash_size; } int table_is_setup(void) { return entry_table_setup; } int setup_table(void) { context_table_t ctx; int result; int i; //Load Btable and copy to ctx if(load_table(&ctx)) { sprintf(error_string,"Error opening btable"); return 0; } //Setup Btable strncpy(ctx.entry.magic0,MAGIC_KEY,MAGIC_LEN); strncpy(ctx.entry.magic1,MAGIC_KEY,MAGIC_LEN); for(i=0; i=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; context_table_t ctx; 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); //Load Btable and copy to ctx if(load_table(&ctx)) { sprintf(error_string,"Error opening btable"); return 0; } i = 0; while(i=0) ctx.entry.entries[oldindex].selected = 0; ctx.entry.entries[i].selected = 1; return store_table(&ctx, 1); } else { sprintf(error_string,"Image table full"); store_table(&ctx, 0); return TABLE_FULL; } } int test_add_entry(const char *name, image_desc_t *image_desc) { int i; context_table_t ctx; char real_name[ENTRY_NAME_LEN]; caddr_t erase_address; size_t erase_size; int images_part; //Btable not setup return if (!entry_table_setup) { sprintf(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } //Load Btable and copy to ctx if(load_table(&ctx)) { sprintf(error_string,"Error opening btable"); return 0; } /* 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"); store_table(&ctx, 0); return UNKNOWN_IMAGE_NAME; } else if (find_index_by_name(real_name, &ctx.entry)>=0) { sprintf(error_string,"Image name \"%s\" already used",real_name); store_table(&ctx, 0); return IMAGE_NAME_ALREADY_USED; } if (image_desc->storage_address==0) { if (!find_free_area(&image_desc->storage_address,image_desc->size, &ctx.entry)) { sprintf(error_string,"No free area of size %lu",(unsigned long)image_desc->size); store_table(&ctx, 0); 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); store_table(&ctx, 0); return INVALID_FLASH_AREA; } erase_address = image_desc->storage_address-(size_t)available_flash_base(); erase_size = image_desc->size; if ((images_part=mtd_part_open("images"))) { mtd_part_get_area(images_part, &erase_address, &erase_size); erase_address += (size_t)available_flash_base(); if (image_overlaps(erase_address, erase_size, &ctx.entry)) { 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); store_table(&ctx, 0); return UNAVAILABLE_FLASH_AREA; } mtd_part_close(images_part); } i = 0; while(i=0) { sprintf(temp,"-%d",iteration++); strncpy(name,newName,ENTRY_NAME_LEN - IT_SZ); strncat(name,temp,IT_SZ); } //Rename it if ((idx = find_index_by_name(oldName, &ctx.entry))>=0) { strncpy(ctx.entry.entries[idx].name,name,ENTRY_NAME_LEN-1); //Store Btable return store_table(&ctx, 1); } else { sprintf(error_string,"Unknown image name"); //Close Btable store_table(&ctx, 0); return UNKNOWN_IMAGE_NAME; } } int update_entry(const char *name, image_desc_t *image_desc) { int Mindex; context_table_t ctx; //Btable not setup return if (!entry_table_setup) { sprintf(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } //Load Btable and copy to ctx if(load_table(&ctx)) { sprintf(error_string,"Error opening btable"); return 0; } //Update entry if ((Mindex = find_index_by_name(name, &ctx.entry))>=0) { ctx.entry.entries[Mindex].image_desc = *image_desc; //Store Btable return store_table(&ctx, 1); } else { sprintf(error_string,"Unknown image name"); //Close Btable store_table(&ctx, 0); return UNKNOWN_IMAGE_NAME; } } int remove_entry(const char *name) { int Mindex; int done; context_table_t ctx; //Btable not setup return if (!entry_table_setup) { sprintf(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } //Load Btable and copy to ctx if(load_table(&ctx)) { sprintf(error_string,"Error opening btable"); return 0; } //Remove entry if ((Mindex = find_index_by_name(name, &ctx.entry))>=0) { memset(ctx.entry.entries[Mindex].name,0,ENTRY_NAME_LEN); if (ctx.entry.entries[Mindex].selected) { ctx.entry.entries[Mindex].selected = 0; for(Mindex=0,done=0;Mindex=0) { strcpy(name,"active"); return 0; } return 1; } int get_entry(const char *name, image_desc_t *image_desc, int *selected) { int Mindex; context_table_t ctx; //Btable not setup return if (!entry_table_setup) { sprintf(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } //Load Btable and copy to ctx if(load_table(&ctx)) { sprintf(error_string,"Error opening btable"); return 0; } //Close Btable store_table(&ctx, 0); //Get entry if ((Mindex = find_index_by_name(name, &ctx.entry))>=0) { *image_desc = ctx.entry.entries[Mindex].image_desc; *selected = ctx.entry.entries[Mindex].selected; return 0; } else { sprintf(error_string,"Unknown image name"); return UNKNOWN_IMAGE_NAME; } } int select_entry(const char *name) { int Mindex; int oldindex; context_table_t ctx; //Btable not setup return if (!entry_table_setup) { sprintf(error_string,"Table not set-up or corrupted"); return TABLE_NOT_SET_UP; } //Load Btable and copy to ctx if(load_table(&ctx)) { sprintf(error_string,"Error opening btable"); return 0; } //Select entry if ((Mindex = find_index_by_name(name, &ctx.entry))>=0) { if (ctx.entry.entries[Mindex].selected) return 0; else { if ((oldindex=find_selected_index(&ctx.entry))>=0) ctx.entry.entries[oldindex].selected = 0; ctx.entry.entries[Mindex].selected = 1; //Store changes in Btable return store_table(&ctx, 1); } } else { sprintf(error_string,"Unknown image name"); //Close Btable store_table(&ctx, 0); return UNKNOWN_IMAGE_NAME; } } char global_name[ENTRY_NAME_LEN]; const char *get_selected_name(void) { int Mindex; context_table_t ctx; //Btable not setup return if (!entry_table_setup) { sprintf(error_string,"Table not set-up or corrupted"); return NULL; } //Load Btable and copy to ctx if(load_table(&ctx)) { sprintf(error_string,"Error opening btable"); return NULL; } //Close Btable store_table(&ctx, 0); //Get selected name if ((Mindex=find_selected_index(&ctx.entry))>=0) { strncpy(global_name, ctx.entry.entries[Mindex].name, ENTRY_NAME_LEN); return global_name; } else { sprintf(error_string,"Image table error"); return NULL; } } char global_next_name[ENTRY_NAME_LEN]; const char *next_entry(const char *name) { int Mindex; caddr_t next_addr; context_table_t ctx; //Btable not setup return if (!entry_table_setup) { sprintf(error_string,"Table not set-up or corrupted"); return NULL; } //Load Btable and copy to ctx if(load_table(&ctx)) { sprintf(error_string,"Error opening btable"); return NULL; } //Close Btable store_table(&ctx, 0); //Find next entry if (name==NULL) Mindex = find_index_by_addr(0, &ctx.entry); else { if ((Mindex = find_index_by_name(name, &ctx.entry))>=0) { next_addr = (caddr_t)ctx.entry.entries[Mindex].image_desc.storage_address+ ctx.entry.entries[Mindex].image_desc.size; Mindex = find_index_by_addr(next_addr, &ctx.entry); } } if (Mindex>=0) { strncpy(global_next_name, ctx.entry.entries[Mindex].name, ENTRY_NAME_LEN); return global_next_name; } else { sprintf(error_string,"No more images"); return NULL; } } const char *image_table_error(void) { return error_string; }