/* * net/spidupd.c * * Copyright (C) 2009 SPiDCOM Technologies * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Author(s): * Drasko DRASKOVIC, drasko.draskovic@spidcom.com */ #include #include #include #include #include #include #include "spidupd.h" /** Debug management */ #undef ET_DEBUG //#define ET_DEBUG #ifdef ET_DEBUG #define TRACE(...) printf("SPiDUPD: " __VA_ARGS__) #else #define TRACE(...) #endif /** Flash image status */ #define BAD_MAGIC_NUMBER 1 #define INDEX_NOT_VALID 2 #define IMAGE_NOT_VALID 3 #define WRONG_IMAGE_ARCH 4 #define WRONG_IMAGE_TYPE 5 #define UPD_NOT_FINISHED 6 #define IMAGE_NOT_SUCCESS 7 #define IMAGE_OK 8 #define IMAGE_OK_ORIGIN 9 /** Max flash images allowed */ #define MAX_IMG 10 #if (CONFIG_COMMANDS & CFG_CMD_NET) /** Timeouts to stop Netloop */ #define TIMEOUT 1 /* TO for a lost pkt in seconds */ #ifndef CONFIG_NET_RETRY_COUNT #define TIMEOUT_COUNT 0 /* TO before giving up */ #else #define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT * 2) #endif /** Flash writing timeout */ #define FLASH_WRITE_TOUT 2*60 /* TO in seconds */ /** Different states of FSM */ #define STATE_UPD_START 1 #define STATE_UPD_TRANSFER 2 #define STATE_UPD_END 3 #define STATE_UPD_IND 4 #define UPD_START STATE_UPD_START #define UPD_TRANSFER STATE_UPD_TRANSFER #define UPD_END STATE_UPD_END #define UPD_IND STATE_UPD_IND /** Informations about place to update image */ struct update_place { ulong flash_addr; ulong ram_addr; ulong index; ulong nb_img; ulong img_0_addr; ulong img_max_size; ulong correct_img_exist; ulong correct_type; ulong correct_archi; char current_version[SPIDUPD_STRING_VERSION_SIZE]; }; /** Informations about image to update */ struct update_image { int num_rx_blk; int len; }; /** Processus management */ struct update_process { int state; int response; int modem_busy; int timeout; struct update_place *place; struct update_image *image; VsUpdStartCnf_t start_cnf; VsUpdTransfCnf_t transfer_cnf; VsUpdEndCnf_t end_cnf; VsUpdEndInd_t end_ind; unsigned char eth_mac_addr[6]; unsigned char plc_mac_addr[6]; int use_plc_addr; char wanted_version[SPIDUPD_STRING_VERSION_SIZE]; }; /** Global processus structure */ struct update_process ctx; /** Global image structure */ struct update_image g_upd_image; /** Global place structure */ struct update_place g_upd_place; /** Global image desc structure */ spidcom_image_desc_generic_t g_img_desc; /** Reference to flash organization */ extern flash_info_t flash_info[]; /**************************| Utility functions |***************************/ /** * Flush Instruction and Data caches. */ static void flush_caches(void) { unsigned int c7format = 0; __asm__ __volatile__( "mcr p15, 0, %0, c7, c6, 0 @ invalidate caches \n\t" : : "r" (c7format) : "memory"); } /** * Copy the Image descriptor in RAM. * * \param addr source address of the descriptor. * \param desc RAM address of the copy. * \return error code. */ static int load_header(spidcom_image_desc_generic_t *desc, uchar *addr) { if(IS_IN_SPI_RANGE(addr)) { /* Source address is in flash */ if(flash_read_spi(addr, (unsigned char *)&desc->img_common, sizeof(spidcom_image_desc_common_200_300_t), 1, 0) != ERR_OK) { return -1; } } else { /* Source is in RAM */ memmove(&desc->img_common, addr, sizeof(spidcom_image_desc_common_200_300_t)); } return spidcom_image_desc_load (desc); } /** * Check Image descriptor to see if it is correct or not. * * \param desc Image descriptor pointer. * \return Image status. */ static int check_img(spidcom_image_desc_generic_t *desc) { if(strcmp(desc->img_common.magic, SPIDCOM_IMG_DESC_MAGIC)) { return BAD_MAGIC_NUMBER; } if((desc->type == SPIDCOM_IMG_DESC_IMAGE_TYPE_200 && (desc->img_200.arch != SPIDCOM_IMG_DESC_SPC200C || desc->img_200.arch != SPIDCOM_IMG_DESC_SPC200E)) || (desc->type == SPIDCOM_IMG_DESC_IMAGE_TYPE_300 && desc->img_300.arch != SPIDCOM_IMG_DESC_SPC300)) { return WRONG_IMAGE_ARCH; } if(desc->img_common.type != SPIDCOM_IMG_DESC_NORMAL_TYPE) { return WRONG_IMAGE_TYPE; } if(desc->img_common.index == SPIDCOM_IMG_DESC_ORIGIN_INDEX) { return IMAGE_OK_ORIGIN; } if(desc->type == SPIDCOM_IMG_DESC_IMAGE_TYPE_300 && desc->img_300.is_not_update != 0) { return UPD_NOT_FINISHED; } if(desc->img_common.is_valid == 0) { return IMAGE_NOT_VALID; } if(desc->img_common.index == SPIDCOM_IMG_DESC_INVALID_INDEX) { return INDEX_NOT_VALID; } if(!desc->img_common.is_1st_boot && desc->img_common.is_not_success) { return IMAGE_NOT_SUCCESS; } return IMAGE_OK; } /** * Find image max size. * * \param bd board info structure. * \return image max size. */ static __inline__ ulong find_img_max_size(bd_t *bd) { /* First image address is stored under NVRAM */ spidcom_nvram_t *nvram = (spidcom_nvram_t *)(bd->bi_nvram_addr); /* We can use SPI Direct Access because image_max_size is a uint32_t */ return nvram->img_max_size; } /** * Find Flash offset of image 0. * * \param bd board info structure. * \return image 0 offset. */ static __inline__ ulong find_img_1st_offset(bd_t *bd) { /* First image address is stored under NVRAM */ spidcom_nvram_t *nvram = (spidcom_nvram_t *)(bd->bi_nvram_addr); /* We can use SPI Direct Access because nb_images is a uint32_t */ return nvram->img_0_offset; } /** * Find the number of allowed images in flash. * * \param bd board info structure. * \return number of image allowed. */ static __inline__ ulong find_nb_images(bd_t* bd) { /* Number of allowed images is stored under NVRAM */ spidcom_nvram_t *nvram = (spidcom_nvram_t *)(bd->bi_nvram_addr); /* We can use SPI Direct Access because nb_images is a uint32_t */ return nvram->nb_images; } /** * Find plc and eth MAC addresses. * * \param bd board info structure. * \param eth Ethernet MAC address buffer. * \param plc PLC MAC address buffer. */ static __inline__ void find_mac_addresses(bd_t* bd, unsigned char eth[6], unsigned char plc[6]) { ulong lsb, msb; /* Number of allowed images is stored under NVRAM */ spidcom_nvram_t *nvram = (spidcom_nvram_t *)(bd->bi_nvram_addr); /* SPI direct can access to flash only through 32bits */ lsb = *((uint32_t*)nvram->eth1_address); msb = *(((uint32_t*)nvram->eth1_address)+1); msb &= 0x0000FFFF; /* Store this MAC address */ eth[0] = (lsb & 0x000000FF); eth[1] = (lsb & 0x0000FF00)>>8; eth[2] = (lsb & 0x00FF0000)>>16; eth[3] = (lsb & 0xFF000000)>>24; eth[4] = (msb & 0x000000FF); eth[5] = (msb & 0x0000FF00)>>8; /* SPI direct can access to flash only through 32bits */ lsb = *((uint32_t*)nvram->plc_address); msb = *(((uint32_t*)nvram->plc_address)+1); msb &= 0x0000FFFF; /* Store this MAC address */ plc[0] = (lsb & 0x000000FF); plc[1] = (lsb & 0x0000FF00)>>8; plc[2] = (lsb & 0x00FF0000)>>16; plc[3] = (lsb & 0xFF000000)>>24; plc[4] = (msb & 0x000000FF); plc[5] = (msb & 0x0000FF00)>>8; } /** * Choose the better update place. * * \param img_nb number of allowed images in flash. * \param img_max_size max size of an image. * \param place update place information structure. * \return error code. */ static int select_image(int img_nb, ulong img_0_addr, ulong img_max_size, struct update_place *place) { spidcom_image_desc_generic_t *desc = &g_img_desc; int img_state; ulong min_index = 0xFFFFFFFF; ulong max_index = 0; int sel_img_ok = -1; int sel_img_or = -1; int sel_img_ko = -1; int one_img_ok = 0; int i; place->correct_img_exist = 0; /* Clear previous stored version */ place->current_version[0] = '\0'; for(i=0 ; i select it */ if (desc->img_common.index <= min_index) { min_index = desc->img_common.index; sel_img_ok = i; } /* Store max index */ if (desc->img_common.index >= max_index) { max_index = desc->img_common.index; /* Store the version */ /* We use the 300 header because spidupdate protocol does not * support the 200 version (length is too big). Luckily, * version field start at the same position. */ memcpy(place->current_version, desc->img_300.version, SPIDUPD_STRING_VERSION_SIZE); } /* Precise type and archi allowed */ place->correct_img_exist = 1; place->correct_type = desc->img_common.type; if (desc->type == SPIDCOM_IMG_DESC_IMAGE_TYPE_200) place->correct_archi = desc->img_200.arch; else place->correct_archi = desc->img_300.arch; break; case IMAGE_OK_ORIGIN: /* It's a JTAG image */ sel_img_or = i; break; default: /* It's a corrupt image */ if (sel_img_ko == -1) /* change sel_img_ko just first time */ { sel_img_ko = i; /* we are taking first corrupt image for update candidate */ } } } if(one_img_ok) { /* at least one image OK present */ /* update index will be max + 1 */ place->index = max_index + 1; } else { /* No image OK present */ /* update index will be 0 */ place->index = 0; } if(sel_img_ko != -1) { place->flash_addr = (sel_img_ko * img_max_size) + img_0_addr; return 0; } else if(sel_img_ok != -1) { if(max_index == min_index) { /* there is only one image OK that will be overwritten */ /* update index will be 0 */ place->index = 0; } place->flash_addr = (sel_img_ok * img_max_size) + img_0_addr; return 0; } else if(sel_img_or != -1) { place->flash_addr = (sel_img_or * img_max_size) + img_0_addr; return 0; } /* Never use */ return -1; } /** * Store the new update image into the flash. * * \return error code. */ static int store_img(void) { int rc = 0; flash_info_t *flinfo = &(flash_info[0]); /* we expect HW to have only one flash, thus only one flinfo */ int i = 0; ulong last_addr = 0; struct update_image *image = ctx.image; struct update_place *place = ctx.place; /* Erase the flash */ /* In order to erase flash, we will use function flash_sect_erase (ulong addr_first, ulong addr_last), * which demands first parameter to be on sector boundary, and the second actually last addr in some sector. * We have to find last adress of the last sector that holds our image. * Note: if we write 0x360000 bytes long image to address 0x140000 * last addr will be 49ffff (0x140000 + 0x35ffff), not 0x4a0000 (0x140000 + 0x360000) */ if( place->flash_addr + image->len > flinfo->start[0] + flinfo->size ) { printf("Error (Not enough place).\n"); return -1; } /* find the last_addr in the flash */ while( flinfo->start[i] < place->flash_addr + image->len && i < flinfo->sector_count) { i++; } if(i == flinfo->sector_count) { last_addr = flinfo->start[0] + flinfo->size - 1; /* address of the last sector in flash */ } else { last_addr = flinfo->start[i] - 1; } TRACE("Erasing the flash from the addr %#x to the addr %#x...\n", place->flash_addr, last_addr); rc = flash_sect_erase(place->flash_addr, last_addr); if(rc!=ERR_OK) { printf("Error (Flash Erase).\n"); flash_perror(rc); return rc; } else { TRACE("done.\n"); } TRACE("Copy to flash..."); #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) { size_t l = upd_img_len; void *to = (void *)place->flash_addr; void *from = (void *)place->ram_addr; while(l > 0) { size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l; WATCHDOG_RESET(); rc = flash_write(from, to, tail); to += tail; from += tail; l -= tail; } } #else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ { rc = flash_write((char*)place->ram_addr, place->flash_addr, image->len); TRACE("\n"); } #endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ if(rc) { flash_perror(rc); printf("Error (Flash Write).\n"); } return rc; } /* * MD5 functions */ #ifdef ET_DEBUG /** * Print the MD5 Sum result. * * \param digest md5 to print. */ static void md5_print(md5_byte_t digest[16]) { unsigned int i; for(i = 0; i < 16; i++) printf("%02x", digest[i]); } #endif /** * Calculate MD5 of an area. * * \param addr start address. * \param len length for calcul. * \param md5_sum md5 result. */ static void md5_calculation(ulong addr, int len, md5_byte_t md5_sum[16]) { md5_state_t state; #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) ulong bdata = addr; ulong edata = bdata + len; #endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ md5_init(&state); TRACE(" Verifying MD5 Checksum ... "); #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) while (bdata < edata) { ulong chunk = edata - bdata; if (chunk > CHUNKSZ) { chunk = CHUNKSZ; } md5_append(&state, (const md5_byte_t *)bdata, chunk); bdata += chunk; WATCHDOG_RESET(); } #else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */ md5_append(&state, (const md5_byte_t *)addr, len); #endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ md5_finish(&state, md5_sum); #ifdef ET_DEBUG printf("MD5 (Linux image) = "); md5_print(md5_sum); printf("\n"); #endif } /**************************| Protocol functions |***************************/ static void SpidupdTimeout(void); /** * Send a SPiDUpdate confirm packet. */ static void SpidupdSend(int rsp_type) { int len = 0; volatile uchar *pkt; VSMS_MME_t *mme; VsUpdStartCnf_t *vs_update_start_cnf; VsUpdTransfCnf_t *vs_update_transfer_cnf; VsUpdEndCnf_t *vs_update_end_cnf; VsUpdEndInd_t *vs_update_end_ind; /* Set structures pointers */ pkt = NetTxPacket; mme = (VSMS_MME_t *)pkt; vs_update_start_cnf = (VsUpdStartCnf_t *)(mme+1); vs_update_transfer_cnf = (VsUpdTransfCnf_t *)(mme+1); vs_update_end_cnf = (VsUpdEndCnf_t *)(mme+1); vs_update_end_ind = (VsUpdEndInd_t *)(mme+1); /* Set the MME version, FMI and OUI */ mme->mmv = MME_MMV; mme->fmi = 0; VSMS_MME_SET_OUI(mme, OUI_SPIDCOM); /* Set MAC Address */ NetSetEther(pkt, NetClientEther, PROT_HPAV); /* change source MAC address if request was on plc MAC address */ if (ctx.use_plc_addr) memcpy (mme->mme_src, ctx.plc_mac_addr, 6); TRACE("Inside SpidupdSend()\n"); TRACE("SpidupdState = %d\n", rsp_type); switch (rsp_type) { case UPD_START: /* Set mmtype to VS_UPDATE_START_CNF */ mme->mmtype = htommes(VS_UPDATE_START_CNF); /* Append the message */ vs_update_start_cnf->start_update = ctx.start_cnf.start_update; /* This is the end of packet, determine length */ len = ((ulong)vs_update_start_cnf - (ulong)pkt) + sizeof(VsUpdStartCnf_t); break; case UPD_TRANSFER: /* Set mmtype to VS_UPDATE_TRANSFER_CNF */ mme->mmtype = htommes(VS_UPDATE_TRANSFER_CNF); /* Append the message */ vs_update_transfer_cnf->ack = ctx.transfer_cnf.ack; vs_update_transfer_cnf->next_block = htommel(ctx.transfer_cnf.next_block); /* This is the end of packet, determine length */ len = ((ulong)vs_update_transfer_cnf - (ulong)pkt) + sizeof(VsUpdTransfCnf_t); break; case UPD_END: /* Set mmtype to VS_UPDATE_END_CNF */ mme->mmtype = htommes(VS_UPDATE_END_CNF); /* Append the message */ vs_update_end_cnf->result = ctx.end_cnf.result; /* This is the end of packet, determine length */ len = ((ulong)vs_update_end_cnf - (ulong)pkt) + sizeof(VsUpdEndCnf_t); break; case UPD_IND: /* Set mmtype to VS_UPDATE_END_IND */ mme->mmtype = htommes(VS_UPDATE_END_IND); /* Append the message */ vs_update_end_ind->result = ctx.end_ind.result; /* This is the end of packet, determine length */ len = ((ulong)vs_update_end_ind - (ulong)pkt) + sizeof(VsUpdEndInd_t); break; default : /* WOW - How the hell did we get here ? */ printf("Error (Unknown State).\n"); NetState = NETLOOP_FAIL; break; } /* Send packet */ NetSendPacket(pkt, len); } /** * Receive a SPiDUpdate request packet. * * \param pkt received packet pointer. * \param dest destination MAC address. * \param src source MAC address. * \param len packet length. */ static void SpidupdHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len) { VSMS_MME_t *mme; VsUpdStartReq_t *vs_update_start_req; VsUpdTransfReq_t *vs_update_transfer_req; VsUpdEndReq_t *vs_update_end_req; uchar md5_all_image[16]; uchar md5_image[16]; struct update_image *image = ctx.image; struct update_place *place = ctx.place; ushort mmtype; /* Set structures pointers */ mme = (VSMS_MME_t *)pkt; vs_update_start_req = (VsUpdStartReq_t *)(mme+1); vs_update_transfer_req = (VsUpdTransfReq_t *)(mme+1); vs_update_end_req = (VsUpdEndReq_t *)(mme+1); mmtype = (ushort)(mmetohs(mme->mmtype)); /* We accept only SPiDCOM mme packets */ if(!VS_UPDATE_RANGE(mmtype) || !VSMS_MME_IS_CORRECT_OUI(mme, OUI_SPIDCOM)) return; /* We accept only packets for us or broadcast */ if(!memcmp (mme->mme_dest, ctx.plc_mac_addr, 6)) { /* We will give the response with plc mac address */ ctx.use_plc_addr = 1; } else { ctx.use_plc_addr = 0; if(memcmp (mme->mme_dest, ctx.eth_mac_addr, 6) && memcmp (mme->mme_dest, BROADCAST_MAC_ADDR, 6)) return; } /* We received MME packet from PC client, reset the NETLOOP Timeout */ NetSetTimeout(TIMEOUT * CFG_HZ, SpidupdTimeout); /* * Server will now analyze the message and * depending on the message and current state : * 1) shape the cnf message (struct members) * 2) send the response * 3) go to the next state */ switch(mmtype) { case VS_UPDATE_START_REQ: TRACE("Got VS_UPDATE_START_REQ\n"); ctx.response = UPD_START; #ifdef ET_DEBUG { int i = 0; puts("version = "); for (i=0; iversion)[i]); } printf("\n"); } printf("arch = %#x\n", vs_update_start_req->arch); printf("upd_type = %#x\n", vs_update_start_req->upd_type); #endif /* Check that no previous update is running */ if((ctx.state == STATE_UPD_START) && !ctx.modem_busy) { /* default send cnf */ ctx.modem_busy = 1; ctx.start_cnf.start_update = SPIDUPD_OK; ctx.state = STATE_UPD_TRANSFER; /* shape the response to client */ if(vs_update_start_req->proto_version > SPIDUPD_PROTOCOL_VERSION) { /* Request with a newer SPiDUpdate protocol */ printf("Error (New SPidUpdate protocol %d, can't understand).\n", vs_update_start_req->proto_version); ctx.modem_busy = 0; ctx.start_cnf.start_update = SPIDUPD_BAD_PROTOCOL; ctx.state = STATE_UPD_START; /* Abort the update */ NetState = NETLOOP_FAIL; break; } if(SPIDCOM_IMG_DESC_SPC300 != vs_update_start_req->arch && SPIDCOM_IMG_DESC_SPC200C != vs_update_start_req->arch) { /* Request bad architecture */ printf("Error (New image bad Architecture).\n"); ctx.modem_busy = 0; ctx.start_cnf.start_update = SPIDUPD_BAD_ARCH; ctx.state = STATE_UPD_START; /* Abort the update */ NetState = NETLOOP_FAIL; break; } if(SPIDCOM_IMG_DESC_NORMAL_TYPE != vs_update_start_req->upd_type) { /* Request doesn't concern a sImage */ printf("Error (New image bad type).\n" ); ctx.modem_busy = 0; ctx.start_cnf.start_update = SPIDUPD_BAD_UPD_TYPE; ctx.state = STATE_UPD_START; /* Abort the update */ NetState = NETLOOP_FAIL; break; } if(place->correct_img_exist && ((vs_update_start_req->version[0] == '\0') || (memcmp(place->current_version, vs_update_start_req->version, SPIDUPD_STRING_VERSION_SIZE) == 0))) { printf("Error (Bad Version).\n" ); ctx.modem_busy = 0; ctx.start_cnf.start_update = SPIDUPD_BAD_VERSION; ctx.state = STATE_UPD_START; /* Abort the update */ NetState = NETLOOP_FAIL; break; } /* Save wanted version */ memcpy(ctx.wanted_version, vs_update_start_req->version, SPIDUPD_STRING_VERSION_SIZE); } else { printf("Error (Already in use).\n"); ctx.start_cnf.start_update = SPIDUPD_MODEM_BUSY; } break; case VS_UPDATE_TRANSFER_REQ: TRACE("Got VS_UPDATE_TRANSFER_REQ\n"); ctx.response = UPD_TRANSFER; TRACE("received_block = %#x\n", image->num_rx_blk); TRACE("block_id = %#x\n", mmetohl(vs_update_transfer_req->block_id) ); TRACE("length = %d\n", mmetohl(vs_update_transfer_req->length) ); if(ctx.state == STATE_UPD_TRANSFER) { /* Block IDs are starting from 1. * We are expecting to receive next block * of the one that we received last time */ if( mmetohl(vs_update_transfer_req->block_id) != image->num_rx_blk ) { TRACE("FAILURE : Received block ID does not match expected.\n" ); ctx.transfer_cnf.ack = SPIDUPD_FAILURE; ctx.transfer_cnf.next_block = image->num_rx_blk; } else /* OK, we received block we expected */ { /* give a small visual indication */ if((image->num_rx_blk % 50) == 0) printf("."); /* Put block in RAM */ memcpy((void*)(place->ram_addr + image->len), vs_update_transfer_req->data, vs_update_transfer_req->length); /* Increase transfered length */ image->len += mmetohl(vs_update_transfer_req->length); /* we successfully received block, increment received counter */ image->num_rx_blk++; /* shape the response */ ctx.transfer_cnf.ack = SPIDUPD_SUCCESS; ctx.transfer_cnf.next_block = image->num_rx_blk; } } else { TRACE("Wrong message...\n"); } break; case VS_UPDATE_END_REQ: TRACE("Got VS_UPDATE_END_REQ\n"); TRACE("|\n"); ctx.response = UPD_END; if (ctx.state == STATE_UPD_TRANSFER) { ctx.state = STATE_UPD_END; /* Transfer is finished so calculate MD5 */ md5_calculation(place->ram_addr, image->len, (md5_byte_t *)md5_all_image); md5_calculation(place->ram_addr + sizeof(spidcom_image_desc_common_200_300_t), image->len - sizeof(spidcom_image_desc_common_200_300_t), (md5_byte_t *)md5_image); if((memcmp(md5_all_image, vs_update_end_req->md5_sum, 16) != 0) || (memcmp(md5_image, ((spidcom_image_desc_common_200_300_t *) place->ram_addr)->md5_sum, 16) != 0)) { /* Wrong MD5 */ printf("Error (MD5 Error).\n"); ctx.modem_busy = 0; ctx.end_cnf.result = SPIDUPD_MD5_ERROR; ctx.state = STATE_UPD_START; /* Abort the update */ NetState = NETLOOP_FAIL; } /* Check image version with wanted version */ else if(memcmp(ctx.wanted_version, ((spidcom_image_desc_300_t *)place->ram_addr)->version, SPIDUPD_STRING_VERSION_SIZE) != 0) { /* Wrong given version */ printf("Error (Wrong given version).\n"); ctx.modem_busy = 0; ctx.end_cnf.result = SPIDUPD_VERSION_ERROR; ctx.state = STATE_UPD_START; /* Abort the update */ NetState = NETLOOP_FAIL; } } else { TRACE("Wrong message...\n"); } break; } /* Acknowledge the block just received, which will prompt * the client for the next one. */ SpidupdSend(ctx.response); /* Update communication is finish correctly lets copy image in flash */ if(ctx.state == STATE_UPD_END) { /* Correct MD5 */ TRACE("MD5 sum OK, will burn image...\n"); NetSetTimeout((ulong)(FLASH_WRITE_TOUT * CFG_HZ), SpidupdTimeout); /* We will start to write new image from RAM to FLASH. * Set the index to correct value. */ ((spidcom_image_desc_common_200_300_t *)place->ram_addr)->index = place->index; if(store_img() != ERR_OK) { /* Error writing flash */ TRACE("Error.\nUpdate failure : image cannot be written to flash.\n"); /* Image on flash is corrupted! */ ((spidcom_image_desc_common_200_300_t *)place->ram_addr)->is_valid = 0; flash_write( (char *)place->ram_addr, place->flash_addr, sizeof(spidcom_image_desc_common_200_300_t) ); /* * We have no valid image anymore! * Update failed. */ ctx.end_ind.result = SPIDUPD_FLASH_WRITE_ERROR; NetState = NETLOOP_FAIL; } else { /* Flash write OK */ TRACE("Update image successfully written to flash.\n"); ctx.end_ind.result = SPIDUPD_SUCCESS; NetBootFileXferSize = image->len; NetState = NETLOOP_SUCCESS; } /* We finished update : * re-write header, but with the normal state indication - * put is_update flag to 0, because update is finished * (it was put to 1 by default when image is generated) */ /* We (dirtily) update the flag event if we have a 200 image. We did * not use the common descriptor here. Luckily for us, the flag is * stored in 300 where there is nothing in 200. */ ((spidcom_image_desc_300_t *)place->ram_addr)->is_not_update = 0; if ( flash_write( (char*)place->ram_addr, place->flash_addr, sizeof(spidcom_image_desc_common_200_300_t) ) != ERR_OK ) { printf("Error writting img desc header to flash -- image will not be valid.\n"); ctx.end_ind.result = SPIDUPD_FLASH_WRITE_ERROR; } ctx.modem_busy = 0; ctx.state = STATE_UPD_START; SpidupdSend(UPD_IND); } } /** * Calculate timeout procedure. */ static void SpidupdTimeout(void) { if(++ctx.timeout > TIMEOUT_COUNT) { printf("Timeout.\n"); /* TIMEOUT occurred. */ /* Send to client an error message */ if(ctx.state != STATE_UPD_START) { ctx.end_ind.result = SPIDUPD_TOUT; SpidupdSend(UPD_IND); } /* Stop eth driver */ eth_halt(); /* Go out of NETLOOP and notify the caller about failure */ NetState = NETLOOP_FAIL; } else { NetSetTimeout(TIMEOUT * CFG_HZ, SpidupdTimeout); SpidupdSend(ctx.response); } } /** * Start SPiPUpdate procedure. */ void SpidupdStart(void) { DECLARE_GLOBAL_DATA_PTR; ulong nb_img; ulong img_0_addr; ulong img_max_size; /* Flush caches just to be sure */ flush_caches(); puts("SPiDUpdate..."); /* Prepare Networking Handler and timeout */ NetSetTimeout(TIMEOUT * CFG_HZ, SpidupdTimeout); NetSetHandler(SpidupdHandler); /* Store eth and plc mac addresses */ find_mac_addresses (gd->bd, ctx.eth_mac_addr, ctx.plc_mac_addr); /* Find number of allowed places on flash */ nb_img = find_nb_images(gd->bd); if(nb_img > MAX_IMG) { printf("Max allowed images is %d\n", MAX_IMG); nb_img = MAX_IMG; } /* Find the first image offset on flash */ img_0_addr = PHYS_FLASH_SPI_1 + find_img_1st_offset(gd->bd); /* Find max image size */ img_max_size = find_img_max_size(gd->bd); /* Find better place to update a new image */ select_image(nb_img, img_0_addr, img_max_size, &g_upd_place); /* Reset globals */ g_upd_place.nb_img = nb_img; g_upd_place.img_0_addr = img_0_addr; g_upd_place.img_max_size = img_max_size; /* We will use free space in SDRAM to temporary store incoming image packets, * before copying it to flash when all image packets are collected. * Begining address will be right after u-boot image, _bss_end + 1, but aligned to 4 byte boundary */ g_upd_place.ram_addr = ( (_bss_end + 1) + 3 ) & ~3; g_upd_image.len = 0; g_upd_image.num_rx_blk = 0; ctx.place = &g_upd_place; ctx.image = &g_upd_image; ctx.modem_busy = 0; ctx.timeout = 0; ctx.state = STATE_UPD_START; #ifdef ET_DEBUG printf("place.flash_addr=%x\n",g_upd_place.flash_addr); printf("place.ram_addr=%x\n",g_upd_place.ram_addr); printf("place.index=%d\n",g_upd_place.index); printf("place.nb_img=%d\n",g_upd_place.nb_img); printf("place.c_img_exist=%d\n",g_upd_place.correct_img_exist); printf("place.c_type=%x\n",g_upd_place.correct_type); printf("place.c_archi=%x\n",g_upd_place.correct_archi); printf("Version: %s\n", g_upd_place.current_version); #endif } #endif /* CFG_CMD_NET */